AS3 hasOwnProperty() to Haxe Reflect and Type

Porting some very dynamic AS3 libraries, built on-top of each other, I’m unsure how to elegantly handle some issues porting AS3’s hasOwnProperty() method.

For example, in a concrete Haxe class I have a property:

    private var _label:String;

    public var label(get, set):String;

    public function set_label(value:String):String {
        return _label = value;
    }

    public function get_label():String {
        return _label;
    }

The originaly AS3 library could simply call: obj.hasOwnProperty("label");

In Haxe, there are two issues:

Using Reflect.hasField(obj, "label") returns false, as this is geared towards anonymous structures.

After getting the class type of the instance, I can call Type.getInstanceFields(type), then search using Lambda.has() - despite the heavy 3-step process, this still fails as it finds the private field, accessor, and mutator methods:

  • _label
  • get_label
  • set_label

What’s the more elegant approach, ideally to the instance, to determine whether a field or property exists?

As in this case, how can I determine that my class instance has the property label?

your don’t need to define a private member for accessing/mutating the value, you can automatically create one using @:isVar, and it will also allow you to access it with Reflect.hasField(obj, “label”)

@:isVar public var label(get, set):String;

public function set_label(value:String):String {
    return label = value;
}

public function get_label():String {
    return label;
}

Thanks, I appreciate that; though, I prefer the private member for faster lookups internal to the class. If there’s business logic inside the setter, I hate time spent calling the accessor.

This will work for these libraries, though.

it compiles to the same javascript code, Flash test shows no performance difference. I can’t say for all languages but I would assume the compiled code to be the same

My OpenFL Haxe Benchmark project shows a factor of 10 - accessing the property is 10x slower than the field itself. But within these libraries, these properties are not performance critical segments of code.

Not sure I trust TryHaxe site for analysis of compiled code.

Per private members, I also like the clarity in combination with Dox documentation. At the beginning of my class, I can define my data model with private members; then, add my code documentation to the property.

Seems strange to me that using the metadata enables reflection to work, when this should result in the same assembly after code generation of the compiler. I’ll have to examine the generated code across targets to fully understand.

Using @:isVar does some significant code generation, which I don’t believe is possible purely in Haxe.

In generated AS3, the property name becomes a protected member:

protected var $label : String;

Actual properties then call accessor / mutator functions:

public function get label() : String { return get_label(); }
public function set label( __v : String ) : void { set_label(__v); }

public function set_label(value : String) : String {
    this.$label = value;
    return this.get_label();
}		
public function get_label() : String {
    return this.$label;
}

Likewise in c++ targets:

::String label = __o_label.Default(HX_HCSTRING("","\x00","\x00","\x00","\x00"));

::String Label_obj::set_label(::String value){
            	HX_STACKFRAME(&_hx_pos_32f3fa18ddcc29cc_117_set_label)
HXLINE( 118)		this->label = value;
HXLINE( 122)		return this->get_label();
            	}

::String Label_obj::get_label(){
            	HX_STACKFRAME(&_hx_pos_32f3fa18ddcc29cc_126_get_label)
HXLINE( 126)		return this->label;
            	}

Significant function overhead there, but rewrites to adaption both target platform as well as Haxe.

Perhaps Reflect.hasField ("label") || Reflect.hasField ("get_label") may be useful in some cases? Since “get_” is required by convention, it makes it simpler to make assumptions and discover getters/setters

Tangentially, how do you see the generated as3 code from a haxe project?

There was a time you could simply add the as3 haxeflag to your project.xml:

<haxeflag name="-as3" value="output_dir" />

Probably a more slick way of doing this, but I do a Flash build:

$ openfl build flash -debug

Then, move the debug.hxml back up to the project level

$ mv Export/flash/debug/haxe/debug.hxml .

In that debug.hxml, remove the -swf and replace it with:

-as3 output_dir

Then, execute that hxml:

$ haxe debug.hxml

Generated AS3 will be in the output-folder/.

Haxelib libraries use a different methodology.

1 Like

Here’s something else you could try:

<haxedef name="dump" value="pretty" />

This will create a “dump” directory containing the fully-processed Haxe code. It won’t answer every question, but it’ll tell you if something was removed by the compiler.

Perhaps we should improve openfl.utils.Object here:

https://github.com/openfl/openfl/blob/develop/openfl/utils/Object.hx#L14

That may allow for the same code :slight_smile:

EDIT: we should also consider making the __get and __set methods of Object (for array access) understand getters and setters to help this address this as well

1 Like

Wow nice idea! haxe generates as3 files woah!

If haxe generates as3 with Away3D and HaxeUI 2.0 than you can see how is Agla3 ( Stage3D with a lot of assemblies )

EDIT:
I found main.as and I have got errors “Error: Incompatible override.” Wow it cannot compile. But how does haxe generate swf clean? But I can not compile manual with mxmlc? Do you know how does it fix for overrides?

From Haxe: as3 sources recompiled to swf and has over 309 errors

From FFdec as3 sources recompiled to swf and has 106 errors

It is very impossible because it can generate 1:1 real swf. How does it work?

When Haxe compiles a SWF, it skips AS3 entirely. This means there might be AS3 bugs even though the SWF works perfectly.

There’s some additional discussion here:

https://groups.google.com/forum/#!topic/Haxelang/qhszd9Yucko

I think the generated AS3 may need a little bit of bootstrapping, but sounds like its being used alright

I’m pretty sure the transpiled AS3 is compiled.

1 Like

Yeah you’re right! But I don’t understand why haxe compiles successful with AS3 into SWF. But mxmlc can not. Or I went wrong. Is it for ASC Compiller 2.0?

You seem to think that when you type openfl test flash, this happens:

  1. Your Haxe code is converted to AS3 code.
  2. The AS3 code is converted into SWF bytecode.
  3. The SWF bytecode is used to make a SWF.

But in fact, this is what happens:

  1. Your Haxe code is compiled into SWF bytecode.
  2. The SWF bytecode is used to make a SWF.

When Haxe compiles a SWF, it skips AS3 entirely.

The AS3 code has errors.

Haxe doesn’t use AS3 code. That’s how it compiles successfully.

MXMLC uses AS3 code. That’s why it fails.