3.3 제네릭(Generic)

3.3 제네릭(Generic)

보통 Haxe 컴파일러는 타입 매개변수를 가졌더라도 클래스나 함수를 하나만 생성해요. 이는 대상 언어의 코드 생성기가 타입 매개변수가 어떤 타입이든 될 수 있다고 가정해야 하는 자연스러운 추상화를 낳습니다. 생성된 코드는 타입 검사를 수행해야 할 수도 있는데, 이는 성능에 해로울 수 있어요.

클래스나 함수에 @:generic 메타데이터(metadata)를 붙이면 제네릭(generic) 으로 만들 수 있습니다. 컴파일러는 타입 매개변수 조합마다 이름이 맹글링(mangled)된 별개의 클래스나 함수를 생성해요. 이런 명세는 정적 대상(static targets)의 성능 중요 코드 구간에서 출력 크기가 커지는 대가로 성능 향상을 얻을 수 있습니다:

@: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);
  }
}

여기서 MyValue<String>처럼 명시적 타입을 보는 것이 다소 특이해 보일 수 있어요. 타입 추론(type inference)이 비슷한 상황을 자주 처리하기 때문이죠. 하지만 이 경우에는 명시적 타입이 필요해요. 컴파일러가 제네릭 클래스를 생성할 때 정확한 타입을 알아야 하기 때문입니다. JavaScript 출력이 그 결과를 보여줘요:

(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();
})();

MyValue<String>MyValue<Int>가 각각 MyValue_StringMyValue_Int가 되었음을 확인할 수 있어요. 제네릭 함수의 경우도 비슷합니다:

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

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

역시 JavaScript 출력이 명확하게 보여줘요:

(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);
};
...

출처: Generic

본문

기본 동작과 @:generic

일반적으로 타입 매개변수가 있어도 컴파일러는 클래스/함수를 하나만 생성하고, 타입 매개변수를 임의 타입으로 취급합니다. @:generic 메타데이터를 붙이면 타입 매개변수 조합마다 별도의 클래스/함수를 만들어 성능을 높일 수 있어요. 이름은 맹글링되어 구분됩니다.

장단점

@:generic은 정적 대상에서 타입 검사 오버헤드를 줄여 성능을 올려주지만, 생성 코드가 커지고 명시적인 타입 지정이 필요해요. 출력 크기가 커지는 대가를 치르는 대신 성능 중요 코드에서 이득을 얻을 수 있답니다.

생성 코드 확인

JavaScript 출력을 보면 MyValue<String>MyValue_String으로, MyValue<Int>MyValue_Int로 각각 별도의 클래스로 생성됨을 확인할 수 있어요. 함수의 경우도 method_String·method_Int처럼 별도 함수로 생성됩니다.

더 알아보기