On Mon, Apr 23, 2012 at 6:53 AM, Alex Russell <a...@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 > slightly...@google.com > slightly...@chromium.org > a...@dojotoolkit.org BE03 E88D EABB 2116 CC49 8259 CF78 E242 59C3 9723 > > _______________________________________________ > es-discuss mailing list > es-discuss@mozilla.org > https://mail.mozilla.org/listinfo/es-discuss >
_______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss