Search code examples
interfaceabstract-classhaxetype-constraints

In Haxe, how to enforce method declarations in subclass when it is not defined in it's "abstract" superclass?


I'm trying to write a class-definition in such a way that, when used within a function or var declaration (such as function instantiateMain(mainCls:Class<MyAbstractClass>)), it should enforce the subclass to have the required method(s) specification. For example, an init() method.

So...

Is there a way to write a class in an abstract way, so that it checks at compile-time for its subclass (the one calling ... extends MyAbstractClass) to declare a specific method(s), and YET be able to extend another existing class (ex: AbstractSprite extends Sprite, or AbstractMC extends MovieClip)?

Alternatively, can Class<...> list more than one constraint types (classes & interfaces)?

For example, Class<Sprite, MyInterface> - tried this already though, maybe my syntax is incorrect.

EDIT:

To add more of a context to the question, here's the code I'm trying to get working:

package;

import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.Lib;

class MyInitializer {
    public static var INSTANCE:MyInitializer;
    public static var STAGE:Stage;

    public static function init(clazz:Class<DisplayObject, InterfaceMain>) {
        if (INSTANCE != null) return INSTANCE;

        //Create a new instance of this global class:
        INSTANCE = new MyInitializer();

        //Add the 'Main' class to the stage:
        STAGE.addChild( Type.createInstance( clazz, [] ) );

        return INSTANCE;
    }
}

class SpriteMain extends Sprite implements InterfaceMain {

}

class MovieClipMain extends MovieClip implements InterfaceMain {

}

interface InterfaceMain {
    function init():Void;
}

Solution

  • You can define types as having multiple constraints:

    typedef Measurable = {
      public var length(default, null):Int;
    }
    
    class Constraints {
      static public function main() {
        trace(test([]));
        trace(test(["bar", "foo"]));
        // String should be Iterable<String>
        //test("foo");
      }
    
      static function
      test<T:(Iterable<String>, Measurable)>(a:T) {
        if (a.length == 0) return "empty";
        return a.iterator().next();
      }
    }