Fixing breaking changes on static extensions in Haxe 4

Whenever I ask questions here I’m overcome with anxiety that it might be a stupid question. But anyway…

I’ve installed Haxe 4 rc2 and I’m getting errors related to static extensions. I’m using the Advanced Layout library which is designed to be used with a “using” directive, adding layout sugar to display objects. The errors relate to the extra fields such as “alignLeft” or “verticalPercent” no longer being added to the displayObjects.

My research indicates that some breaking changes in Haxe 4 are that static extensions no longer resolve on an implicit this type, and static extensions no longer apply abstract field-casts. So I suspect this is what’s happening.

In Advanced Layout the abstracts and casting are happening in the Resizable class, and the added fields are in the LayoutCreator class. Could somebody please take a peek at these and give me a hint of where to start fixing?

To save you a click, here’s the jist of what’s in Resizable:

@:forward(x, y, width, height, baseWidth, baseHeight, left, right, top, bottom)
abstract Resizable(ResizableImpl) from ResizableImpl {
	public var scaleX(get, set):Float;
	public var scaleY(get, set):Float;
	
	public var centerX(get, never):Float;
	public var centerY(get, never):Float;
	
	/**
	 * Useful for when you need something invisible to mark a position.
	 */
	public function new() {
		return cast new RectangleResizable(new Rectangle(0, 0, 1, 1));
	}
	
	@:from private static inline function fromDisplayObject(displayObject:DisplayObject):Resizable {
		return cast new DisplayObjectResizable(displayObject);
	}
//etc...
}

Okay one more try here. I know this is hard to grok just reading words on a forum—any help is greatly appreciated.

To recap, my problem is that in Haxe 4 the abstracts in advanced-layout lib are not being applied as they did in Haxe 3. To use it before (in Haxe 3) one only needed to include a using layout.LayoutCreator line, and then new layout methods (static extensions) would be available on OpenFL DisplayObjects such as “centerX” etc. In Haxe 4 these are not applied.

It seems that the problem relates to how the library tries to handle many different types of view objects, i.e. Display Object, Haxe UI Object, FlxSprite, HaxePunk Entity. Instead of declaring the new layout methods in an Abstract (which would then compile to a DisplayObject or whatever) it declares the layout methods in the LayoutCreator and then casts the view objects to its own class “Resizable” which is the abstract with methods of its own. To complicate things further, the first parameter passed to Resizable is cast as ResizableImpl (which adds more fields) and there are custom @:from directives in Resizable which will cast the view object to other classes such as DisplayObjectResizable (extending ResizableImpl.)

Is there a surefire way to solve all these inheritance problems or does this thing need a complete refactor? Am I better off using a different layout framework?

Now I feel guilty for having suggested that change :blush:

Well, I guess you have these options:

  1. for every view object kind that you care fore, make an extension class that forwards the calls to LayoutCreator (this would best be achieved via macros)

  2. Do something like this:

    class Helper {
      static public inline function layout(r:com.player03.layout.Resizable, ?f) {
        if (f != null) f(r);
        return r;
      }
    }
    
    import Helper.layout;
    layout(
     mySprite, s -> {
       s.simpleScale();
       s.fillPercentWidth(0.5);
       s.fillPercentHeight(0.5);
      }
    );
    layout(myBitmap).matchWidth(sprite);
    layout(myBitmap).maintainAspectRatio();
    

    You can also give the method a one-letter name if length worries you (the result will look quite jQuery-esque I guess).

  3. Make a PR upstream that returns the Resizable from the extension methods, you you can chain:

    layout(mySprite)
      .simpleScale()
      .fillPercentWidth(0.5)
      .fillPercentHeight(0.5);
    

Thanks so much! I think I will try solution 2 first since I can actually understand what’s going on there. What needed to click in my mind is that the view object needs to be cast to Resizable before entering the LayoutCreator. Really appreciated.

It’s working good! :slight_smile:

In other news, @player_03 is working on a proper upgrade now.