On Mon, Apr 23, 2012 at 2:47 PM, Russell Leggett <russell.legg...@gmail.com> wrote: > > > 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.
"everywhere" is incredibly strong wording, and I think that in the large, you're probably not correct. Some large % of code might manually "call their scope" through closure binding, but even that isn't an argument against soft binding. >> 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. Having done this dance a couple of times, let me suggest to you that the method form will *eventually* end up at a per-class getter on the prototype which vends an instance function which is bound. People will (reasonably) want binding of some sort. >> 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. Yeah, I think you're missing the composition arguments. If I create mixins with methods, they're going to have a promiscuious "this" as a *feature*. You might not write code like this today, but you probably should ;-) _______________________________________________ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss