3.3 Generic

Usually, the Haxe Compiler generates only a single class or function even if it has type parameters. This results in a natural abstraction where the code generator for the target language must assume that a type parameter could be of any type. The generated code might then have to perform type checks which can be detrimental for performance.

A class or function can be made generic by attributing it with the @:generic metadata. This causes the compiler to emit a distinct class or function per type parameter combination with mangled names. A specification like this can yield a boost in sections of performance-critical code on static targets at the cost of a larger output size:

@:generic
class MyValue<T> {
  public var value:T;

  public function new(value:T) {
    this.value = value;
  }
}

class Main {
  static public function main() {
    var a = new MyValue<String>("Hello");
    var b = new MyValue<Int>(42);
  }
}

It may seem unusual to see the explicit type MyValue<String> here as type inference often handles similar situations. Nonetheless, it is required in this case as the compiler must know the exact type of a generic class upon construction. The JavaScript output shows the result:

(function () { "use strict";
var Test = function() { };
Test.main = function() {
    var a = new MyValue_String("Hello");
    var b = new MyValue_Int(5);
};
var MyValue_Int = function(value) {
    this.value = value;
};
var MyValue_String = function(value) {
    this.value = value;
};
Test.main();
})();

We can identify that MyValue<String> and MyValue<Int> have become MyValue_String and MyValue_Int respectively. The situation is similar for generic functions:

class Main {
  static public function main() {
    method("foo");
    method(1);
  }

  @:generic static function method<T>(t:T) {}
}

Again, the JavaScript output makes it obvious:

(function () { "use strict";
var Main = function() { }
Main.method_Int = function(t) {
}
Main.method_String = function(t) {
}
Main.main = function() {
    Main.method_String("foo");
    Main.method_Int(1);
}
Main.main();
})();