Re: Bound instance-function vending (was RE: Arrow binding)
A bit on Object.extend(obj,{...}) vs. obj.{...} To get started, just a reminder that we can't really compare the two based on the assumption that the second argument to extend is an object literal as there is no way to syntactically guarantee that. We have to assume that both arguments to Object.extend are preexisting object that were created in some arbitrary manner. EG, we are have to compare Object.extend(obj1, obj2) vs. obj1.{...} On Apr 29, 2012, at 10:10 AM, Axel Rauschmayer wrote: ... Object.extend would automatically invoke Object.defineMethod() (or similar) for you, to enable super-references (but I doubt there is much use for them in mixins). Mixin's and inheritance (including) super references are orthogonal concepts. Some may choose to use only one or the other but they really need to be composable for for those who need to use them in combination. The defineMethod point is important. Equally important is the treatment of private named properties. To correctly preserve super invocation semantics methods must be processed using Object.defineMethod when they are copied from obj2 to obj1. For obj1.{...} this isn't a problem because the extension object and its properties don't preexist. They are just syntax that is processed just like creating completely new properties on obj1 and the semantic rules for those new properties are exactly the same as those that would have been used in an object literal that was providing the initial definition of obj1. There is no copying semantics of worry about. One of the syntactic distinctions that is made by obj1.{...} is the difference between a method property and a function valued state property. Consider: //somewhere else in the program vender.getSomeCallback = function(a,b) { let cb= function() {...myWeakMap.get(cb).attachment...this.something(a,b)}; myWeakMap.set(cb, generateAttachment(a,b)); return cb; } //main example obj1.{ callback: vender.getSomeCallback(x,y), meth() { super.meth(); this.callback.call(this.target); } Note that .{ sees the callback property as a regular state property and doesn't use defineMethod semantics to create it on obj1. The value returned by vender.getSomeCallback is directly used as the value of the callback state property and the identify based annotation mechanism used in the definition of the callback will work just fine. meth, because it is expressed using concise method syntax is processed as a new method definition that is super bound as if by defineMethod to obj1. Now consider using extend: let obj2 = { callback: vender.getSomeCallback(x,y), meth() { super.meth(); this.callback.call(this.target); }; Object.extend(obj1,obj2); Object.extend doesn't have any visibility of how the properties of obj2 were defined. All it sees is two data properties whose values are functions. It if used Object.defineProperty to process both properties then methwould be super bound to the wrong object. If it used Object.defineMethod on both properties then the callback function's identify may change. What Object.extend will have to do is have a heuristic (if the value is super bound to obj2, then defineMethod it to obj1. Otherwise, just use defineProperty) that it applies to function valued data properties. This heuristic should be adequate for uses that correspond to what could be expressed using .{ but it also allows other cases where the heuristic may produce something other than the desired result. Those situations simply don't exist for .{ Use of private names with Object.extend is even more problematic. Consider something like: let MixinArrayIterator = (obj) = obj.{ @iterator() { let coll = this; return function*() {...yield coll[...} } } which uses the built-in @iterator private name. This works nicely with .{ because the private name is used within the .{ special form and doesn't require any runtime reflection on the mixin object. However, to do the same with Object.extend would requires that extend has reflective visibility of actual private named properties of obj2. The reflection restrictions on private names exists to support various high-integrity use cases. In this particular situation, there is nothing actually private in the hight-integrity sense about @iterator. To make this all work with extend we would probably have to re-introduce the concept of unique names which are like private names but without the reflection restrictions. That then would introduces additional complexities. It is probably possible to support mixin attachment using a functional form (Object.extend) rather than using a special form (.{} ) but there is a lot more to it than just a simply syntactic substitutions. Allen ___ es-discuss mailing list es-discuss@mozilla.org
Re: Bound instance-function vending (was RE: Arrow binding)
Axel Rauschmayer wrote: I am not saying that the transition from the old rules to the new rules will be entirely painless, but if the new rules are simple, that pain is worth it, IMHO. There are no new rules. Some functions ignore |this| or bind it rather than using it. These differences in kind do not change due to arrows. Library code might need to go to extra lengths to help normal developers with the transition (error messages, different behavior, tool functions, etc.) and – to be explicit – might need a predicate such as `isArrowFunction` (which should only ever be used under the hood and thus would not increase confusion for library*users*). There's no point in such a misnamed predicate. Today we have functions that ignore or bind |this|, as well as those that use |this| passed by the caller. Code requires and assumes one kind or another and does not test (and most programmers wouldn't cover all cases, and shouldn't have to). Part of an API, an essential part of the contract, is any function parameter's |this| binding. Arrows make it easier to use callbacks wanting lexical |this| or not using |this| at all. This covers a large cohort. Code invoking the arrow is not going to test well or at all and do something helpful, or unhelpful such as throwing an exception. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
With “rules”, I don’t mean rules in the sense of the language spec, but rather rules for teaching the language to newcomers. On Apr 29, 2012, at 10:28 , Brendan Eich wrote: Axel Rauschmayer wrote: I am not saying that the transition from the old rules to the new rules will be entirely painless, but if the new rules are simple, that pain is worth it, IMHO. There are no new rules. Some functions ignore |this| or bind it rather than using it. These differences in kind do not change due to arrows. Library code might need to go to extra lengths to help normal developers with the transition (error messages, different behavior, tool functions, etc.) and – to be explicit – might need a predicate such as `isArrowFunction` (which should only ever be used under the hood and thus would not increase confusion for library*users*). There's no point in such a misnamed predicate. Today we have functions that ignore or bind |this|, as well as those that use |this| passed by the caller. Code requires and assumes one kind or another and does not test (and most programmers wouldn't cover all cases, and shouldn't have to). Part of an API, an essential part of the contract, is any function parameter's |this| binding. Arrows make it easier to use callbacks wanting lexical |this| or not using |this| at all. This covers a large cohort. Code invoking the arrow is not going to test well or at all and do something helpful, or unhelpful such as throwing an exception. /be -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
On Apr 28, 2012, at 22:24, Axel Rauschmayer a...@rauschma.de wrote: The following two rules should be everything one has to know regarding callable entities, in ES.next: 1. Method: `this` is an implicit parameter = use a method definition. 2. Non-method function: `this` is not an implicit parameter = use an arrow function. In this light, I’d rewrite Kevin’s code slightly, because, conceptually, `localStorage ` is a non-method function: const localStorage = (obj) = { Object.extend(obj, { If I understand correctly, this approach negates the need for a mixin function entirely - localStorage could just be an old style mixin hash. But either way this tosses out the benefits I get from functional mixins. By invoking the mixin instead of copying it I can a) customize it's behavior by passing it arguments b) have the mixin add advice (before, after, around) to functions of the target object. I think Angus’ most important point is this: Yes, people get confused by this binding; even though it is not hard to learn the rules, and I know them very well, I still trip over them sometimes. But unless we are going to introduce a hella strict mode that reverts all previous rules of |this| binding, yet another rule will just add to the morass. It would be my hope that we can replace all previous rules with the two rules above. `apply` will mostly be replaced by the spread operator, `call` will mostly be replaced by calling a value. Some code such as `forEach` implementations that previously needed to use `call` to simulate lexical scoping don’t need a `thisValue` parameter for array functions. I admire the vision but in reality the boundary between ES5 and ES6 will be messy and drawn out - there will be no clear cut switching point. Legacy code must live alongside the new vision. Without a new strict mode which banishes much of the old spec (and kills my functional mixins) I'm finding it hard not to picture chaos. (and how do you shim = anyway?) ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
On Apr 29, 2012, at 1:28, Brendan Eich bren...@mozilla.org wrote: Axel Rauschmayer wrote: I am not saying that the transition from the old rules to the new rules will be entirely painless, but if the new rules are simple, that pain is worth it, IMHO. There are no new rules. Some functions ignore |this| or bind it rather than using it. These differences in kind do not change due to arrows. Is there lexical |this| binding in ES5? Angus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
If I understand correctly, this approach negates the need for a mixin function entirely - localStorage could just be an old style mixin hash. But either way this tosses out the benefits I get from functional mixins. By invoking the mixin instead of copying it I can a) customize it's behavior by passing it arguments b) have the mixin add advice (before, after, around) to functions of the target object. For me, conceptually, localStorage() is a non-method function that has a single parameter. I don’t think the capabilities are impaired if you change each occurrence of: this.foo = function (...} {...}; to Object.extend(obj, { ... foo(...) { ... }, ... }); Object.extend would automatically invoke Object.defineMethod() (or similar) for you, to enable super-references (but I doubt there is much use for them in mixins). Admittedly, if there is only a single method then there is a lot of unnecessary syntactic noise. However, methods tend to appear in groups (implementing protocols). Putting such groups in object literals makes much sense. As an aside: If you want to annotate methods then function expressions are indeed a plus, because they can be immediately invoked. Python has method decorators for this [1]. myExtend(obj, { someMethod: function (inner, arg) { doSomething(); var result = inner(arg); result++; return result }.around() }); A bit hacky, but nicely declarative. Function.prototype.around() would tag the method, later post-processing would perform the transformation. [1] http://www.python.org/dev/peps/pep-0318/ It would be my hope that we can replace all previous rules with the two rules above. `apply` will mostly be replaced by the spread operator, `call` will mostly be replaced by calling a value. Some code such as `forEach` implementations that previously needed to use `call` to simulate lexical scoping don’t need a `thisValue` parameter for array functions. I admire the vision but in reality the boundary between ES5 and ES6 will be messy and drawn out - there will be no clear cut switching point. Legacy code must live alongside the new vision. Without a new strict mode which banishes much of the old spec (and kills my functional mixins) I'm finding it hard not to picture chaos. (and how do you shim = anyway?) Right. I think you can still tell a simple story to beginners while supporting thin arrow or (this, ...) = {} for legacy software. But I’d hope that the old code can be cleanly separated and that a new coding style will be supported by static checking tools such as JSLint. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
1- Yes, several time that you mention it, and ++ from me each time 2- I prefer the dot notation rather than Object.extend, even if both are good Le 28/04/2012 20:49, Kevin Smith a écrit : Hi Angus! 1) Kevin et al suggested YAGN call/apply on (non-method) functions. Here's a pretty neat example where call/apply is a perfect fit for standalone functions - and would break if replaced with fat arrows. https://gist.github.com/2520731 This is a great example. Two points: 1.) In this case, I think it's going to be pretty difficult to prove that a dynamic this arrow function would be any more readable or better than current syntax: // On what basis is this: this.initialize = () - { ... }; // any better than this? this.initialize = function() { ... }; There are a couple of characters saved, but it's less readable. Why introduce new syntax for such dubious gain? 2.) For mixin stuff like your example, I think the elegant solution is object literal extension syntax: https://gist.github.com/2521128 I'm not sure of the status of that syntax, but hopefully it will get included in ES6. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- jCore Email : avi...@jcore.fr Web :www.jcore.fr Webble : www.webble.it Extract Widget Mobile : www.extractwidget.com BlimpMe! : www.blimpme.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
If so then there is no need for any isArrowFunction or isFunctionThatBindsOrIgnoresThis predicate. /be Axel Rauschmayer wrote: With “rules”, I don’t mean rules in the sense of the language spec, but rather rules for teaching the language to newcomers. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Angus Croll wrote: On Apr 29, 2012, at 1:28, Brendan Eichbren...@mozilla.org wrote: Axel Rauschmayer wrote: I am not saying that the transition from the old rules to the new rules will be entirely painless, but if the new rules are simple, that pain is worth it, IMHO. There are no new rules. Some functions ignore |this| or bind it rather than using it. These differences in kind do not change due to arrows. Is there lexical |this| binding in ES5? The only relevant issue for my exchange with Axel was whether any kind of this-binding exists in ES5 or older. The answer is yes. Lexical this is often wanted and of course simulated with var self = this; ... function (){...self...} or .bind (implementable in pure ES3). But the lexical part doesn't enter into the contract of the API taking the function argument. It's between the API caller and the function argument's implementation -- when the latter is a closure in the former, lexical |this| often wins. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Brendan Eich wrote: But the lexical part doesn't enter into the contract of the API taking the function argument. It's between the API caller and the function argument's implementation -- when the latter is a closure in the former, lexical |this| often wins. What does enter into the contract of the API taking the function argument is whether |this| is dynamically bound and passed with the expectation that the funarg not use some other |this|. But even then, the funarg is free to ignore |this|. Between lexical-this and no-this, Kevin's analysis shows 80-90% (high end helped by method definition shorthand) coverage. Thinking about arrows as a new thing to teach is fine, but we should not teach myths. |this| binding in JS today requires careful thought in all the usual scenarios: constructor, method, callback, global or local function. You can see why some advocate no-this uber alles! But lexical-this is (if memory serves) around 40-50% gross of the 80-90% Kevin studied. That's big and we know people get that wrong. If there's a strong use-case for - as function shorthand, we should consider adding - too. But the use-cases don't look strong enough yet, at least not to me (and I'm sympathetic!) to go back to TC39 asking for - on top of =. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Then I guess we need another survey. What does the JS arrow function proposal mean to you? a) An abbreviated function syntax b) A hard bound lexical |this| binding c) Nothing I'd gladly be proved wrong but my guess is most JS developers who don't answer (c) will answer (a). (I see plenty of supporting evidence on Twitter). Thin arrow would be an excellent decoy for those who expect (or want) just (a). This is also in response to Kevin's suggestion that arrow syntax is barely more concise than regular function syntax. I don't think that's the perception in the wider dev community, neither is it mine (in the best case we save four ways - no function keyword, no braces, no argument parens, no return stmt). Personally I expect I can get by using function keyword where using = will break my idioms - but its a bit much to expect everyone to understand and react to these subtleties. I guess I'm trying to anticipate future cowpaths and pave them before they make too much mess. On Sun, Apr 29, 2012 at 11:37 AM, Brendan Eich bren...@mozilla.org wrote: Brendan Eich wrote: But the lexical part doesn't enter into the contract of the API taking the function argument. It's between the API caller and the function argument's implementation -- when the latter is a closure in the former, lexical |this| often wins. What does enter into the contract of the API taking the function argument is whether |this| is dynamically bound and passed with the expectation that the funarg not use some other |this|. But even then, the funarg is free to ignore |this|. Between lexical-this and no-this, Kevin's analysis shows 80-90% (high end helped by method definition shorthand) coverage. Thinking about arrows as a new thing to teach is fine, but we should not teach myths. |this| binding in JS today requires careful thought in all the usual scenarios: constructor, method, callback, global or local function. You can see why some advocate no-this uber alles! But lexical-this is (if memory serves) around 40-50% gross of the 80-90% Kevin studied. That's big and we know people get that wrong. If there's a strong use-case for - as function shorthand, we should consider adding - too. But the use-cases don't look strong enough yet, at least not to me (and I'm sympathetic!) to go back to TC39 asking for - on top of =. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Use case: error checks. For example: forEach could complain if it got both an arrow function and a thisValue. One could also complain if one expected a function with dynamic/unbound `this` and got a function with bound `this`, instead. To be extra strict, one could even complain when an unbound function is provided where a non-method function is expected (because either an arrow function should be used or a method’s `this` should be bound). All of these are things that you do as an API implementer, not necessarily as an API user. Static checking would be even better, but then we would need a way to declare whether an argument is expected to have dynamic or lexical this. Possibly On Apr 29, 2012, at 20:01 , Brendan Eich wrote: If so then there is no need for any isArrowFunction or isFunctionThatBindsOrIgnoresThis predicate. /be Axel Rauschmayer wrote: With “rules”, I don’t mean rules in the sense of the language spec, but rather rules for teaching the language to newcomers. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Angus Croll wrote: Then I guess we need another survey. What was the first survey? Kevin's analysis was on code, using a tool to classify functions as no-this/lexical-this vs. the rest. What does the JS arrow function proposal mean to you? a) An abbreviated function syntax b) A hard bound lexical |this| binding c) Nothing This is all subjective and (without implementations to user-test) prospective. A survey is not going to be helpful IMHO. Rorschach test... I'd gladly be proved wrong but my guess is most JS developers who don't answer (c) will answer (a). (I see plenty of supporting evidence on Twitter). Thin arrow would be an excellent decoy for those who expect (or want) just (a). What do you mean by decoy? This is all kind of twitter-ific, and so pretty much useless. This is also in response to Kevin's suggestion that arrow syntaxis barely more concise than regular function syntax. I don't think that's the perception in the wider dev community, neither is it mine (in the best case we save four ways - no function keyword, no braces, no argument parens, no return stmt). You mean where Kevin wrote: // On what basis is this: this.initialize = () - { ... }; // any better than this? this.initialize = function() { ... }; There are a couple of characters saved, but it's less readable. Why introduce new syntax for such dubious gain? with a space before the - and one before { in both alternatives, and with the parameter list costing the same no matter what, there are five characters saved (' -' vs. 'function'). Five is good, I like it (I like thin arrows and proposed them along with fat arrows initially). But if this use-case is rare enough due to = and method definition shorthand (combined with Object.extend or better where possible), it may not be worth the added cost of -. What's the cost of adding -? Mainly users having to remember when to use which, and getting it wrong. That's not a trivial concern, and it kept - out of consensus at the last TC39 meeting. Personally I expect I can get by using function keyword where using = will break my idioms - but its a bit much to expect everyone to understand and react to these subtleties. I guess I'm trying to anticipate future cowpaths and pave them before they make too much mess. Doing nothing leaves the cows falling off the wrong-this cliff. Doing something means adding syntax, there's no way to make a breaking change. Adding two things instead of one makes not only two things, but the problem of choice. We may get - yet, don't get me wrong. But it won't come from surveys or twitter samples. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Axel Rauschmayer wrote: Use case: error checks. For example: forEach could complain if it got both an arrow function and a thisValue. Do you mean error, or warning? Because you can use forEach with a function that ignores its |this|, and pass the thisValue optional parameter too, without error today. I see no good coming from trying to add an arrow-only error in the future when this case is not an error. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
I'm sorry that I could not reply to the multiple replies I got last weekend. Simply can't get the time - plus I have a phobia of fan-out replies (an issue with mail-based discussion groups?) In any case here's a potted reply that addresses at least some of the points: 1) Kevin et al suggested YAGN call/apply on (non-method) functions. Here's a pretty neat example where call/apply is a perfect fit for standalone functions - and would break if replaced with fat arrows. https://gist.github.com/2520731 It's a simplified version of a a localStorage function (itself a mixin BTW) which defines standard encoding methods and then mixes in whatever storage technique is available to the browser. (An added bonus of having functions here, aside from privacy, is that we can employ hoisting to move the implementation nitty-gritty to the bottom, so as not to obscure the core process) 2) Brendan et al pointed out that we already have hard |this| binding in the form of Function::bind. Yes, but bind is so blatantly explicit in its intention, the probability of surprise is almost certainly less than with arrow functions, whose hard lexical binding will surely come as a surprising side effect to many. 3) Several people suggested that there is a strong desire for a more intuitive form of |this| binding. Yes, people get confused by this binding; even though it is not hard to learn the rules, and I know them very well, I still trip over them sometimes. But unless we are going to introduce a hella strict mode that reverts all previous rules of |this| binding, yet another rule will just add to the morass. Most of the yay, fat arrow comments I've seen from the dev community are celebrating its brevity, I expect many of the authors have zero knowledge of the lexical binding implications (why would they, unless they came from CoffeeScript?). Now matter how much we justify fat arrow behavior as part of a long term vision, to many it is going to be a hidden, and unwanted side effect. At least introduce thin arrow at the same time, as a carrot to lure who just want (and just expect) an abbreviated function syntax. On Mon, Apr 23, 2012 at 3:01 PM, Brendan Eich bren...@mozilla.org wrote: Brendan Eich wrote: No, in any such prototype-getter-makes-bound-**function scenario, we would need memoization, so that o.m === o.m (Edit: I see you mention this below.) The real problem is better captured by showing the prototype p and two instances, o and q: p.m === p.m should be true. So should o.m === o.m and q.m === q.m but what about o.m === p.m and o.m === q.m JS requires distinct bound function identity from the unbound p.m identity, so false and false. If we managed to extend JS with a classy declarative syntax that enabled vtables, while keeping functions first class (at the price of prototype-chain mutation: assignment to override, or shadow; also of course delete), then we might well want true and true. But there would be no way in JS itself to implement such magic in terms of properties (data or accessor, doesn't matter) with function values. This is why I continue to think that we won't see what Alex predicted: prototype getter method vending. We haven't see it much in the wild yet either. /be __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Hi Angus! 1) Kevin et al suggested YAGN call/apply on (non-method) functions. Here's a pretty neat example where call/apply is a perfect fit for standalone functions - and would break if replaced with fat arrows. https://gist.github.com/2520731 This is a great example. Two points: 1.) In this case, I think it's going to be pretty difficult to prove that a dynamic this arrow function would be any more readable or better than current syntax: // On what basis is this: this.initialize = () - { ... }; // any better than this? this.initialize = function() { ... }; There are a couple of characters saved, but it's less readable. Why introduce new syntax for such dubious gain? 2.) For mixin stuff like your example, I think the elegant solution is object literal extension syntax: https://gist.github.com/2521128 I'm not sure of the status of that syntax, but hopefully it will get included in ES6. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Kevin Smith wrote: 2.) For mixin stuff like your example, I think the elegant solution is object literal extension syntax: https://gist.github.com/2521128 I'm not sure of the status of that syntax, but hopefully it will get included in ES6. What if the ES6 solution were a standardized Object.extend, instead? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
What if the ES6 solution were a standardized Object.extend, instead? https://gist.github.com/2523106 (Assuming the same semantics...) It's a little more wordy but still looks pretty good to me for this use case. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
On Sat, Apr 28, 2012 at 11:13 AM, Angus Croll anguscr...@gmail.com wrote: 1) Kevin et al suggested YAGN call/apply on (non-method) functions. Here's a pretty neat example where call/apply is a perfect fit for standalone functions - and would break if replaced with fat arrows. https://gist.github.com/2520731 It's a simplified version of a a localStorage function (itself a mixin BTW) which defines standard encoding methods and then mixes in whatever storage technique is available to the browser. (An added bonus of having functions here, aside from privacy, is that we can employ hoisting to move the implementation nitty-gritty to the bottom, so as not to obscure the core process) This is a mixin, which means that it needs methods, not functions. Fat arrows aren't meant for methods. This should rightly use 'function' (which is meant for methods), or eventually use a mixin syntax. (We should keep this in mind as an example of mixins, so we don't accidentally forbid the ability to choose which mixin to use dynamically, like this does.) ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Tab Atkins Jr. wrote: This should rightly use 'function' (which is meant for methods), or eventually use a mixin syntax. See the version Kevin did using Object.extend and method definition shorthand: https://gist.github.com/2523106 /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
The following two rules should be everything one has to know regarding callable entities, in ES.next: 1. Method: `this` is an implicit parameter = use a method definition. 2. Non-method function: `this` is not an implicit parameter = use an arrow function. In this light, I’d rewrite Kevin’s code slightly, because, conceptually, `localStorage ` is a non-method function: const localStorage = (obj) = { Object.extend(obj, { I think Angus’ most important point is this: Yes, people get confused by this binding; even though it is not hard to learn the rules, and I know them very well, I still trip over them sometimes. But unless we are going to introduce a hella strict mode that reverts all previous rules of |this| binding, yet another rule will just add to the morass. It would be my hope that we can replace all previous rules with the two rules above. `apply` will mostly be replaced by the spread operator, `call` will mostly be replaced by calling a value. Some code such as `forEach` implementations that previously needed to use `call` to simulate lexical scoping don’t need a `thisValue` parameter for array functions. Then the question remains: What else is possibly confusing? Using function* as a name for generators might be problematic. Most of the yay, fat arrow comments I've seen from the dev community are celebrating its brevity, I expect many of the authors have zero knowledge of the lexical binding implications (why would they, unless they came from CoffeeScript?). Now matter how much we justify fat arrow behavior as part of a long term vision, to many it is going to be a hidden, and unwanted side effect. True. I would ague that partitioning callable entities into the two categories mentioned at the beginning is natural and will allow you to forget about binding rules. I am not saying that the transition from the old rules to the new rules will be entirely painless, but if the new rules are simple, that pain is worth it, IMHO. Library code might need to go to extra lengths to help normal developers with the transition (error messages, different behavior, tool functions, etc.) and – to be explicit – might need a predicate such as `isArrowFunction` (which should only ever be used under the hood and thus would not increase confusion for library *users*). -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Correction: Some code such as `forEach` implementations that previously needed to use `call` to simulate lexical scoping don’t need the `thisValue` parameter for arrow [was: array] functions. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Mon, Apr 23, 2012 at 3:36 PM, David Herman dher...@mozilla.com wrote: I'm much more sympathetic to the idea of having *two* shorter-function syntaxes, one optimized for methods and one optimized for non-method functions. I understand the concern about bloat, but to me it addresses the reality of different contexts in programming, e.g.: a.map(x = x + 1) vs box = { _value: 0, get: () - this._value, set(v) { this._value = v } } I don't understand this example. What is set(v) {...}? It's not a setter, because it's not associated with a property name. Assuming you meant set value(v) {...}, why not just use an ordinary getter as well? ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Tue, Apr 24, 2012 at 12:33 PM, Tab Atkins Jr. jackalm...@gmail.comwrote: On Mon, Apr 23, 2012 at 3:36 PM, David Herman dher...@mozilla.com wrote: I'm much more sympathetic to the idea of having *two* shorter-function syntaxes, one optimized for methods and one optimized for non-method functions. I understand the concern about bloat, but to me it addresses the reality of different contexts in programming, e.g.: a.map(x = x + 1) vs box = { _value: 0, get: () - this._value, set(v) { this._value = v } } I don't understand this example. What is set(v) {...}? It's not a setter, because it's not associated with a property name. Assuming you meant set value(v) {...}, why not just use an ordinary getter as well? When I read this, I assumed it was a reference to this: http://wiki.ecmascript.org/doku.php?id=harmony:object_literals#object_literal_property_shorthands Which would produce a method named set on box box.set(42) box.get() 42 The example is easily confused. Hope that helps Rick ~TJ ___ 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
Re: Arrow binding
Seems like a typo and Tab’s got it right. The advantage of a thin arrow (over a method definition) here is that you can do an implicit return and have slightly less to type. Given that method definitions don’t appear inside statements, I don’t see that as a problem. AFAIK, an implicit return of the completion value of a method is out, because one might involuntary return wrong values (previously: undefined, now: completion value). On Apr 24, 2012, at 18:51 , Rick Waldron wrote: On Tue, Apr 24, 2012 at 12:33 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Mon, Apr 23, 2012 at 3:36 PM, David Herman dher...@mozilla.com wrote: I'm much more sympathetic to the idea of having *two* shorter-function syntaxes, one optimized for methods and one optimized for non-method functions. I understand the concern about bloat, but to me it addresses the reality of different contexts in programming, e.g.: a.map(x = x + 1) vs box = { _value: 0, get: () - this._value, set(v) { this._value = v } } I don't understand this example. What is set(v) {...}? It's not a setter, because it's not associated with a property name. Assuming you meant set value(v) {...}, why not just use an ordinary getter as well? When I read this, I assumed it was a reference to this: http://wiki.ecmascript.org/doku.php?id=harmony:object_literals#object_literal_property_shorthands Which would produce a method named set on box box.set(42) box.get() 42 The example is easily confused. Hope that helps Rick ~TJ ___ 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 -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Tue, Apr 24, 2012 at 9:51 AM, Rick Waldron waldron.r...@gmail.com wrote: When I read this, I assumed it was a reference to this: http://wiki.ecmascript.org/doku.php?id=harmony:object_literals#object_literal_property_shorthands Which would produce a method named set on box box.set(42) box.get() 42 The example is easily confused. Ah, that makes sense. Okay. In that case, I don't see why one wouldn't just use the same syntax for both methods: let box = { _value: 0, get() { return this._value; }, set(v) { this._value = v; } }; There doesn't seem to be a need there for thin-arrow (dynamic this) functions. (Edit: Oh, I see, leaning on the completion value of thin-arrow functions here lets you shave a few characters off. The readability loss of mixing the two syntaxes doesn't seem worthwhile, though.) In fact, we can enumerate the different situations functions can appear, since they're all gaining nice syntax: 1. Method on a class - when we get max/min classes, these'll have a nice syntax, and will have dynamic-this behavior, just what we want. 2. Method on an object literal - if we have the syntax extension outlined above, you also get dynamic-this, which we want. 3. Method dynamically attached to an object - here we don't have special syntax, so we'll still need to use the function keyword. 4. Non-method function - you don't want a dynamic this, you want to lexically close over all your variables. Fat-arrows do this for you. (The only reason to want dynamic this on a non-method is to do a poor-man's currying. Get a real curry function; this isn't worth the bugs.) The only case that isn't receiving special syntax (and thus which could potentially benefit from a dynamic-this thin-arrow function) is #3. However, while #3 is common today, #1 and #2 will eat most of its share. I'm not sure that the remaining #3 cases will be worth a special syntax. If they are, though, nothing's closing the door on a thin-arrow in the future. No reason to block fat-arrow based on this. ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Tue, Apr 24, 2012 at 1:03 PM, Tab Atkins Jr. jackalm...@gmail.comwrote: On Tue, Apr 24, 2012 at 9:51 AM, Rick Waldron waldron.r...@gmail.com wrote: When I read this, I assumed it was a reference to this: http://wiki.ecmascript.org/doku.php?id=harmony:object_literals#object_literal_property_shorthands Which would produce a method named set on box box.set(42) box.get() 42 The example is easily confused. Ah, that makes sense. Okay. In that case, I don't see why one wouldn't just use the same syntax for both methods: let box = { _value: 0, get() { return this._value; }, set(v) { this._value = v; } }; There doesn't seem to be a need there for thin-arrow (dynamic this) functions. I think the colon was just a typo Rick [snip] ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
3. Method dynamically attached to an object - here we don't have special syntax, so we'll still need to use the function keyword. Not necessarily. Object literal extensions are a possibility here, especially if you are attaching more than one method: obj.{ addMethodA() { ... }, addMethodB() { ... } }; kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
Rick Waldron wrote: I think the colon was just a typo Dave is not cc'ed and may have missed the responses going back to Tab's first one, but I think there was no typo. Dave's example: box = { _value: 0, get: () - this._value, set(v) { this._value = v } } Yes, it's awkward as examples go because get and set are contextual keywords, but this shows them used as plain identifiers. This also shows - as property value in an object literal (for property name 'get'), well as method definition shorthand (for 'set'), to contrast the two styles. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
Tab Atkins Jr. wrote: The only case that isn't receiving special syntax (and thus which could potentially benefit from a dynamic-this thin-arrow function) is #3. However, while #3 is commontoday, #1 and #2 will eat most of its share. I'm not sure that the remaining #3 cases will be worth a special syntax. If they are, though, nothing's closing the door on a thin-arrow in the future. No reason to block fat-arrow based on this. Nicely put and I agree -- but I'm open to the future being sooner than we think. Getting = past TC39 took some doing, don't want to break consensus over pushing -. Do want to get to - if the use-cases from the field are strong enough. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Tue, Apr 24, 2012 at 4:21 PM, Brendan Eich bren...@mozilla.org wrote: Rick Waldron wrote: I think the colon was just a typo Dave is not cc'ed and may have missed the responses going back to Tab's first one, but I think there was no typo. Dave's example: box = { _value: 0, get: () - this._value, set(v) { this._value = v } } Yes, it's awkward as examples go because get and set are contextual keywords, but this shows them used as plain identifiers. This also shows - as property value in an object literal (for property name 'get'), well as method definition shorthand (for 'set'), to contrast the two styles. This makes complete sense now, thank you for the clarification. Rick /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 9:51 AM, Rick Waldron wrote: On Tue, Apr 24, 2012 at 12:33 PM, Tab Atkins Jr. jackalm...@gmail.com wrote: On Mon, Apr 23, 2012 at 3:36 PM, David Herman dher...@mozilla.com wrote: box = { _value: 0, get: () - this._value, set(v) { this._value = v } } I don't understand this example. What is set(v) {...}? It's not a setter, because it's not associated with a property name. Assuming you meant set value(v) {...}, why not just use an ordinary getter as well? When I read this, I assumed it was a reference to this: http://wiki.ecmascript.org/doku.php?id=harmony:object_literals#object_literal_property_shorthands Right. Thanks for providing the reference. Which would produce a method named set on box box.set(42) box.get() 42 The example is easily confused. Yeah, my bad. I was trying to demonstrate several syntaxes but shouldn't've picked an example with a method named set. To clarify the example: box = { _value: 0, unbox: () - this._value, setbox(v) { this._value = v } } Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 10:03 AM, Tab Atkins Jr. wrote: There doesn't seem to be a need there for thin-arrow (dynamic this) functions. (Edit: Oh, I see, leaning on the completion value of thin-arrow functions here lets you shave a few characters off. The readability loss of mixing the two syntaxes doesn't seem worthwhile, though.) Lets you eliminate { and } and return, but requires additional : and -. Net savings of 3 characters. But more than that, eliminating return lets you write methods in a functional style without needing the explicit control flow operator. The only case that isn't receiving special syntax (and thus which could potentially benefit from a dynamic-this thin-arrow function) is #3. However, while #3 is common today, #1 and #2 will eat most of its share. I'm not sure that the remaining #3 cases will be worth a special syntax. Classes certainly make it less necessary, given that cases like: C.prototype.m1 = function(...) { ... }; C.prototype.m2 = function(...) { ... }; C.prototype.m3 = function(...) { ... }; will often be replaced by classes. But I am less sure it'll go away. If they are, though, nothing's closing the door on a thin-arrow in the future. No reason to block fat-arrow based on this. I'm definitely not advocating blocking fat-arrow! I favor both of them, though IMO fat-arrow is more important. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 1:40 PM, David Herman wrote: On Apr 24, 2012, at 10:03 AM, Tab Atkins Jr. wrote: There doesn't seem to be a need there for thin-arrow (dynamic this) functions. (Edit: Oh, I see, leaning on the completion value of thin-arrow functions here lets you shave a few characters off. The readability loss of mixing the two syntaxes doesn't seem worthwhile, though.) Lets you eliminate { and } and return, but requires additional : and -. Net savings of 3 characters. But more than that, eliminating return lets you write methods in a functional style without needing the explicit control flow operator. I believe that we could grammatically use ArrowBody as the body of concise methods in object literals and classes. In that case, Dave's example could be expressed as: box = { _value: 0, unbox() ()- this._value, setbox(v) this._value = v } It could also be used as the body of getter/setters val = { _value: 0, get value() this._value, set value(v) this._value = v } Allen___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
I believe that we could grammatically use ArrowBody as the body of concise methods in object literals and classes. In that case, Dave's example could be expressed as: box = { _value: 0, unbox() ()- this._value, setbox(v) this._value = v } That would be very nice. And it would be a perfect solution for the completion value issue: If you want to implicitly return the completion value, use an expression body. Is there a typo in the code? I’d expect it to be: box = { _value: 0, unbox() this._value, setbox(v) this._value = v } -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
Allen Wirfs-Brock wrote: unbox() ()- this._value, Left-over ()- in the middle, right? /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 2:09 PM, Allen Wirfs-Brock wrote: On Apr 24, 2012, at 1:40 PM, David Herman wrote: On Apr 24, 2012, at 10:03 AM, Tab Atkins Jr. wrote: There doesn't seem to be a need there for thin-arrow (dynamic this) functions. (Edit: Oh, I see, leaning on the completion value of thin-arrow functions here lets you shave a few characters off. The readability loss of mixing the two syntaxes doesn't seem worthwhile, though.) Lets you eliminate { and } and return, but requires additional : and -. Net savings of 3 characters. But more than that, eliminating return lets you write methods in a functional style without needing the explicit control flow operator. I believe that we could grammatically use ArrowBody as the body of concise methods in object literals and classes. In that case, Dave's example could be expressed as: box = { _value: 0, unbox() ()- this._value, ITYM: unbox() this._value, setbox(v) this._value = v } It could also be used as the body of getter/setters val = { _value: 0, get value() this._value, set value(v) this._value = v } This all seems reasonable to me. I guess I see a couple reasonable alternatives here: A. add thin arrow, add expression bodies to method shorthands (-) Might be a bit much (+) But all around a goodly set of convenience forms B. add expression bodies to method shorthands, don't add skinny arrow (-) Loses the flexibility of shorthand syntax for assigning to an existing object, a Tab pointed out. (Sorry Axel, mustache is not particularly Harmonious.) (+) Keeps us to just one arrow form C. eliminate method shorthands, add skinny arrow (-) Loses the method shorthand in object literals (-) Methods in classes would remain the same, which loses some symmetry between object literals and classes (+) Eliminates visual confusion between getters/setters and method shorthand, but still with a minimal syntax (i.e., -) All three of these options look pretty decent to me. I think I'd be pretty happy with any of them. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 2:44 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: unbox() ()- this._value, Left-over ()- in the middle, right? yes, that's right. it should be unbox () this.value, I was actually confusing that example with something thunk () () = this._value, Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
B. add expression bodies to method shorthands, don't add skinny arrow (-) Loses the flexibility of shorthand syntax for assigning to an existing object, a Tab pointed out. (Sorry Axel, mustache is not particularly Harmonious.) Sorry to hear that. _.extend(), then (by whichever name)? As long as this operation can be performed in some manner... (+) Keeps us to just one arrow form C. eliminate method shorthands, add skinny arrow (-) Loses the method shorthand in object literals (-) Methods in classes would remain the same, which loses some symmetry between object literals and classes (+) Eliminates visual confusion between getters/setters and method shorthand, but still with a minimal syntax (i.e., -) That would make super-references more difficult to implement, right? You’d have to invoke a defineMethod() somewhere along the way. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 3:30 PM, Axel Rauschmayer wrote: B. add expression bodies to method shorthands, don't add skinny arrow (-) Loses the flexibility of shorthand syntax for assigning to an existing object, a Tab pointed out. (Sorry Axel, mustache is not particularly Harmonious.) Sorry to hear that. _.extend(), then (by whichever name)? As long as this operation can be performed in some manner... or we need to find mustached harmony, perhaps with some slight syntax change. The utility of .{ seems to be showing up fairly frequently in these discussions and also fits quite nicely with max-min classes for both instance and class property definition. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
Using a builtin function (as opposed to an operator) would be less problematic if one could invoke it infix, e.g.: this (extend) { x: x, y: y } But I guess deciding on that will have to wait until operator overloading gets figured out. On Apr 25, 2012, at 0:43 , Allen Wirfs-Brock wrote: On Apr 24, 2012, at 3:30 PM, Axel Rauschmayer wrote: B. add expression bodies to method shorthands, don't add skinny arrow (-) Loses the flexibility of shorthand syntax for assigning to an existing object, a Tab pointed out. (Sorry Axel, mustache is not particularly Harmonious.) Sorry to hear that. _.extend(), then (by whichever name)? As long as this operation can be performed in some manner... or we need to find mustached harmony, perhaps with some slight syntax change. The utility of .{ seems to be showing up fairly frequently in these discussions and also fits quite nicely with max-min classes for both instance and class property definition. Allen -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 24, 2012, at 3:53 PM, Axel Rauschmayer wrote: Using a builtin function (as opposed to an operator) would be less problematic if one could invoke it infix, e.g.: this (extend) { x: x, y: y } That wouldn't address the issues concerning cloning private names, super binding, etc. I believe Dave's main issue is with the exact .{ syntax. I'm flexible if that can be be harmoniously resolved with a minor syntactic change such as: this.={methodA() {}, methodB() {} }; or this.+{methodA() {}, methodB() {} }; or something else this.{methodA() {}, methodB() {} }; Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
I wasn't convinced at first but I think the obj.{ ... } extension syntax provides good utility. I would strongly suggest not giving it up. I've used it in several refactoring examples on this list. And I still don't see the attraction of thin arrow. It provides no semantic benefit and only very arguable syntactic benefit. Object literal methods and arrows eliminate the pain of function syntax for pretty much every place where it is a pain. The ability to eliminate return ... from method bodies is a very dubious benefit; I believe that in the case of methods this will make code less readable. There seems to be a general assumption that arrows are the new function. This comes from CoffeeScript, I suppose, but in my opinion following that route will neither make the language more readable nor expressive. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Arrow binding
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. 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. 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? -- 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
Re: Arrow binding
I'm not sure I understand the reasoning behind soft-binding. If I use arrow syntax, my intention is to close over |this|. Allowing a caller to change the binding of |this| will result in a violation of that closure. In this respect, |this| within an arrow function is no different that any other closed-over variable. I would not want a caller to be able to override the binding on any of those variables, right? kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
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
Re: Arrow binding
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.
Re: Arrow binding
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 ;-) But anyone who understands the language would not use arrow functions for that use case. I assume you're referring to something like this (Angus posted a similar example a while back): function mixin() { this.{ addMethodA() {}, addMethodB() {} }; } Your idea of a preferred binding for methods is interesting (as a form of method extraction), but I don't think it can be applied to arrow functions. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Mon, Apr 23, 2012 at 6:46 AM, Kevin Smith khs4...@gmail.com wrote: I'm not sure I understand the reasoning behind soft-binding. If I use arrow syntax, my intention is to close over |this|. Allowing a caller to change the binding of |this| will result in a violation of that closure. In this respect, |this| within an arrow function is no different that any other closed-over variable. I would not want a caller to be able to override the binding on any of those variables, right? Right. I think this is the key issue regarding defaults and what arrow functions must do -- hard binding. Making this binding soft would destroy the integrity of lexical capture that arrow functions provide for this. Alex, http://wiki.ecmascript.org/doku.php?id=strawman:soft_bind, which we worked on together, implements soft binding as a simple small library. We wrote this over a year ago. Since then, I've never found a need for this. Could you give a concrete example where this is useful? Do such uses justify a role beyond such library implementations? I'm inclined to YAGNI on this one. kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 23, 2012, at 16:17 , Alex Russell wrote: 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. An important use case. However, wouldn’t it be simpler to achieve the same goal by allowing the following two operations to co-exist? - get: obj.method invokes the getter – which hard-binds on demand (but might cache via a weakmap). - call: obj.method() invokes the actual method. Hence, in addition to getters and setters, we would have callers. If a property doesn’t have a caller then obj.method() would first invoke the getter and then try to call the result. -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Mon, Apr 23, 2012 at 3:53 AM, Alex Russell a...@dojotoolkit.org wrote: 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. Sorry if I missed reading about this but: why can't we re-bind 'this in bound functions when using call(), apply() ? I'm sure it will make more work for JIT optimizers but they are very good and love this kind of problem. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
The semantic of Function.prototype.bind() precludes it. If we could relax that to be effectively soft-bound, I'm *completely* on board, but I expect it will cause some problems. We could, of course, try this out in Chrome and see how it goes. On Mon, Apr 23, 2012 at 4:32 PM, John J Barton johnjbar...@johnjbarton.com wrote: On Mon, Apr 23, 2012 at 3:53 AM, Alex Russell a...@dojotoolkit.org wrote: 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. Sorry if I missed reading about this but: why can't we re-bind 'this in bound functions when using call(), apply() ? I'm sure it will make more work for JIT optimizers but they are very good and love this kind of problem. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 23, 2012, at 8:32 AM, John J Barton wrote: On Mon, Apr 23, 2012 at 3:53 AM, Alex Russell a...@dojotoolkit.org wrote: 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. Sorry if I missed reading about this but: why can't we re-bind 'this in bound functions when using call(), apply() ? I'm sure it will make more work for JIT optimizers but they are very good and love this kind of problem. Because the semantics would be difficult to implement -- jit or otherwise -- and difficult to specify otherwise :-( The more serious issue though is that of program behaviour -- if a developer has strongly bound this, it is reasonable to expect that they had some reason to do so. If you provide a mechanism that can bypass that binding you can break program abstraction, potentially allowing security bugs in the SES/Caja type language models. It would also imply being able to rebind |this| in bound functions, which would be insane. --Oliver jjb ___ 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
Re: Arrow binding
On Apr 23, 2012, at 3:30 PM, Russell Leggett wrote: 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. Let me reword from everywhere to extremely common. My point was that even though it is not used in every case, it is used often enough that |this| cannot be relied on. And my other point was that you have to know how the function passed in *uses* this, which makes it pretty tightly coupled. 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. If that happens, then I will be more inclined to agree with you. Until that happens, I guess I just don't. Your argument seems balanced on something which you think will happen. I find that hard to agree with. 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 ;-) I use mixins all the time, I just don't see them being being declared with arrow functions, which was the point I was trying to make here. If you are creating a mixin, then you would most likely want to use the new method syntax or at least the function syntax, but I think it would be silly to use the arrow function syntax, so I guess I'm just not sympathetic to that. If methods on classes sprout binding of some sort, this will be the natural style. And I think that's a good place to be. If both arrow and class methods lexically soft-bind, truly unbound functions will be declared as function and will be easy to spot. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
The real use case that I constantly run into has nothing to do with binding at all, rather the need for Function.prototype.partial and *no specific binding*. The primary use case for soft binding or dynamic non-method binding, as mentioned above, is the event callback and that's weird semantic captured in the way the DOM works. The problem is that with JS it's a prevalent use case because of how closely associated JS has been with the DOM. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
On Apr 23, 2012, at 11:17 AM, Brendan Eich wrote: Apologies for sounding schizo. I'm saying prototypal wins at scale and I see it more often used, but closure has its fans and it's used too. With both (plus other approaches such as Angus's) I do not think it's a given that in the future, JS will make methods auto-bind |this| via prototypal accessors. That is possible today (ES5 and earlier getter/setter support in most browsers) and it's quite rare -- I can think of only a few cases, one of which is in the new I18N library. And note that the I18N usage is for a situation where the property is vending (to use Alex's term) a function that is intended to be used as a call-back that needs access to the state of the instance it was accessed from. In particular, it enables someone to say: someArray.sort(myCollator.compare) rather than someArray.sort(myCollator.compare.bind(myCollator) This seems like an important idiom hat may become even more important in the context of ES6. We probably need to encourage broader education about this idiom. But it isn't clear that it needs special syntax or even what that might be. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Allen Wirfs-Brock wrote: This seems like an important idiomhat may become even more important in the context of ES6. We probably need to encourage broader education about this idiom. But it isn't clear that it needs special syntax or even what that might be. Dave wrote http://wiki.ecmascript.org/doku.php?id=strawman:bind_operator for this and it's a live strawman (albeit in conflict with guard syntax, or perhaps just reusing it outside of binding contexts). Agree it's not ready for ES6, of course. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Bound instance-function vending (was RE: Arrow binding)
Brendan Eich wrote: No, in any such prototype-getter-makes-bound-function scenario, we would need memoization, so that o.m === o.m (Edit: I see you mention this below.) The real problem is better captured by showing the prototype p and two instances, o and q: p.m === p.m should be true. So should o.m === o.m and q.m === q.m but what about o.m === p.m and o.m === q.m JS requires distinct bound function identity from the unbound p.m identity, so false and false. If we managed to extend JS with a classy declarative syntax that enabled vtables, while keeping functions first class (at the price of prototype-chain mutation: assignment to override, or shadow; also of course delete), then we might well want true and true. But there would be no way in JS itself to implement such magic in terms of properties (data or accessor, doesn't matter) with function values. This is why I continue to think that we won't see what Alex predicted: prototype getter method vending. We haven't see it much in the wild yet either. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Arrow binding
On Apr 23, 2012, at 3:53 AM, Alex Russell wrote: This means that most users of most functions can still use .call() and .apply() without apprehension. Functions are still just functions. You're assuming your conclusion: that there's some sort of platonic ideal (just functions) of JS functions always having a use for their `this` binding. But when I pass function() { elt.style.background = 'yellow' } to setTimeout, is my function some betrayal of The JavaScript Way? No it's a function that changes the background color of an element. It's not evil. It's every bit as valid a function as one that's intended to be a method. JavaScript uses functions for many different things: constructors, top-level functions, callbacks, and methods. Sometimes you need all their features, sometimes you don't. 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. I don't accept this frame. The contract of .call() and .apply() is that their first argument specifies the binding for `this`. The contract between a function and its caller is that the caller provides bindings for the arguments, and the callee decides what to do with those arguments. It is perfectly acceptable for the callee to disregard some arguments. Now, it's certainly possible to make functions less abstract than necessary by using closed-over variables instead of arguments (including `this`). Maybe where I'm closer to agreement with you is that *when you're implementing methods* it's better to use `this` than to lexically close over the object the methods were created for. But not all functions in JavaScript are methods. I'm much more sympathetic to the idea of having *two* shorter-function syntaxes, one optimized for methods and one optimized for non-method functions. I understand the concern about bloat, but to me it addresses the reality of different contexts in programming, e.g.: a.map(x = x + 1) vs box = { _value: 0, get: () - this._value, set(v) { this._value = v } } 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. Maybe you do need to, because I'm not convinced. JavaScript already lets you do either. With the shorter function syntax, we've only been discussing conveniences for things you can already express. You claim that conveniences like fat arrow are radical, but soft bind is the proposal that breaks an existing language guarantee. It introduces a new distinction: a callee can now change behavior depending on whether it was called via f() or vs f.call(null). That breaks the feature that you can always use .call/.apply as a drop-in replacement for the equivalent explicit call. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss