Arrow binding

Russell Leggett russell.leggett at gmail.com
Mon Apr 23 06:47:08 PDT 2012


On Mon, Apr 23, 2012 at 6:53 AM, Alex Russell <alex at dojotoolkit.org> wrote:

> Despite making repeated arguments for "soft binding", I'm pretty sure I
> haven't outlined here what it actually would *be*. Now that we're looking
> to add syntactic forms that create bound function objects (arrows and class
> methods), perhaps it's time to get consensus for or against. Soft binding
> has 2 properties that make it desirable:
>
>  * The global contract that methods can have their "this" re-set with
> .call() and .apply() is maintained
>  * Common-case usage avoids the hazards of unbound and mis-appropriated
> "this" contexts. Most commonly, passing a method to a function which takes
> a callback:
>
>     node.addEventListener("click", foo.bar);
>
> The language today has 2 types of functions:
>
>   * unbound: methods for which "this" is not fixed
>   * hard-bound: methods bound by Function.prototype.bind()
>
> Crucially, we have no syntax which creates hard-bound methods which means
> that they're not common (yet). To the extent that they are used, it is
> explicitly through forms like:
>
>     node.addEventListener("click", foo.bar.bind(foo));
>
> Or through libraries:
>
>     dojo.connect(node, "onclick", foo, "bar");
>
> This means that most users of most functions can still use .call() and
> .apply() without apprehension. Functions are still "just functions".
>

That is only true for functions that actually use |this|. Even though bind
is probably not used in force yet because of cross-browser worries, "var
self = this" is used everywhere. Functions using that pattern are no more
usable with call/apply than arrow functions.


>
> The new forms we're adding (methods and arrows) have the potential to
> change this radically, causing a large percentage of functions encountered
> by programmers to have binding. If that binding is hard-binding, .call()
> and .apply() break in the minds of users. Perhaps that's fine by you, but
> in addition to being a contractual failure, it removes a form of
> genericness which is unique in the language.
>

Last I checked, the new method form is still a dynamic binding - otherwise
it wouldn't work. So really, you're just talking about arrow functions. In
the cases where arrow functions make the most sense (callbacks) you rarely
want a dynamic |this| - the oddball case being event handlers primarily.


>
> What to do?
>
> One option is to barrel onward with either unbound functions, hard bound
> functions, or some mix thereof. These are all painful in ways I don't need
> to spend time here explaining. I propose a third alternative: soft binding
> (aka "preferred binding"). It enables the following:
>
>     node.addEventListener("click", foo.bar.prefer(foo));
>
> While still allowing the following:
>
>     foo.bar.call(otherThis, …args);
>
> Functions with preferred bindings can still be re-bound either with new
> preferred binding or with new hard binding (both forms vend new functions
> objects and they do today).
>
> Here's a JSFiddle with an a quick ES5 desugaring + example:
>
>      http://jsfiddle.net/slightlyoff/739CS/20/
>
> Note that we need to re-define .call() and .apply() to be savvy to
> preferences, but this doesn't seem particularly painful. I've bluntly
> worked around it in this example to avoid __proto__ re-wiring.
>
> Thoughts?
>

When I enumerate the use cases, I have trouble finding a *good* reason for
soft-binding. You are correct that it removes a certain amount of
genericness to use hard-binding, but I think writing a generic function
should be intentional.

    function foo(bar){
        bar.call(otherThis);
    }

If you write a function foo that expects a function parameter bar, and you
intend to override it's this value, that is a contract, and the |this| you
substitute also needs to abide by the contract for use inside of the bar
function. Traditionally, this would be done using a *parameter* to bar,
instead of changing |this| which seems fragile at best. The only use case I
see for changing |this| is if the function bar passed in is already an
existing method.

    //For this use case, why would I ever use an arrow function
    foo( ()=>this.myBar() );

    //instead of just passing the method directly
    foo( this.myBar );

I really just don't see the value of changing the |this| value of a
function created for the purpose of being an argument to a function. And
frankly, I just don't see many other use cases for arrows. Maybe thats the
part I'm missing.

- Russ


>
> --
> Alex Russell
> slightlyoff at google.com
> slightlyoff at chromium.org
> alex at dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120423/9a8a033c/attachment.html>


More information about the es-discuss mailing list