Annotating Types and Type Members
Go Up to Attributes Index
This topic describes the syntax and rules appropriate when annotating a type or a member with an attribute.
Annotating an attribute using its parameterless constructor:
[AttributeClassName] or [AttributeClassName()]
Annotating an attribute using one of its constructors with parameters:
[AttributeClassName (parameters) ]
The constructs above must be succeeded by a syntactical element that allows annotation. The following code blocks exemplify the different language constructs that allow annotations.
Annotating a class
type [AttributeClassName] TNewClass = class(TObject) ... end;
Annotating a record
type [AttributeClassName] TRecord = record ... end;
Annotating a simple type
type [AttributeClassName] TSimpleType = set of (stOne, stTwo, stThree);
Annotating a class member
type TNewClass = class(TObject) [AttributeClassName] FString: String; ... end;
An attribute that is annotated to a type or a member is inserted into the RTTI information block in the generated binary. The emited information includes:
- The class type of the attribute.
- The pointer to the selected constructor.
- A list of constants that are later passed to the attribute constructor.
It is important to understand that the values passed to the attribute's constructor must be constant expressions. Because those values must be embedded directly into the resulting binary, it is impossible to pass an expression that requires run-time evaluation. This raises a few limitations to the information that can be passed to the attribute at compile time:
- Only constant expressions are allowed, including sets, strings, and ordinal expressions.
- out and var parameters cannot be used, because they require run-time evaluation of addresses of passed parameters.
- Addr() intrinsic and @ operator cannot be used.
- The TypeInfo() operator can be used to pass type information, because the RTTI block addresses are known at compile time.
- Class references are allowed, because the metaclass addresses (as the case of TypeInfo()) are known at compile time.
The following code exemplifies the case in which the compiler does not compile the annotation:
var a, b: Integer; type [SomeAttribute(a + b)] TSomeType = record ... end;
In the previous example, the constructor of SomeAttribute requires an integer value. The passed expression requires a run-time evaluation of a + b. Because the compiler expects a constant expression, a compile-time error is emitted.
The code below shows an accepted expression:
const a = 10; b = 20; type [SomeAttribute(a + b)] TSomeType = record ... end;
The values of a and b are known at compile time; thus, the constant expression is evaluated directly.