Strange Neko Bug When Inlining Getters

So while trying to create simple wrapper classes for some of OpenFL’s built-ins I’ve encountered a very strange issue that only affects Neko. Long story short, it seems that in-lining getter methods in a function call cause Neko to somehow lose its context within the called function.

obj1.fn(obj2.get_some_value()); // "this" gets corrupt within get_some_value()

I’ve created a repo to demonstrate the problem:

https://github.com/Cleod9/WeirdOpenFLNekoBug

While there are a couple of workarounds, this seems to be a major gotcha for the Neko platform that I haven’t been able to find any other topics on. Would really appreciate it someone else could take a look at this, as I have already been avoiding property getter/setters in favor of traditional getter/setter methods so that it behaves more consistently across platforms :pray:

Neko has a different way of handling Dynamic instances.

On other platforms (ActionScript, JavaScript, etc) the class type is preserved on the object. Even if the object is dynamically typed, object.classMethod () still exists, because it’s a part of the object prototype chain. Under the hood (of course) that’s what JavaScript is really using, until ES6 there was no class type in JavaScript.

Neko works instead by using lookups, to know what class methods/statics (etc) are available. If you lose the object’s type, it also loses it’s ability to find these methods. As a result, passing an object through Dynamic, it sort of forgets what class it is.

If you remove the Dynamic types from your sample, it works. I would recommend avoiding the use of Dynamic on Neko, at least for referencing methods in this way.

1 Like

Thanks so much for the detailed explanation! @singmajesty

Do you happen to know why the code works given the two workarounds? I don’t mind avoiding Dynamic altogether if necessary, but I would like to understand a little better why Neko is able to lookup the proper type when it’s not evaluated inline like this.

Perhaps my explanation applies to class-member methods, and not necessarily to variables?

That’s not a bad hypothesis, yet it works fine when the method is called on a separate line :thinking:. It seems like something funky is going on with the function stack to me, but i don’t have proof of this.

Before I give up on this completely, is there a way to read the intermediary.neko code before it gets turned into a binary .n file?

Looks like it’s -D neko-source, but I haven’t tried it

Thanks, that worked for me!

So it does appear to be a Neko-specific issue:

Broken output (inline function call in source):

 @tmp.addChild = function(value) {
        var tmp = this.stage.addChild;
        tmp(value.get_instance());
        return null;
    }

Fixed output (expanded the inline in source):

    @tmp.addChild = function(value) {
        var ins = value.get_instance();
        this.stage.addChild(ins);
        return null;
    }

What I find especially interesting about is that the broken version already goes out of its way to create a temp variable, despite it breaking the code (most likely because of what you said before- neko doesn’t know what type stage is anymore)

It seems like assigning the method of a Dynamic object to a temporary var is dangerous in Neko. It would be nice if the compiler warned about this, or didn’t allow it altogether. But this could also probably fixed one of three ways:

  1. If haxe’s neko output assigned the object to a tmp instead of the function
  2. If haxe’s neko output remained inline altogether instead of expanding into additional tmp vars
  3. If haxe’s neko output used $call on all functions assigned from Dynamic vars (e.g. $call(tmp, this.stage,$array(this.stage));)

Any thoughts? I feel like taking some kind of action, even if just a warning, would be helpful for devs just getting into OpenFL/Haxe

I would post an issue to https://github.com/haxefoundation/haxe/issues, I think you’re able to make a simple reproduction case, and illustrate how the compiler is creating broken Neko bytecode. Would be great to get more visibility on it

1 Like

Alright cool, I’ll head over there next. Thanks again for the feedback!