Metamodel

The Ceylon metamodel base package.

The Ceylon metamodel allows you to:

- dynamically inspect modules, packages, functions, values and types,
- invoke functions, constructors and class initialisers,
- read and write values, and
- inspect the annotations on program elements.

### A little bit of terminology

There are a few concepts and terms in the Ceylon metamodel API that you should be familiar with:

- A declaration is the definition of a Ceylon construct, such as a module, package, value, function or class. Declarations are singletons: there is only a single instance of a given class declaration, for example. You can inspect declarations to get information about how they were defined by their author. You cannot directly invoke function or class declarations, but you can apply them to get a model that you can invoke.
- A model is a Ceylon definition that represents a declaration where all the type variables have been bound to closed type values. You can query models for their member models and you can directly invoke models.
- A closed type is a type which does not contain any unbound type variables.
- An open type is a type which may contain unbound type variables.

For example, given the following Ceylon program:

    shared abstract class MyList<T>() satisfies List<T>{}

The declaration of `MyList` represents the class declaration and contains the information that it is `abstract` and that it satisfies the `List<T>` open type. That type is open because it contains an unbound type variable `T`, which is not bound when we inspect the `MyList` class declaration.

Given an particular instance of `MyList`, we can query its (closed) type with the `type()` function, and we obtain a closed type representing (for example) `MyList<Integer>`. Object instances necessarily have a closed type at runtime, since in order to instantiate an object, all type arguments must be provided and known during instantiation, so the type of an object instance at runtime is necessarily a closed type: they cannot contain unbound type variables.

Closed types that represent class or interfaces are also models. For example, the closed type of our `MyList<Integer>` instance is both a closed type and a class model: you can query its satisfied types and find that it satisfies `List<Integer>` closed type and model (as opposed to the class declaration of `MyList` which satisfies the `List<T>` open type). You can also invoke that model to obtain a new instance of `MyList<Integer>`.

### Model and declaration literals

Ceylon supports getting declaration values using either the declaration API or using declaration literals:

- ``module ceylon.file`` returns the Module declaration which corresponds to the `ceylon.file` module you imported in your module descriptor, or to the current module if it is `ceylon.file`. You can also obtain a reference to the current module with ``module``.
- ``package ceylon.language.meta`` returns the Package declaration from your current module or its imports. You can also obtain a reference to the current package with ``package``.
- ``interface List`` returns the InterfaceDeclaration for the List type. You can also obtain a reference to the current interface with ``interface``.
- ``class Integer`` returns the ClassDeclaration for the Integer type. You can also obtain a reference to the current class with ``class``.
- ``new Array.ofSize`` returns the CallableConstructorDeclaration for the `Array.ofSize()` constructor. Similarly ``new Color.black`` for value constructors.
- ``function type`` returns the FunctionDeclaration for the `type()` function. Similarly ``function List.shorterThan`` for methods.
- ``value modules`` returns the ValueDeclaration for the `modules` value. Similarly ``function List.size`` for attributes.
- ``alias AliasName`` returns the AliasDeclaration for the `AliasName` type alias.
- ``given T`` returns the TypeParameter for the `T` type parameter.

Note that declaration literals cannot have type arguments specified on types or methods, as declarations are not types.

You can also get access to closed types and model using either the model API or using literals:

- ``List<Integer>`` returns the Interface model and closed type for the List type applied with the Integer type argument.
- ``Integer`` returns the Class model and closed type for the Integer type.
- ``Array.ofSize`` returns the CallableConstructor model for the Array.ofSize constructor. Similarly ``Color.black`` for value constructor models.
- ``type<Integer>`` returns the Function model for the `type()` function applied with the Integer type argument. Similarly ``List<Integer>.shorterThan`` for method models.
- ``modules`` returns the Value model for the `modules` value. Similarly ``List<Integer>.size`` for attribute models.
- ``A & B`` returns a IntersectionType for the `A & B` intersection type.
- ``A | B`` returns a UnionType for the `A | B` union type.
- ``T`` returns a Type representing the runtime type argument value for the `T` type parameter.

Notice that all model and close type literals must be applied with all required type arguments.

### Accessing the metamodel using the API

Aside from declaration and model literals there are several ways you can start using the metamodel API:

- The `modules` object contains a list of all currently loaded Module declarations. Note that these contain even modules you did not import as it contains all transitive dependencies, and may contain multiple different versions of the same module.
- The `classDeclaration()` function will return the `ClassDeclaration` of the given instance.
- The `type()` function will return the closed type of the given instance, which can only be a ClassModel since only classes can be instantiated.
- The `typeLiteral()` function is the functional equivalent to closed type literals: it turns a type argument value into a metamodel closed type.
- The declaration package contains all the declaration and open types.
- The model package contains all the model and closed types.

### Inspecting annotations

Constrained annotations can be inspected using the `annotations()` function, like this:

    // Does the process declaration have the Shared annotation?
    value isShared = annotations(`SharedAnnotation`, `value process`) exists;

or the related `optionalAnnotation()` and `sequencedAnnotations()` functions.

Note that annotations are queried for via their `Annotation` type, not by the annotation constructor which was used to annotate the program element.

By: Gavin King, Stephane Epardaud, Tom Bentley

Subpackages
ceylon.language.meta.declaration | Metamodel The Ceylon metamodel open type and declaration package.
ceylon.language.meta.model | Metamodel The Ceylon metamodel closed type and model package.

Values
`modules` | Source Code `shared modules modules` Represents the list of Ceylon modules currently loaded at runtime. Note that this contains all loaded modules, including those that are not imported by your module. Since Ceylon supports module isolation at runtime, it is possible that there are more than one version of a given module loaded at the same time. ### Usage example Here's how you would iterate all the loaded modules and print their name and version:
    import ceylon.language.meta { modules }

    for(mod in modules.list){
        print("Module: ``mod.name``/``mod.version``");
    }

Functions
`annotations` | Source Code `shared Values annotations<Value, Values, in ProgramElement>(Class<ConstrainedAnnotation<Value,Values,ProgramElement,Anything>,Nothing> annotationType, ProgramElement programElement) given Value satisfies ConstrainedAnnotation<Value,Values,ProgramElement,Anything> given ProgramElement satisfies Annotated` The annotations of the given type applied to the given program element. For example:
    // Does the process declaration have any annotations
    // of type SharedAnnotation?
    value isShared = annotations(`SharedAnnotation`, `value process`) exists;
The annotations may be returned in any order.
`classDeclaration` | Source Code `shared ClassDeclaration classDeclaration(Anything instance)` Returns the class declaration for a given instance. Since only classes can be instantiated, this will always be a `ClassDeclaration` model. Using `declaration` can be more efficient than using `type()` and obtaining the ClassDeclaration from the returned ClassModel.
`optionalAnnotation` | Source Code `shared Value? optionalAnnotation<Value, in ProgramElement>(Class<OptionalAnnotation<Value,ProgramElement,Anything>,Nothing> annotationType, ProgramElement programElement) given Value satisfies OptionalAnnotation<Value,ProgramElement,Anything> given ProgramElement satisfies Annotated` The value of given optional annotation type on the given program element, or null if the program element was not annotated with that annotation type. For example:
    // Does the process declaration have the Shared annotation?
    value isShared = optionalAnnotation(`SharedAnnotation`, `value process`) exists;
`sequencedAnnotations` | Source Code `shared Value[] sequencedAnnotations<Value, in ProgramElement>(Class<SequencedAnnotation<Value,ProgramElement,Anything>,Nothing> annotationType, ProgramElement programElement) given Value satisfies SequencedAnnotation<Value,ProgramElement,Anything> given ProgramElement satisfies Annotated` The values of given sequenced annotation type on the given program element, or empty if the program element was not annotated with that annotation type. For example:
    // Does the sum declaration have any ThrownException annotations?
    value throwsSomething = sequencedAnnotation(`ThrownException`, `function sum`) nonempty;
The annotations may be returned in any order.
`type` | Source Code `shared ClassModel<Type,Nothing> type<out Type>(Type instance) given Type satisfies Anything` Returns the closed type and model of a given instance. Since only classes can be instantiated, this will always be a `ClassModel` model. See also `classDeclaration()`
`typeLiteral` | Source Code `shared ClosedType<Type> typeLiteral<out Type>() given Type satisfies Anything` Functional equivalent to type literals. Allows you to get a closed type instance for a given type argument. For example:
    assert(is Interface<List<Integer>> listOfIntegers = typeLiteral<List<Integer>>());

Classes
`modules` | Source Code `shared modules` Represents the list of Ceylon modules currently loaded at runtime. Note that this contains all loaded modules, including those that are not imported by your module. Since Ceylon supports module isolation at runtime, it is possible that there are more than one version of a given module loaded at the same time. ### Usage example Here's how you would iterate all the loaded modules and print their name and version:
    import ceylon.language.meta { modules }

    for(mod in modules.list){
        print("Module: ``mod.name``/``mod.version``");
    }