COMMUNITY

Binding on the JS target

haxe-js

(Vladimir Velikov) #1

Hi all,
I’ve a question about the js generator.

If you take a look at https://try.haxe.org/#23850 you’ll see that instead of relying on the native js binding functionality, the generator creates wrapper-functions that carry the bound parameters within their scope. I think it hasn’t always been this way, but I’m not sure.

The problem we have with this is that you lose the reference to the results of the bind calls, and thus if you use those as listeners (think Observable pattern), you cannot remove them afterwards.

So two questions:

  • Is the reason for these wrapper-functions merely for code-transparency/debugging purposes, or is there something else I’m missing?

  • How would you go about changing the generator behaviour if you have legacy code that suddenly turns out to be leaking? What I’ve tried so far is:

  1. A macro approach which lead me to eventually replace all classes that make use of bind at Compiler.onGenerate and it is not optimal.
  2. Regular expression replacement in already generated js feels too non-haxe-y to become comfortable with.
  3. I was hoping there would be a compiler directive that handles this, but couldn’t find one.

What’s left is a custom JS generator, which feels like overkill.

Thanks in advance!


(Mark) #2

Indeed, when you use bind, you always get a new function. so calling test.bind(1) twice results in two functions, not a same instance. This is described in the bind documentation.

This means, you can never do observers.remove(test.bind(1));, since you will remove a function you just created (and is never in the observers list.

What you are describing so its not an issue of the js-generator, but a architectural issue; how do you remove a anonymous function? It might be less usable for the observable pattern, but it if you can just store a reference to the function, and you are able to remove it.

class Main {
    static function main() new Main();
  	private var observers:Array<Void->Void> = [];
    private var removeMeLater:Void->Void;
    
    public function new() {
        // Remove later, store reference
        this.removeMeLater = test.bind(1);
        observers.push(this.removeMeLater);
        
        // .. somewhere else in your code
        observers.remove(this.removeMeLater);
        
        trace(observers.length); // 0
    }
    
    function test(a) trace(a);
}

(Kevin Leung) #3

Don’t confuse Haxe’s bind with native JS’s bind. They are completely different things.

Haxe’s bind is a partial application of function. Think of it as pre-filling some arguments to a function.
JS’s bind controls the this object reference within the function body. In Haxe there is no such thing as this always points to the current class instance and cannot be customized.