LionWeb-io / specification

Specifications of the LionWeb initiative
http://lionweb.io/specification/
6 stars 0 forks source link

If and how to represent Annotations in M3 #13

Closed enikao closed 11 months ago

enikao commented 1 year ago

Do we want Annotations, and how to represent them in M3?

See also: #11, #12

What is an annotation?

Limited[1] additional, orthogonal information attached to potentially any node, sharing the node’s lifecycle. The annotated node (or its concept) does not need to know about the annotation.

[1] "limited" because the more complex the annotation is, the more likely it should not be part of the annotated node's lifecycle -- We might want to reuse the complex annotation somewhere else. Example: In MPS, the editor of a concept can be seen as an annotation of that concept. But even if we deleted the concept, we might want to reuse the editor for another (similar) concept.

Use cases

Representation in M3

Alternative A: Just represent them as regular Concepts

Pro:

Con:

Alternative B: Separate them out into adjacent model

example: EMF ecore vs. genmodel

Pro:

Con:

Alternative C: First-class citizen in M3, separate from Classifier; don't support containment

classDiagram

class LanguageEntity

class Feature

class Property
Feature <|-- Property

class Classifier
LanguageEntity <|-- Classifier
Classifier "1" *-- "*" Feature: features

class Concept {
  Boolean abstract
  Boolean partition
}
Classifier <|-- Concept
Concept "1" --> "*" Concept: extends
Concept "*" --> "*" ConceptInterface: implements

class ConceptInterface
Classifier <|-- ConceptInterface
%% ConceptInterface"*" o-- "*" ConceptInterface: extends

class Annotation {
  Boolean multiple
}
Annotation "*" --> "1" Classifier: annotates
LanguageEntity <|-- Annotation
Annotation "1" *-- "*" Property: properties
Annotation "1" --> "*" Annotation: extends
Annotation "*" --> "*" ConceptInterface: implements

Pro:

Con:

Alternative D: First-class citizen in M3, subtype of Classifier

classDiagram

class LanguageEntity

class Feature

class Classifier
LanguageEntity <|-- Classifier
Classifier "1" *-- "*" Feature: features

class Concept {
  Boolean abstract
  Boolean partition
}
Classifier <|-- Concept
Concept "1" --> "*" Concept: extends
Concept "*" --> "*" ConceptInterface: implements

class ConceptInterface
Classifier <|-- ConceptInterface
%% ConceptInterface"*" o-- "*" ConceptInterface: extends

class Annotation {
  Boolean multiple
}
Annotation "*" --> "1" Classifier: annotates
Classifier <|-- Annotation
Annotation "1" --> "*" Annotation: extends
Annotation "*" --> "*" ConceptInterface: implements

Pro:

Con:

Alternative E: Specialization of Concept

classDiagram

class LanguageEntity

class Feature

class Classifier
LanguageEntity <|-- Classifier
Classifier "1" *-- "*" Feature: features

class Concept {
  Boolean abstract
  Boolean partition
}
Classifier <|-- Concept
Concept "1" --> "*" Concept: extends
Concept "*" --> "*" ConceptInterface: implements

class ConceptInterface
Classifier <|-- ConceptInterface
%% ConceptInterface"*" o-- "*" ConceptInterface: extends

class Annotation {
  Boolean multiple
}
Annotation "*" --> "1" Classifier: annotates
Concept <|-- Annotation

Pro:

Con:

Alternative F: Marker interface in builtin library

Does not work, as the concept that implements IAnnotation would need to instantiate it, i.e. fill IAnnotation's features with concrete values.

classDiagram

class IAnnotation ["builtins::IAnnotation"] {
  Boolean multiple
}
<<ConceptInterface>> IAnnotation
IAnnotation "*" --> "1" Classifier: annotates

class LanguageEntity

class Feature

class Classifier
LanguageEntity <|-- Classifier
Classifier "1" *-- "*" Feature: features

class Concept {
  Boolean abstract
  Boolean partition
}
Classifier <|-- Concept
Concept "1" --> "*" Concept: extends
Concept "*" --> "*" ConceptInterface: implements

class ConceptInterface
Classifier <|-- ConceptInterface
%% ConceptInterface"*" o-- "*" ConceptInterface: extends

Pro:

Con:

Alternative G: Separate M3 language, similar to derived model

Annotations are “just” a derived model (as e.g. type system). Each client can request them the same way as any other derived model.

Difference: Annotations are stored, type system is calculated. This would break our assumption: “Derived model can be reconstructed from original model”.

Pro

Con:

This could be implemented as a “adjacent annotation” processor implementing annotations as separate models

ftomassetti commented 1 year ago

I understood that the non-structural constrain to be introduced would be Link.type, not node.annotations

Is it right that we need to introduce these constraints?

enikao commented 1 year ago

Annotation.target is Structurally an AbstractConcept but it cannot be Annotation

I think yes

Link.type is Structurally an AbstractConcept but it cannot be Annotation

I'd say Containment.type can never be Annotation. What about Reference.type? Can one Annotation refer to another one? Can we refer from a Concept that's a child of an Annotation to another Annotation?

ftomassetti commented 1 year ago

Good point. I guess we could allow references to Annotation, but I have not a strong opinion on this and I would be curious to hear what others think

dslmeinte commented 1 year ago

I think annotations are quite different beasts from the other subtypes of FeaturesContainer (see issue #20 as well). We also would need to think of the semantics: how can you instantiate them? So yes: we should make constraints that exclude annotations as Link.type.

markusvoelter commented 1 year ago

.... and otherwise make them concepts, right?

ftomassetti commented 1 year ago

Have we concluded that Annotation cannot be used as the target of references? Should we mark this issue as closed?

joswarmer commented 1 year ago

I think there is little reason for annotations to be defined at the M3 level. Annotations can simply be defined in a separate language at the M2 level. Annotations are then just concepts, like any other concepts and they can use inheritance, interfaces etc just like in any other language. Use cases range from language specific to generic annotations and from simple to complex annotations:

The reference in this solution is always from the annotation to the annotated concept, which I think is conceptually correct.

Whether we expect annotations to show in an editor together with the annotated concept or separately is purely an editor/tool issue. Both options can be supported, even within the same editor/tool. In the use cases above both options are being used.

I see no benefit from creating a separate M3 notion of Annotation because:

The solution of having separate annotation languages at the M2 level is a combination of alternative A (represent annotations as concepts) and alternative B (separate annotations out in a separate model).

The "con" at alternative B that it did not work out in practice is disputable. At Mendix we used a separate annotation model for defining version annotations attached to concepts, which worked very well. And in Freon we also use separate annotation model for editor definitions etc., which also works fine.

Gives this I am strongly in favor of not adding Annotation to the M3 level.

enikao commented 1 year ago

The reference in this solution is always from the annotation to the annotated concept, which I think is conceptually correct.

If I understand correctly, this is on M2 level: The AnnotationConcept (e.g. DocumentationAnnotation) refers to annotatable concepts, e.g. JavaClass or TypescriptMethod.

On M1 level, we need the opposite direction: For each JavaClass instance, I need to find all attached annotation instances. So we need to somehow represent them in serialization (details tbd). (This does not contradict above's finding, just clarification).

The "con" at alternative B that it did not work out in practice is disputable.

The quoted con argument also relates to M1: In GMF, it was very hard to keep the "annotations" to ecore instances (kept in genmodel, gmfgraph, gmftool, ... models) in sync.

enikao commented 1 year ago

Decision via Slack vote on 2023-08-04: Alternative D: First-class citizen in M3, subtype of Classifier