Chapter 7. Annotations

Annotations allow information to be attached to a declaration or assertion, and recovered at runtime via the use of the Ceylon metamodel. Annotations are used to specify:

7.1. Annotations of program elements

Annotations occur at the very beginning of a declaration or assertion, in an annotation list.

"The user login action"
by ("Gavin King",
    "Andrew Haley")
throws (`class DatabaseException`,
        "if database access fails")
see (`function LogoutAction.logout`)
scope (session) 
action { description="Log In"; url="/login"; }
shared deprecated

7.1.1. Annotation lists

An annotation is an initial lowercase identifier, optionally followed by an argument list.

Annotation: MemberName Arguments?

The annotation name is a reference to an annotation constructor, resolved according to §5.1.7 Unqualified reference resolution.

A list of annotations does not require punctuation between the individual annotations in the list. An annotation list may begin with a string literal, in which case it is interpreted as the argument of a doc annotation.

Annotations: StringLiteral? Annotation*

Every annotation is an invocation expression, as defined by §6.6 Invocation expressions, of an annotation constructor. The annotation name is interpreted as a base expression, as defined in §6.5.1 Base expressions.

7.1.2. Annotation arguments

For an annotation with no arguments, the argument list may be omitted, in which case the annotation is interpreted as having an empty positional argument list. Otherwise, the annotation argument list may be specified using one of two forms:

As a special case, the name of the doc annotation and the parenthesis around its argument may be ommitted if it is the first annotation in an annotation list.

"the name" String name;

Operator expressions, member expressions, self references, anonymous functions, comprehensions, and string templates are not permitted in an annotation argument. Every base expression in an annotation argument must be a value reference to an anonymous class instance of an enumerated type, or must occur in a direct instantiation expression, as defined in §6.6.1 Direct invocations, for an annotation type.

A named argument to an annotation may not be an inline function, value, or anonymous class.

7.2. Annotation definition

Annotations are typesafe.

  • An annotation constructor defines the schema of an annotation as it appears at a program element.

  • An annotation type defines constraints upon which program elements can bear the annotation, and an API for accessing the information carried by an annotation.

7.2.1. Annotation constructors

An annotation constructor is a toplevel function that defines an annotation schema. An annotation constructor must be annotated annotation. An annotation constructor may not declare type parameters.

Each parameter of an annotation constructor must have one of the following types:

  • Integer, Float, Character, or String,

  • an enumerated type whose cases are all anonymous classes, such as Boolean,

  • a subtype of Declaration in ceylon.language.meta.declaration,

  • an annotation type,

  • T? where T is a legal annotation constructor parameter type,

  • {T*}, {T+}, [T*], or [T+] where T is a legal annotation constructor parameter type, or

  • any tuple type whose element types are legal annotation constructor parameter types.

A parameter of an annotation constructor may be variadic.

An annotation constructor must simply instantiate and return an instance of an annotation type. The body of an annotation constructor may not contain multiple statements. Operator expressions, member expressions, self references, anonymous functions, comprehensions, and string templates are not permitted in the definition of an annotation constructor. Every base expression in the body of an annotation constructor must be a reference to a parameter of the annotation constructor or to an anonymous class instance of an enumerated type, or must occur in a direct instantiation expression, as defined in §6.6.1 Direct invocations, for an annotation type.

A named argument appearing in the definition of an annotation constructor may not be an inline function, value, or anonymous class.

shared annotation Scope scope(ScopeType s) => Scope(s);
shared annotation Todo todo(String text) => Todo(text);

An annotation constructor parameter may have a default argument, which must be a legal annotation argument.

The return type of an annotation constructor must be a constrained annotation type, as defined below in §7.2.3 Constrained annotation types.

A user-defined annotation constructor may not return the same annotation type as one of the modifiers listed below in §7.4.1 Declaration modifiers.

Note: in future releases of the language we will let an annotation constructor return a sequence or tuple of annotation type instances.

7.2.2. Annotation types

Annotation constructors produce instances of annotation types. An annotation type is a class annotated annotation. An annotation type may not be a generic type with type parameters. An annotation type must have an empty initializer section.

Note: currently every annotation type must be a final class which directly extends Basic in ceylon.language.

Each initializer parameter of an annotation type must have one of the following types:

  • Integer, Float, Character, or String,

  • an enumerated type whose cases are all anonymous classes, such as Boolean,

  • a subtype of Declaration in ceylon.language.meta.declaration,

  • an annotation type,

  • T? where T is a legal annotation parameter type,

  • {T*}, {T+}, [T*], or [T+] where T is a legal annotation parameter type, or

  • any tuple type whose element types are legal annotation parameter types.

An initializer parameter of an annotation type may be variadic.

An initializer parameter of an annotation type may have a default argument, which must be a legal annotation argument.

7.2.3. Constrained annotation types

A constrained annotation type is an annotation type that is a subtype of OptionalAnnotation or SequencedAnnotation defined in the package ceylon.language.

  • If A is a subtype of OptionalAnnotation, at most one annotation of annotation type A may occur at a given program element.

  • If A is a subtype of SequencedAnnotation, multiple annotations of annotation type A may occur at a given program element.

  • If A is a subtype of ConstrainedAnnotation<A,B,P,T>, then an annotation of annotation type A may not occur at a program element whose reference expression type, as defined in §6.10.3 Type of a reference expression, is not assignable to P.

  • If A is a subtype of ConstrainedAnnotation<A,B,P,T> where T is not exactly Anything, then an annotation of annotation type A may not occur at a program element whose metamodel type, as defined in §6.9.1 Type of a metamodel expression, is not assignable to T.

shared final annotation class Scope(shared ScopeType scope)
        satisfies OptionalAnnotation<Scope,ClassOrInterfaceDeclaration> {
    string => (scope==request then "request")
         else (scope==session then "session")
         else (scope==application then "application")
         else nothing;
}
shared final annotation class Todo(String text)
        satisfies SequencedAnnotation<Todo> {
    string => text;
}

Note: it is perfectly acceptable for multiple annotation constructors to return the same annotation type.

7.3. Annotation values

An annotation value is the value returned when an annotation constructor is invoked. We may obtain the annotation values of all annotations of a given annotation type that occur at a given program element by passing the annotation type metamodel, as defined in §6.9 Metamodel expressions, and program element reference, as defined in §6.10 Reference expressions, to the method annotations() defined in the package ceylon.language.meta.model.

Scope scope = annotations(`Scope`, `class Person`) else Scope(request);
Todo[] todos = annotations(`Todo`, `function method`);

7.4. Language annotations

Certain important annotations are predefined in the module ceylon.language.

7.4.1. Declaration modifiers

The following annotations, called modifiers, are compiler instructions that affect the compilation process:

  • shared specifies that a declaration is visible outside of the package or body in which it occurs, as specified in §5.1.3 Visibility, or that a package is visible outside the module it belongs to, as specified in §4.2 Imports.

  • restricted specifies that a declaration is only referenceable, as defined by §5.1.5 References and block structure, in code belonging to any one of a specified list of modules.

  • abstract specifies that a class cannot be instantiated, or that a constructor is a partial constructor, as specified in §4.5.5 Abstract, final, sealed, formal, and default classes.

  • formal specifies that a member does not specify an implementation and must therefore be refined by every concrete subclass.

  • default specifies that a method, attribute, or member class may be refined by subtypes.

  • actual indicates that a method, attribute, or member type refines a method, attribute, or member type defined by a supertype.

  • variable specifies that a value may be assigned multiple times, as specified in §4.8.1 References.

  • late disables definite initialization checking for a reference, allowing a toplevel reference to omit initialization in its declaration, or a reference which is an attribute of a class to be left unassigned by the initializer of the class, and allows the value to be assigned by any other code, as specified by §4.8.1 References.

  • native specifies that a program element implementation is specific to a certain platform, and should be ignored by the compiler backend when compiling for any other platform, or that it is actually implemented in a different language, and that the program element should be completely ignored by the Ceylon compiler backend, or that a module or module import statement, as defined in §9.3.10 Module descriptors, is specific to a certain platform.

  • deprecated indicates that a value, function or type is deprecated. It accepts an optional String argument. The compiler produces a warning when compiling code that depends upon a deprecated program element.

  • final specifies that a class may not be extended, and may not declare default members, as specified in §4.5.5 Abstract, final, sealed, formal, and default classes.

  • sealed specifies that a class may not be extended or instantiated outside the module in which it is defined, as specified in §4.5.5 Abstract, final, sealed, formal, and default classes, that an interface may not be satisfied by a class or interface outside the module in which it is defined, as specified in §4.4.3 Sealed interfaces, or that a constructor may not be invoked outside the module in which it is defined, as specified in §4.9 Constructors.

  • annotation specifies that a class is an annotation type, or that a toplevel function is an annotation constructor, as specified in §7.2 Annotation definition.

  • serializable specifies that a class is serializable.

  • service specifies that a class implements a given service type.

  • optional specifies that a module dependency is optional at runtime, as defined in §9.3.10 Module descriptors.

  • suppressWarnings hides compilation warnings occurring at the annotated program element.

Note: annotation constraints ensure that these annotations do not occur at program elements to which they do not apply.

The following annotation is a hint to the compiler that lets the compiler optimize compiled bytecode for non-64 bit architectures:

  • small specifies that a value of type Integer or Float contains 32-bit values, or that a value of type Character contains 16-bit values.

By default, Integer and Float are assumed to represent 64-bit values, as specified in §8.5.2 Numeric operations, and Character is assumed to represent 32-bit Unicode code points.

7.4.2. Documentation

The following annotations are instructions to the documentation compiler:

  • doc specifies the description of a program element, in Markdown format text.

  • by specifies the authors of a program element.

  • license specifies the URL of the license under which a module or package is distributed.

  • see specifies a related member or type.

  • throws specifies a thrown exception type.

  • since specifies the version of its module in which a program element was introduced.

  • aliased specifies aliases that tools use to offer suggestions.

  • tagged specifies classifying named tags.

The String arguments to the deprecated, doc, throws and by annotations are parsed by the documentation compiler as Markdown-format content.

These annotations are all defined in the package ceylon.language.

7.5. Serialization

TODO: Define how serialization works.