CHAPTER 13

Attribute

Attribute is a special class type used to facilitate meta-programming. Attributes annotate the source code at specific places, such as type and method declaration. These attributes are then loaded along with the type itself into the engine runtime during type loading. Later these attributes can be retrieved through reflection.

Here we define an attribute, then use it to annotate a class definition:

  attribute Author {
    string name;
    int year;
  }

  [Author(name="Liam", year=1980)]
  class MyClass {

  }

As shown above, each field on the attribute can be initialized with an expression, which is called attribute initializer. Fields which are not explicitly initialized will retain their default value. The attribute initializers get evaluated as part of type loading. The implication of this timing is that they cannot access to the type system as other parts of the script would. In fact, only primitive types, module-less types such as String, as well as any Enum types, can be referred here. Attempt to use any other types, either as the type of attribute member, or via intermediate values to access to directly or indirectly from the initializer, including all System.* (with the exception of some meta-attribute types) and user-defined type, will result in exception.

Throughout the runtime, MyClass will retain the attribute instance Author(name="Liam", year=1980). This attribute can be retrieved through reflection. We will talk about how in a later chapter.

Attributes are themselves annotated by attributes, which are called meta-attributes. Meta-attributes are predefined and provided as engine built-ins.

  // (Provided by engine)
  attribute AttributeType {
    // If true, multiple instances of this attribute can be applied at same place.
    bool allowMultiple;
    // The allowed types of target. This is the bitwise sum (OR'ed) of all the allowed target constants.
    int target;
  }
  
  class AttributeTarget {
    static const int CLASS = 0b000001;
    static const int ATTRIBUTE = 0b000010;
    static const int ENUM = 0b000100;
    static const int METHOD = 0b001000;
    static const int FIELD = 0b010000;
    static const int CONSTRUCTOR = 0b100000;
  }
  
  // Declare a new attribute that can be applied on class and method definition.
  [AttributeType(allowMultiple=false, target=AttributeTarget.CLASS | AttributeTarget.METHOD)]
  attribute Unchecked {
    
  }

Attributes are the main means to set up platform interop. We will see a lot of attribute usage in Interoperating with Platform.