Attributes and Aspects

Elements provides full support for attributes on all platforms, and support for a select number of compiler-defined special Attributes. In addition, Elements allows the compiler itself to be extended by defining Aspects, which essentially are more sophisticated attributes that can control the compiler's behavior.

An attribute is a tag that can be applied to certain code elements (for example classes or methods) or — on .NET only — the executable itself to provide additional information that is not part of the core code. The function of attributes can vary widely, from actually affecting the compiler's behavior to merely attaching a piece of information to a code element that can be queried for at runtime using Reflection.

On .NET and Java, attributes are types that descend from System.Attribute (.NET) or implement the java.lang.annotation.Annotation interface (Java), respectively. On Cocoa, all attributes are [compiler-defined](Special Attributes (Cocoa) "wikilink"), and custom attributes are not supported.

Cirrus is an extension of the standard attribute syntax and concept that allows for the creation of even more flexible Aspects that can influence how the compiler handles the annotated code. Cirrus aspects are supported for all platforms, but are always implemented in .NET.

Example

For example, the Conditional attribute (defined by the .NET runtime, and provided by the Elements compiler for Cocoa and Java) causes the compiler to omit any calls to the methods it is attached to, unless the passed conditional define (in this case "DEBUG") is defined.

type
  DebugHelper = public class
  public
    [Conditional('DEBUG')]
    class method DebugOutput(aData: String);
  end;
public class DebugHelper
{
    [Conditional("DEBUG")]
    public static void DebugOutput(string data) {
        ...
    }
}
public class DebugHelper {
    @Conditional("DEBUG") 
    public static func DebugOutput(string data) {
        ...
    }
}
public class DebugHelper {
    @Conditional("DEBUG") 
    public static void DebugOutput(string data) {
        ...
    }
}

In this example, other parts of code might contain calls to DebugHelper.DebugOutput(). These calls will turn into no-ops and not be compiled into the final executable, unless the DEBUG define is set.