Having problems using Getting/Setter with Interface

I’ve been trying to port one of my projects which is the CHAOS UI Framework over to Haxe and ran into some problems. In AS3 using an Interface with the same properties a Sprite class worked out fine. This included properties like name, scaleX, scaleY ,rotate and etc.

Now in the Interface I try to use stuff like this:

var width(default, default) : Float;
var height(default, default) : Float;

But end up getting error messages like this:

…/CHAOS HX/com/chaos/form/ui/TextLabel.hx:14: lines 14-110 : Field height has different property access than in com.chaos.ui.classInterface.IBaseUI ((get,set) should be var)
…/CHAOS HX/com/chaos/form/ui/TextLabel.hx:14: lines 14-110 : Field name has different property access than in com.chaos.ui.classInterface.IBaseUI ((get,set) should be var)

However when I use get,set like requested in the error window I get this:

…/CHAOS HX/com/chaos/form/ui/TextLabel.hx:14: lines 14-110 : Field get_name needed by com.chaos.ui.classInterface.IBaseUI is missing
…/CHAOS HX/com/chaos/form/ui/TextLabel.hx:14: lines 14-110 : Field get_parent needed by com.chaos.ui.classInterface.IBaseUI is missing

Getters and setters work differently when targeting Flash than when targeting anything else. Normally, you’d use (get, set), and then you’d define the corresponding getters and setters.

public var width(get, set):Float;

//...

private function get_width():Float {
    return _width;
}
private function set_width(value:Float):Float {
    return _width = value;
}

When the compiler sees (get, set) after “width,” it looks for corresponding get_width and set_width methods. Then if you say “width = width + 1,” the compiler replaces that with “set_width(get_width() + 1).”

Haxe-style getters and setters work on any target, even Flash. So what’s the problem? Shouldn’t your solution work?

Well, in this case, the compiler doesn’t see “(get, set)” anywhere. The variable definition is just “var width:Float,” with no access modifiers. It’s declared this way in Flash’s Sprite class, which you can’t edit.

You can’t use Haxe-style getters or setters here, but fortunately, Flash provides an alternate version. Flash-style getters and setters happen at runtime, not compile time. Whenever you access a variable in Flash, it checks if there’s a relevant getter or setter. If there is, Flash uses that. So you can’t modify the Sprite class itself, but you can add a getter for the width variable, and then Flash will call your getter.

class MySprite extends Sprite {
    @:getter(width)
    private function get_width():Float {
        return _width;
    }
    
    @:setter(width)
    private function set_width(value:Float):Void {
        _width = value;
    }
}

The names of the functions are totally arbitrary. All you need is the right annotation, and the right function signature.

Speaking of function signatures, you’ll notice that get_width() returned Float in the Haxe example, but now it returns Void. Haxe-style setters must return a value, and Flash-style setters aren’t allowed to return anything, and there’s no way around either of those.

That said, you can still make this work using #if flash tags. This way, you can include a return statement when compiling for most targets, but skip it in Flash. You can also remove “(get, set)” in the Flash target.

#if flash
var width:Float;
#else
var width(get, set):Float;
#end

//...

@:getter(width)
private function get_width():Float {
    return _width;
}

@:setter(width)
private function set_width(value:Float) {
    _width = value;
    
    #if !flash
    return _width;
    #end
}

I left the return value off of set_width() so that Haxe would infer it. Usually, I recommend typing all of your variables and functions, but in this case it would require too much extra code.

This implementation is almost done. The one remaining thing you need to take into account is that you’re extending the Sprite class, and the compiler will give you an error if you try to redefine the width variable. Also, the non-Flash version of Sprite already has get_width() and get_height() functions, so you need to add the override keyword.

//#if flash
//var width:Float;
//#else
//var width(get, set):Float;
//#end

//...

#if flash @:getter(width) #else override #end
private function get_width():Float {
    return _width;
}

#if flash @:setter(width) #else override #end
private function set_width(value:Float) {
    _width = value;
    
    #if !flash
    return _width;
    #end
}
3 Likes

I have a BaseUI class that could pretty much be the “MySprite” in this example. I’ll make the changes you talked about and get back to you.

Everything worked! Now from here on out is just code clean up and getting things to show up.