kolonitsky
kolonitsky

Reputation: 124

How to check that object is instance of generic in Haxe

I'm looking for a safe way to fork logic depending on the object type. I haven't found out how to check if an object belongs to a specific generic type.

class Test {
    static function main() {
        var aa = new AA<Int>();
        //ERROR: Cast type parameters must be Dynamic
        //var a:A<Int> = cast(aa, A<Int>); 

        //ERROR: Unexpected )
        //var a:A<Int> = Std.instance(aa, A<Int>);

        //OK, but throw run-time exception with flash target. 
        var a:A<Int> = cast aa; 
        a.printName();

        //Run-time exception
        a = cast "String is obviously wrong type";
    }
}

class A<T> {
    public function new () { }
    public function printName() {
        trace("Generic name: A");
    }
}

class AA<T> extends A<T> {
    public function new () { super(); }
    override public function printName() {
        trace("Generic name AA");
    }
}

Is there a legal way to check if an object belongs to a generic type?

Upvotes: 3

Views: 1476

Answers (1)

Gama11
Gama11

Reputation: 34138

There is generally no great way of doing this, because the information is not available at runtime anymore. You could use the same workaround that is often suggested for Java, which is storing the generic type in your class:

class Main {
    static function main() {
        var a = new A<Int>(Int);

        trace(a.typeParamIs(Int)); // true
        trace(a.typeParamIs(Bool)); // false
    }
}

class A<T> {
    var type:Any;

    public function new (type:Any) {
        this.type = type;
    }

    public function typeParamIs(type:Any):Bool {
        return this.type == type;
    }
}

Alternatively, you could use Type.typeOf() like this if A has a field of type T:

class Main {
    static function main() {
        checkType(new A<Int>(5)); // Int
        checkType(new A<Bool>(true)); // Bool
        checkType(new A<B>(new B())); // B
        checkType(new A<B>(null)); // unhandled type TNull
    }

    static function checkType<T>(a:A<T>) {
        trace(switch (Type.typeof(a.value)) {
            case TInt: "Int";
            case TBool: "Bool";
            case TClass(cls) if (cls == B): "B";
            case other: throw "unhandled type " + other;
        });
    }
}

class A<T> {
    public var value:T;
    public function new (value:T) {
        this.value = value;
    }
}

class B {
    public function new() {}
}

As you can see, while this usually works, it might lead to unexpected behavior in some cases - such as when value is null. Also keep in mind the docs of Type.typeOf():

May vary per platform. Assumptions regarding this should be minimized to avoid surprises.


Further reading: mailing list thread where this has been discussed a while back. A macro solution is mentioned there, in case you do not need to know the type at runtime.

Upvotes: 4

Related Questions