hxhsl: binding targets on the JS target and "this"

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

hxhsl: binding targets on the JS target and "this"

Dion Amago
I've developed a light-weight injection system for binding listeners
to signals.  It works great in AS3, but in JS, there's a problem with
function scope.  I'm fairly new to JS, so I may be missing something
obvious.

In JS, a normal bind call works fine.  However when the injector binds
the listener to the signal, instead of the the listener owner being
"this", the RegularBond object is, meaning that I can't access any
relevant local variables.

The injector works by reading class method annotations, and grabbing
the appropriate signal and calling the bind method.  So the bind call
is not occurring within the class owning the listener function, but
elsewhere.  In JS, maybe this alters the scope, changing "this" to
whatever owns the function.  The problem is, I don't see why this
transfer of scope doesn't happen anyway, despite the differences in
calling "bind".

--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: hxhsl: binding targets on the JS target and "this"

Franco Ponticelli
You should probably post some code; in the meanwhile try to give a look at Reflect.callMethod since it should permit you to restore the proper scope, something like: Reflect.callMethod(obj, Reflect.field(obj, "foo"), [])
Note that the second argument is not the method name but a reference to it.

Franco.

On Wed, Sep 8, 2010 at 5:21 PM, Dion Amago <[hidden email]> wrote:
I've developed a light-weight injection system for binding listeners
to signals.  It works great in AS3, but in JS, there's a problem with
function scope.  I'm fairly new to JS, so I may be missing something
obvious.

In JS, a normal bind call works fine.  However when the injector binds
the listener to the signal, instead of the the listener owner being
"this", the RegularBond object is, meaning that I can't access any
relevant local variables.

The injector works by reading class method annotations, and grabbing
the appropriate signal and calling the bind method.  So the bind call
is not occurring within the class owning the listener function, but
elsewhere.  In JS, maybe this alters the scope, changing "this" to
whatever owns the function.  The problem is, I don't see why this
transfer of scope doesn't happen anyway, despite the differences in
calling "bind".

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: hxhsl: binding targets on the JS target and "this"

Dion Amago
This code demonstrates the problem.  To reiterate the problem:

On the js compiler, the "this" keyword references different objects in the bar.function method when binding signals these different ways:

        foo.signaler.bind(bar.listener);
        foo.signaler.bind(Reflect.field(bar, "listener"));

On flash, the bar object is the "this" reference for both listeners (ok, it's the same listener bound twice). On js, "this" is the bar for the first binding, on the second the "this" references the Bond object.
I've looked at the source, but still can't figure out why the first works but not the second.  In both cases the function becomes a member of the Bond object.

In the first case, the js version is

foo.signaler.bind(bar.listener);

and the second is:

foo.signaler.bind(bar["listener"]);

I thought that these two ways of referencing members are functionally equivalent WRT class properties, but this code seems to say otherwise.  Does anyone know why these two produce different results?




Code:

package;

import hsl.haxe.DirectSignaler;
import hsl.haxe.Signaler;

class Demo
{
    public function new ()
    {
        var foo = new Foo();
        var bar = new Bar();
       
        foo.signaler.bind(bar.listener);
        foo.signaler.bind(Reflect.field(bar, "listener"));
       
        foo.fire();
    }
   
    public static function main()
    {
        new Demo();
    }

}

class Foo
{
    public var signaler :Signaler<String>;
   
    public function new ()
    {
        signaler = new DirectSignaler(this);
    }
   
    public function fire () :Void
    {
        signaler.dispatch("firing");
    }
   
    public function toString () :String
    {
        return "Foo";
    }
}

class Bar
{
    public function new ()
    {
    }
   
    public function listener (signalText :String) :Void
    {
        trace(signalText + " recieved on " + this);
    }
   
    public function toString () :String
    {
        return "Bar";
    }

}


Franco Ponticelli wrote:
You should probably post some code; in the meanwhile try to give a look at Reflect.callMethod since it should permit you to restore the proper scope, something like:  Reflect.callMethod(obj, Reflect.field(obj, "foo"), [])
Note that the second argument is not the method name but a reference to it.

Franco.

On Wed, Sep 8, 2010 at 5:21 PM, Dion Amago <[hidden email]> wrote:
I've developed a light-weight injection system for binding listeners
to signals.  It works great in AS3, but in JS, there's a problem with
function scope.  I'm fairly new to JS, so I may be missing something
obvious.

In JS, a normal bind call works fine.  However when the injector binds
the listener to the signal, instead of the the listener owner being
"this", the RegularBond object is, meaning that I can't access any
relevant local variables.

The injector works by reading class method annotations, and grabbing
the appropriate signal and calling the bind method.  So the bind call
is not occurring within the class owning the listener function, but
elsewhere.  In JS, maybe this alters the scope, changing "this" to
whatever owns the function.  The problem is, I don't see why this
transfer of scope doesn't happen anyway, despite the differences in
calling "bind".

--
haXe - an open source web programming language
http://haxe.org


--
haXe - an open source web programming language
http://haxe.org
Reply | Threaded
Open this post in threaded view
|

Re: hxhsl: binding targets on the JS target and "this"

Niel Drummond-3
On haxe-javascript, referencing a function creates a closure and rebinds the 'this' keyword by using the javascript construct 'Function.apply', whereas Reflection simply references the function directly. you can see this if you do the following in a console capable browser:

untyped console.log(bar.listener);
untyped console.log(Reflect.field(bar, "listener"));

the effect of this is in the first case is as expected, because function.apply is intended to call functions while rebinding scope to the specified object (in this case an instance of Bar), though in the second case, 'this' is only resolved when when the function is actually called, causing unexpected results.

- Niel

On 11/22/10 19:24, dionjw wrote:
This code demonstrates the problem.  To reiterate the problem:

On the js compiler, the "this" keyword references different objects in the bar.function method when binding signals these different ways:

        foo.signaler.bind(bar.listener);
        foo.signaler.bind(Reflect.field(bar, "listener"));

On flash, the bar object is the "this" reference for both listeners (ok, it's the same listener bound twice). On js, "this" is the bar for the first binding, on the second the "this" references the Bond object.
I've looked at the source, but still can't figure out why the first works but not the second.  In both cases the function becomes a member of the Bond object.

In the first case, the js version is

foo.signaler.bind(bar.listener);

and the second is:

foo.signaler.bind(bar["listener"]);

I thought that these two ways of referencing members are functionally equivalent WRT class properties, but this code seems to say otherwise.  Does anyone know why these two produce different results?




Code:

package;

import hsl.haxe.DirectSignaler;
import hsl.haxe.Signaler;

class Demo
{
    public function new ()
    {
        var foo = new Foo();
        var bar = new Bar();
       
        foo.signaler.bind(bar.listener);
        foo.signaler.bind(Reflect.field(bar, "listener"));
       
        foo.fire();
    }
   
    public static function main()
    {
        new Demo();
    }

}

class Foo
{
    public var signaler :Signaler<String>;
   
    public function new ()
    {
        signaler = new DirectSignaler(this);
    }
   
    public function fire () :Void
    {
        signaler.dispatch("firing");
    }
   
    public function toString () :String
    {
        return "Foo";
    }
}

class Bar
{
    public function new ()
    {
    }
   
    public function listener (signalText :String) :Void
    {
        trace(signalText + " recieved on " + this);
    }
   
    public function toString () :String
    {
        return "Bar";
    }

}


Franco Ponticelli wrote:
You should probably post some code; in the meanwhile try to give a look at Reflect.callMethod since it should permit you to restore the proper scope, something like:  Reflect.callMethod(obj, Reflect.field(obj, "foo"), [])
Note that the second argument is not the method name but a reference to it.

Franco.

On Wed, Sep 8, 2010 at 5:21 PM, Dion Amago <[hidden email]> wrote:
I've developed a light-weight injection system for binding listeners
to signals.  It works great in AS3, but in JS, there's a problem with
function scope.  I'm fairly new to JS, so I may be missing something
obvious.

In JS, a normal bind call works fine.  However when the injector binds
the listener to the signal, instead of the the listener owner being
"this", the RegularBond object is, meaning that I can't access any
relevant local variables.

The injector works by reading class method annotations, and grabbing
the appropriate signal and calling the bind method.  So the bind call
is not occurring within the class owning the listener function, but
elsewhere.  In JS, maybe this alters the scope, changing "this" to
whatever owns the function.  The problem is, I don't see why this
transfer of scope doesn't happen anyway, despite the differences in
calling "bind".

--
haXe - an open source web programming language
http://haxe.org



--
haXe - an open source web programming language
http://haxe.org