Attributes with haXe (AKA Metadata or Annotations)
Many languages support metadata in the form of additional information attached to classes, methods or variables. In this post I provide a sample implementation to produce such a thing in haXe.
I created a class Attributes (source code attached to this post) with the following signature:
class Attributes {
public static function of(cls : Class, ?field : String) : Attributes;
public var parent(default, null) : Attributes;
public function exists(key : String) : Bool;
public function get(key : String, ?alternative : String) : String;
public function set(key : String, value : String) : Void;
public function isInherited(key : String) : Bool;
public function keys() : Iterator;
public function iterator() : Iterator;
public function toString() : String;
}
Instances of the class cannot be created directly but they must be obtained using the static method Attributes.of(). The first parameter is the type of the class we want to retrieve attributes, the second optional parameter is a field of that class (it works with either static or instance members). The class is very similar to Hash with the exception that attributes are inherited; so class B that extends class A can inherit or redefine the attributes of B.
Let's see how we can use the class.
import attributes.Attributes;
import haxe.rtti.Infos;
/**
* @author Franco Ponticelli
* @year 2009
*/
class Main implements Infos {
/**
* @role entry point
*/
static function main() {
trace("attributes of Main: " + Attributes.of(Main));
trace("attributes of Main.main: " + Attributes.of(Main, "main"));
}
}
The output is:
Main.hx:15: attributes of Main: { author : Franco Ponticelli, year : 2009 }
Main.hx:16: attributes of Main.main: { role : entry point }
In the first case we have retrieved the attributes of the class Main while in the second the attributes of its method main().
If you want to try you can't forget about two things: classes that provide attributes must implement haxe.rtti.Infos and you must add the directive -D use_rtti_doc when you compile your project. The latter informs the compiler that <haxe_doc> nodes must be included in the generated code.
One nice thing about attributes is that they are both "code" and documentation. Attributes can have a lot of applications, in ORM they can be used to wire a class name to a SQL table name or to map fields and relations to columns; in controllers they can be used to bind a method to certain credentials or templates; in a unit testing system they could be used to mark the functions that are test methods.
There is one thing are a couple of things to consider before embracing this technique, rtti info are stored as XML in the code and the parsing can be slow (the provided implementation caches the results to speed things up) and there is currently a bug in the (bug fixed in CVS, version 2.05 will be bug free)-D use_rtti_doc: overrode methods do not bring their documentation so attributes attached to them are simply discarded. Hopefully the latter problem will be addressed soon.
