Skip to content

If and how to represent Annotations in M3 #13

@enikao

Description

@enikao

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

  • (MPS) Editor of concept: May survive deletion of concept, to be reused for other concept
  • Documentation: Reuse fancy doc language for all other languages
  • Scoper
  • Type system: Makes no sense without the annotated node
  • (MPS) Generator / Antiquotations: Extend original language without original language knowing about annotations
  • View model of editor: Store positions for diagram projection of node
    But: Might want to store somewhere else for version control reasons
  • Target-language specific information, e.g. "For Java, generate to java.math.BigInteger; for C#, generate to System.Numerics.BigInteger

Representation in M3

Alternative A: Just represent them as regular Concepts

Pro:

  • Structurally similar
  • Less concepts on M3

Con:

  • Annotations are always tied to the annotated node; Concepts can be used on their own (or misused if they represent annotations)
  • It can be annoying to filter out annotations from generic processing
  • How to describe annotatable Concepts and multiple flag?

Alternative B: Separate them out into adjacent model

example: EMF ecore vs. genmodel

Pro:

  • Separation of concerns

Con:

  • Never worked well in practice, models eventually get out of sync

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
Loading

Pro:

  • Clearly separates them from regular concepts
  • Structurally enforces node.annotations can only be of Annotation type
  • Compatible with EMF annotations

Con:

  • Would need to replicate a lot of Classifier structure, e.g. supertype, features
  • Annotations in most systems (Java, C#, MPS) support containment-like structure

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
Loading

Pro:

  • Leverages similarity and capabilities to Classifier

Con:

  • Introduces non-structural constraint on node.annotations return type?? Don't understand that
  • Duplicates structures of Concept

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
Loading

Pro:

  • Leverages similarity and capabilities to Concept

Con:

  • Annotation can never be a partition, so inherited partition flag is useless
  • What is an abstract annotation?
  • Non-structural constraint: Annotation and Concept can only extend their own kind OR we allow that mixture.
    The mixture is weird if used but not a structural problem.

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
Loading

Pro:

  • No change to M3

Con:

  • Annotations (i.e. Concepts implementing IAnnotation) can appear everywhere, even in regular structure

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

  • Separation of concerns
  • No change to M3

Con:

  • More builtin languages to deal with
  • Update issues
    • How to delete annotations alongside with annotated node?
      --> Would need an active repository, or a processor
    • Where to add annotation for a specific annotated node, e.g. what's the annotation's parent?

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions