Scoped binding of a method to an object
Scoped binding of a method to an object Well, I know how some languages solve this issue but I wondered if ECMAScript considered addressing this or already have and I missed it. Often, I want to extend objects, for example - Array.prototype.shuffle - takes an array and shuffles it. However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype *before* it was adapted to the spec and not get eventually bitten. Stuff like underscore _.shuffle makes for less object oriented code, I find it harder to write and it feels like the code is not where it belongs. What I'd like is a way to add such methods in a scoped way, so within *my* code I get to use .shuffle but any code that is not in that scoped block does not get access to this method. Has there been a proposal or discussion about this in the past? Benjamin Gruenabum ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Generic Bundling
On Sat, Oct 12, 2013 at 12:07 PM, Brendan Eich bren...@mozilla.com wrote: However, Russell's counter-argument that fallback in older browsers to loading lots of little files, request by request, from the server directory hierarchy, may be too painful, reducing the value as a migration technique. this is what happens today with external CDN scripts and/or AMD like solutions regardless ... if these are not bundled all together, isn't it? Is there a way for old browsers that avoids a request storm, and which can be expressed entirely in the hosted content (no protocol stack update problem)? hacking HTML SCRIPT prototype upfront, it's possible to improve the behavior but hard to make it fully able to ignore network requests. However, this is not usually the main concern for new/recent proposals so I wonder why it is in such specific case? Best Regards ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Generic Bundling
On Oct 13, 2013 4:40 AM, Andrea Giammarchi andrea.giammar...@gmail.com wrote: On Sat, Oct 12, 2013 at 12:07 PM, Brendan Eich bren...@mozilla.com wrote: However, Russell's counter-argument that fallback in older browsers to loading lots of little files, request by request, from the server directory hierarchy, may be too painful, reducing the value as a migration technique. this is what happens today with external CDN scripts and/or AMD like solutions regardless ... if these are not bundled all together, isn't it? To me at least, the primary difference there is that in that case it is in the authors hand whereas native feature support is in the hands of the user agent, creating a potentially huge and unmanageable perf delta in the short/medium term. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 3:54 AM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: Scoped binding of a method to an object Well, I know how some languages solve this issue but I wondered if ECMAScript considered addressing this or already have and I missed it. Often, I want to extend objects, for example - Array.prototype.shuffle - takes an array and shuffles it. However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype *before* it was adapted to the spec and not get eventually bitten. Stuff like underscore _.shuffle makes for less object oriented code, I find it harder to write and it feels like the code is not where it belongs. What I'd like is a way to add such methods in a scoped way, so within *my* code I get to use .shuffle but any code that is not in that scoped block does not get access to this method. Has there been a proposal or discussion about this in the past? This is trivial with Symbols: let shuffle = Symbol(); Array.prototype[shuffle] = function() {...}; Only code that has access to the `shuffle` symbol may use the method: let shuffled = array[shuffle](); Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
This is trivial with Symbols: let shuffle = Symbol(); Array.prototype[shuffle] = function() {...}; Only code that has access to the `shuffle` symbol may use the method: let shuffled = array[shuffle](); Unfortunately, such a construction will fail in a multi-realm (i.e. multiple frames) environment. { Kevin } ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 6:45 PM, Kevin Smith zenpars...@gmail.com wrote: This is trivial with Symbols: let shuffle = Symbol(); Array.prototype[shuffle] = function() {...}; Only code that has access to the `shuffle` symbol may use the method: let shuffled = array[shuffle](); Unfortunately, such a construction will fail in a multi-realm (i.e. multiple frames) environment. That's what the symbol registry will solve, though. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Apologies for the (iPad + haste)-induced typos below :-(. /be Brendan Eich mailto:bren...@mozilla.com October 13, 2013 10:17 AM Benjamin (Inglor) Gruenbaum wrote: However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) Actually, people say extending Object.prototype is bad practive (verboten, the original post, IIRC from Arv, said; yes, I recalled correctly: http://erik.eae.net/archives/2005/06/06/22.13.54/). Extending Array.prototype is less so, and PrototypeJS did it. Other libraries extend built-in prototypes. Some even take care not to jump a prior claim. The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype /before/ it was adapted to the spec and not get eventually bitten. No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Symbols help but (without dot syntax) also hurt. We'll see how much use they get in the future, but for the record, string-equated names have been and will be used to extend standard built-ins too. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. This proposal died precise because of the performance problem. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 12:54 AM Scoped binding of a method to an object Well, I know how some languages solve this issue but I wondered if ECMAScript considered addressing this or already have and I missed it. Often, I want to extend objects, for example - Array.prototype.shuffle - takes an array and shuffles it. However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype /before/ it was adapted to the spec and not get eventually bitten. Stuff like underscore _.shuffle makes for less object oriented code, I find it harder to write and it feels like the code is not where it belongs. What I'd like is a way to add such methods in a scoped way, so within /my/ code I get to use .shuffle but any code that is not in that scoped block does not get access to this method. Has there been a proposal or discussion about this in the past? Benjamin Gruenabum ___ 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: Scoped binding of a method to an object
We did proposes this back in 2011 http://wiki.ecmascript.org/doku.php?id=strawman:scoped_object_extensions I wasn't at this actual F2F meeting so I don't know many details. Brendan might remember what the blocking issue was? On Sun, Oct 13, 2013 at 1:19 PM, Brendan Eich bren...@mozilla.com wrote: Apologies for the (iPad + haste)-induced typos below :-(. /be Brendan Eich mailto:bren...@mozilla.com October 13, 2013 10:17 AM Benjamin (Inglor) Gruenbaum wrote: However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) Actually, people say extending Object.prototype is bad practive (verboten, the original post, IIRC from Arv, said; yes, I recalled correctly: http://erik.eae.net/archives/2005/06/06/22.13.54/). Extending Array.prototype is less so, and PrototypeJS did it. Other libraries extend built-in prototypes. Some even take care not to jump a prior claim. The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype /before/ it was adapted to the spec and not get eventually bitten. No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Symbols help but (without dot syntax) also hurt. We'll see how much use they get in the future, but for the record, string-equated names have been and will be used to extend standard built-ins too. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. This proposal died precise because of the performance problem. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 12:54 AM Scoped binding of a method to an object Well, I know how some languages solve this issue but I wondered if ECMAScript considered addressing this or already have and I missed it. Often, I want to extend objects, for example - Array.prototype.shuffle - takes an array and shuffles it. However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype /before/ it was adapted to the spec and not get eventually bitten. Stuff like underscore _.shuffle makes for less object oriented code, I find it harder to write and it feels like the code is not where it belongs. What I'd like is a way to add such methods in a scoped way, so within /my/ code I get to use .shuffle but any code that is not in that scoped block does not get access to this method. Has there been a proposal or discussion about this in the past? Benjamin Gruenabum ___ 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 -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 7:17 PM, Brendan Eich bren...@mozilla.com wrote: Benjamin (Inglor) Gruenbaum wrote: However, this is considered bad practice for many reasons I don't have to repeat here (what if other libraries also override it? What if some user code? What if it makes it to the standard some day?) Actually, people say extending Object.prototype is bad practive (verboten, the original post, IIRC from Arv, said; yes, I recalled correctly: http://erik.eae.net/archives/2005/06/06/22.13.54/). Extending Array.prototype is less so, and PrototypeJS did it. Other libraries extend built-in prototypes. Some even take care not to jump a prior claim. Given the hoops we have to jump through because of Array.prototype and String#prototype extensions right now ([1] and Unscopable), I would argue that extending any builtins' prototypes without at least some poor-man's namespacing shouldn't be done, either. I do agree that poly- and prollyfilling can be quite convenient, but ISTM that the problems they create for the language's builtins library ability to evolve only increase over time. If we ever manage to introduce better syntax for by-symbol property lookups, that problem would be thoroughly solved. [1]: https://bugzilla.mozilla.org/show_bug.cgi?id=903755 The problem is even more prevalent in stuff like String.prototype.contains which we know will be in the next spec - people had little way to add that function to the string prototype /before/ it was adapted to the spec and not get eventually bitten. No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Symbols help but (without dot syntax) also hurt. We'll see how much use they get in the future, but for the record, string-equated names have been and will be used to extend standard built-ins too. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. This proposal died precise because of the performance problem. /be ___ 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: Scoped binding of a method to an object
David Bruant bruan...@gmail.com wrote This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. Of course, and I'm sorry if I implied otherwise. I'm sure we all acknowledge the problem of extending the native prototypes in libraries. I just don't understand how having a `_` prefix attempts to give us a solution to the problem. I'm not saying I have a solution either, but I think implying that it's ok to extend them with a prefix doesn't really solve much. Maybe I got what you were trying to say wrong though. On Sun, Oct 13, 2013 at 9:25 PM, David Bruant bruan...@gmail.com wrote: Le 13/10/2013 20:03, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com wrote: Concretely, attempted prolyfills, could be _-prefixed (that really fits with what you call poor-man's prefixing, I believe) Authors would feel free to add something like Array.prototype._shuffle or Array.prototype._last, or EventTarget.prototype._on without worrying about collision with the platform. What if I use two libraries that polyfill `_shuffle` or `_last` differently (let's say with different behavior for an empty array for `_last` or weaker guarantee on the randomness in `_shuffle`)? What do you do today when a library overrides Array.prototype.concat with a different semantics? What do you do when you load two libraries each defining a global $ with different semantics? Apply every prevention/resolution mechanism you use today with global properties. Among other ideas: * don't load libraries that are known to have conflicts (!!) * isolate the code that enhance built-ins (preferably, run it before anything else and not in the middle of your application lifecycle) * Define functions as non-configurable/non-writable in development mode to discover conflicts before pushing to production. This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Any library that monkey patches primordials and wishes to be able to rely on the primordials being mutated only according to it should demand to be run before primordials are otherwise corrupted or frozen, and should freeze the primordials after patching. Of course, such a library isn't a library in the traditional sense -- it is a kernel for everything loaded into that realm after it. Two such kernels aren't composable because of this unsolvable conflict problem. Libraries meant to be composable should not mutate primordials, and should assume only that primordials are in some uncorrupted state. On Sun, Oct 13, 2013 at 11:25 AM, David Bruant bruan...@gmail.com wrote: Le 13/10/2013 20:03, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com wrote: Concretely, attempted prolyfills, could be _-prefixed (that really fits with what you call poor-man's prefixing, I believe) Authors would feel free to add something like Array.prototype._shuffle or Array.prototype._last, or EventTarget.prototype._on without worrying about collision with the platform. What if I use two libraries that polyfill `_shuffle` or `_last` differently (let's say with different behavior for an empty array for `_last` or weaker guarantee on the randomness in `_shuffle`)? What do you do today when a library overrides Array.prototype.concat with a different semantics? What do you do when you load two libraries each defining a global $ with different semantics? Apply every prevention/resolution mechanism you use today with global properties. Among other ideas: * don't load libraries that are known to have conflicts (!!) * isolate the code that enhance built-ins (preferably, run it before anything else and not in the middle of your application lifecycle) * Define functions as non-configurable/non-writable in development mode to discover conflicts before pushing to production. This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. David ___ 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: Scoped binding of a method to an object
Le 13/10/2013 20:29, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com mailto:bruan...@gmail.com wrote This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. Of course, and I'm sorry if I implied otherwise. I'm sure we all acknowledge the problem of extending the native prototypes in libraries. I just don't understand how having a `_` prefix attempts to give us a solution to the problem. I'm not saying I have a solution either, but I think implying that it's ok to extend them with a prefix doesn't really solve much. Maybe I got what you were trying to say wrong though. Not wrong, but partial ;-) '_'-prefixing isn't a solution in itself. It requires a commitment from the platform to say they won't make use of this namespace in the future, thus allowing authors to use this namespace without worrying about future conflicts. Just to clarify a point, I started speaking about _-prefixing after Till's point about the language's builtins library ability to evolve. My point is somewhat unrelated to scoped binding and is not a solution for that (I should fork the thread if we continue discussing this). David On Sun, Oct 13, 2013 at 9:25 PM, David Bruant bruan...@gmail.com mailto:bruan...@gmail.com wrote: Le 13/10/2013 20:03, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com mailto:bruan...@gmail.com wrote: Concretely, attempted prolyfills, could be _-prefixed (that really fits with what you call poor-man's prefixing, I believe) Authors would feel free to add something like Array.prototype._shuffle or Array.prototype._last, or EventTarget.prototype._on without worrying about collision with the platform. What if I use two libraries that polyfill `_shuffle` or `_last` differently (let's say with different behavior for an empty array for `_last` or weaker guarantee on the randomness in `_shuffle`)? What do you do today when a library overrides Array.prototype.concat with a different semantics? What do you do when you load two libraries each defining a global $ with different semantics? Apply every prevention/resolution mechanism you use today with global properties. Among other ideas: * don't load libraries that are known to have conflicts (!!) * isolate the code that enhance built-ins (preferably, run it before anything else and not in the middle of your application lifecycle) * Define functions as non-configurable/non-writable in development mode to discover conflicts before pushing to production. This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Prollyfilling is great too (perhaps you disagree?), and as its name suggests it happens *before* the method is added to the spec. So in your opinion adding a `.shuffle` method to an Array in a library I ship to users is a good idea if it makes my code clearer and nicer? I'm not saying I disagree, I'm not one of those people who passes an extra parameter for `undefined` in a function. I just think it can be very risky. When I have to work on big code bases that run JavaScript end to end using multiple frameworks and libraries on both sides, I find that extending object prototypes can be _very_ risky - and Prollyfilling (nice term by the way) has bitten me before. Sure, in _my_ code it can be very nice, but I expect libraries to have little to no side effects on my code and that's exactly the cases it can bite me. How exactly did that example fail? The differences in detail hardly matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry about the edge case differences. I don't think anyone today is doubting the enormous contribution PrototypeJS had and `.bind` was very useful in it and is very useful in ES5. However, running into edge cases and getting unexpected results is something I don't think people appreciate. The SweetJS case is just as interesting. There is no doubt some of the most interesting API additions have come from people extending natives and that says something. However, today when rather than writing 1000 line pages I see more and more 100 thousand lines code bases using multiple libraries - side effects that extending natives sound _very_ scary, and being able to extend the natives in a way that does not bite me is something I'd _really_ love to play with. Don't worry about syntax yet. Of course, I was just toying around. Like I've said before, pretty much anyone else in this discussion is more qualified to come with an actual solution than me. This must cost, and it does cost. Would you mind elaborating on that or linking to relevant discussion about the last proposal? I'd love to understand the issues involved and get a better understanding of the challenges something like this would bring. On Sun, Oct 13, 2013 at 9:37 PM, Brendan Eich bren...@mozilla.com wrote: Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 11:00 AM Brendan Eichbren...@mozilla.com mailto:bren...@mozilla.com wrote: No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Polyfilling is great _after_ the method has already been added to the spec. Prollyfilling is great too (perhaps you disagree?), and as its name suggests it happens *before* the method is added to the spec. I'm completely fine with adding an Array.prototype.map shim to IE8, the problem with adding a method that's not on the prototype yet is that it'll fail in case the spec is different from the implementation I chose. If you mentioned PrototypeJS, its `.bind` method is one such example. How exactly did that example fail? The differences in detail hardly matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry about the edge case differences. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. I have to say this surprises me, a performance issue is the last thing I expected. What about attaching a prototype as a closure variable, something (and this is a syntax I __don't__ like) like: ``` (function(use Array){ Array.prototype.contains = function() { ... ... // any code here has access to .contains, code that did not originate here does not have such access, much like a closure. // other code is free to use Array without any collisions. })() ``` Again, I __don't__ like this sort of syntax and I'm __not__ sure about the semantics here, I just noticed I have this problem - I'm probably not the most qualified for coming up with the solution out of the amazing minds right here. Don't worry about syntax yet. The issue in any such semantic extension is the required extra lookup parameter: not just contains on the right of dot, but the enclosing closure scope. Unqualified identifiers (ones not used after dot) indeed require lookup via closure environments, to the global (let's ignore 'with' and DOM inline event handlers). Dot-qualified identifiers and equivalent bracketed computed property name accesses require prototype chain lookup. No matter the syntax, and independent of details of how one specs it, you're proposing a hybrid of the two schemes. This must cost, and it does cost. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 11:36 AM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: First of all - well put. Thanks. Second, wouldn't being able to do this in a scoped way solve the conflict problem? As Brendan points out, doing this in a scoped way adds a third parameter representing the scope, or that somehow needs to be scope specific. Such a third parameter needs to be first class. WeakMaps and relationships do exactly that. On Sun, Oct 13, 2013 at 9:33 PM, Mark S. Miller erig...@google.comwrote: Any library that monkey patches primordials and wishes to be able to rely on the primordials being mutated only according to it should demand to be run before primordials are otherwise corrupted or frozen, and should freeze the primordials after patching. Of course, such a library isn't a library in the traditional sense -- it is a kernel for everything loaded into that realm after it. Two such kernels aren't composable because of this unsolvable conflict problem. Libraries meant to be composable should not mutate primordials, and should assume only that primordials are in some uncorrupted state. On Sun, Oct 13, 2013 at 11:25 AM, David Bruant bruan...@gmail.comwrote: Le 13/10/2013 20:03, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com wrote: Concretely, attempted prolyfills, could be _-prefixed (that really fits with what you call poor-man's prefixing, I believe) Authors would feel free to add something like Array.prototype._shuffle or Array.prototype._last, or EventTarget.prototype._on without worrying about collision with the platform. What if I use two libraries that polyfill `_shuffle` or `_last` differently (let's say with different behavior for an empty array for `_last` or weaker guarantee on the randomness in `_shuffle`)? What do you do today when a library overrides Array.prototype.concat with a different semantics? What do you do when you load two libraries each defining a global $ with different semantics? Apply every prevention/resolution mechanism you use today with global properties. Among other ideas: * don't load libraries that are known to have conflicts (!!) * isolate the code that enhance built-ins (preferably, run it before anything else and not in the middle of your application lifecycle) * Define functions as non-configurable/non-writable in development mode to discover conflicts before pushing to production. This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
As Brendan points out, doing this in a scoped way adds a third parameter representing the scope, or that somehow needs to be scope specific. Such a third parameter needs to be first class. WeakMaps and relationships do exactly that. My relative lack of experience here is probably working against me. Would you mind explaining how WeakMaps (and later relationships) give me that third scope parameter? Also, are you implying adding this sort of scoped extension of a native prototype be possible/easy once those features are implemented? (Sending me to reading is great too, I don't want to waste your time) On Sun, Oct 13, 2013 at 10:00 PM, Mark S. Miller erig...@google.com wrote: On Sun, Oct 13, 2013 at 11:36 AM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: First of all - well put. Thanks. Second, wouldn't being able to do this in a scoped way solve the conflict problem? As Brendan points out, doing this in a scoped way adds a third parameter representing the scope, or that somehow needs to be scope specific. Such a third parameter needs to be first class. WeakMaps and relationships do exactly that. On Sun, Oct 13, 2013 at 9:33 PM, Mark S. Miller erig...@google.comwrote: Any library that monkey patches primordials and wishes to be able to rely on the primordials being mutated only according to it should demand to be run before primordials are otherwise corrupted or frozen, and should freeze the primordials after patching. Of course, such a library isn't a library in the traditional sense -- it is a kernel for everything loaded into that realm after it. Two such kernels aren't composable because of this unsolvable conflict problem. Libraries meant to be composable should not mutate primordials, and should assume only that primordials are in some uncorrupted state. On Sun, Oct 13, 2013 at 11:25 AM, David Bruant bruan...@gmail.comwrote: Le 13/10/2013 20:03, Benjamin (Inglor) Gruenbaum a écrit : David Bruant bruan...@gmail.com wrote: Concretely, attempted prolyfills, could be _-prefixed (that really fits with what you call poor-man's prefixing, I believe) Authors would feel free to add something like Array.prototype._shuffle or Array.prototype._last, or EventTarget.prototype._on without worrying about collision with the platform. What if I use two libraries that polyfill `_shuffle` or `_last` differently (let's say with different behavior for an empty array for `_last` or weaker guarantee on the randomness in `_shuffle`)? What do you do today when a library overrides Array.prototype.concat with a different semantics? What do you do when you load two libraries each defining a global $ with different semantics? Apply every prevention/resolution mechanism you use today with global properties. Among other ideas: * don't load libraries that are known to have conflicts (!!) * isolate the code that enhance built-ins (preferably, run it before anything else and not in the middle of your application lifecycle) * Define functions as non-configurable/non-writable in development mode to discover conflicts before pushing to production. This proposal does not aim at solving the problem of library conflicts which existed before this proposal and should be solve independently. David ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 11:19 AM Keeping a third parameter beyond object and property name seems unnecessary. Here is a counterexample based on the strawman's syntax: // In module LINQ's body: extension Array.prototype { where: Array.prototype.filter, select: Array.prototype.map } export function query(a, w, s) { return a.where(w).select(s); } import {query} from LINQ; Array.prototype.select = () = oops; var b = readData(); var w = ..., s = ...; var r = query(b, w, s); // So far, so good. Now let's try an array-like: var c = { length: 0 }; // and let's be mean: Object.prototype.where = () = oops for real!; String.prototype.select = x = x; // identity function // Fill c from b and query c with w and s: b.forEach(e = c[c.length++] = e); var s = query(c, w, s); // This must hold: assertEqual(s, oops for real!); The only way to make this work is for the code in LINQ's body, in function query, to look for 'where' in 'a' (whose type is not known statically) by passing a token for the extended scope of module LINQ's body. When 'a.where' is evaluated to call the method, if 'a' is an instance of Array.prototype with no shadowing 'where', in particular when it refers to 'b', then the extension method = Array.prototype.filter is found. When 'a' refers to 'c', however, the code in LINQ does not know this _a priori_, so again the lookup of 'where' in c must pass the scope token. But this time, because c is an array-like Object instance that does not delegate to Array.prototype, the extension 'where' method is not found. In my likely naive eyes, dynamic `this` gives us great power here. Thinking about other languages that deal with the problem. As far as I remember C# extension methods are just (really nice) syntactic sugar for statics. C# has static types and name lookup rules. JS has neither in full, although its name lookup rules are static within functions (and blocks in ES6), excluding 'with'. Is it difficult to convert something like: ``` Array.prototype.last = function(){ return this[this.length-1] } ``` To something like ``` function Array$prototype$last(param1){ return (function(){ return this[this.length-1] }).call(param1); } ``` ? You have not defined convert, and there's no client code that calls 'last' on a given array instance. Another way of saying this: your name mangling does nothing to help an array ('b' in my example) find its method. There's no static type, no class or traits. The lookup in LINQ to call a.where is fully dynamic. Same for any use of your last method. The name rendezvous must be via prototypal lookup. If you wrote client code in scope of the 'last' extension, e.g. var b = [1, 2, 3]; alert(b.last()); and expected some whole-program transformation (which we do not perform in JS, too much ambiguity -- think of computed property names, never mind 'with' and the global object and eval!) that results in var b = [1, 2, 3]; alert((b instanceof Array) ? Array$prototype$last.call(b) : b.last()); then you have essentially added the third (scope token) parameter by code expansion. Whether ?: or an if statement or polymorphic lookup is used, that's real added runtime cost, and it won't fly. /be -- Forwarded message -- From: Erik Arvidsson erik.arvids...@gmail.com mailto:erik.arvids...@gmail.com To: Brendan Eich bren...@mozilla.com mailto:bren...@mozilla.com Cc: es-discuss es-discuss@mozilla.org mailto:es-discuss@mozilla.org Date: Sun, 13 Oct 2013 13:32:23 -0400 Subject: Re: Scoped binding of a method to an object We did proposes this back in 2011 http://wiki.ecmascript.org/doku.php?id=strawman:scoped_object_extensions I wasn't at this actual F2F meeting so I don't know many details. Brendan might remember what the blocking issue was? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Erik Arvidsson wrote: Let's not kid ourselves. WeakMaps have bad user ergonomics and runtime ergonomics. I think at this point non method functions are much better. Hang on, relationships and new syntax can solve both performance and ergonomics concerns, we think. Perhaps you missed the March meeting where Mark discussed relationships (big meeting, it may have been near or even over a break). The key insight is that with: obj@rel obj@rel = val we can avoid the dot dilemma of having to parameterize by scope, instead treat these two as rel.@@get(obj) rel.@@set(obj, val) respectively, under the hood. Mark observed further that where rel could be a weak map, it should not be implemented as an ephemeron table with all the GC costs that entails. Because such an object field relationship outlives all object instances, it is equivalent to a class or trait private member, and the value can be stored directly on the object. The issue of proxy leaking is dodged by delegating to rel, which can itself by proxied in a membrane setting, IIRC. But at this point I should summon Mark to take over. My point is that it seems not everyone heard Mark's statement that weakmaps should not be used to implement relationships except in preprocessors targeting ES6 (assuming we get relationships into ES7). /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Generic Bundling
Anne van Kesteren mailto:ann...@annevk.nl October 11, 2013 12:34 AM On Fri, Oct 11, 2013 at 3:53 AM, Brendan Eichbren...@mozilla.com wrote: On Thu, Oct 10, 2013 at 8:10 PM, Andrea Giammarchi andrea.giammar...@gmail.commailto:andrea.giammar...@gmail.com wrote: You are confining the problem in HTTP only scenarios while the solution provided by script src=lib/main.js ref=”assets.zip”/script No, you're right -- agree with you and Andrea, this is sweet. It would require each end point that wants to support this to have new syntax. A solution from http://wiki.whatwg.org/wiki/Zip#URLs will not require updating all the end points. That doc is a bit cryptic. Can you explain how new URL syntax to address a ZIP member (I like, we had it in the ancient days with JAR files [ZIPs of course] using '!') avoids updating both end points? The content on the server starts using script src=assets.zip!lib/main.js/script How do old browsers cope? HTML nerd nit: is ref the right name? I thought it was used as an attribute name somewhere in HTML or nearby, but I can't find it. Cc'ing Anne. You might be thinking of rev (which is obsolete now in favor of using rel everywhere). That's it, thanks! /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Generic Bundling
Jorge Chamorro wrote: On 11/10/2013, at 03:53, Brendan Eich wrote: On Thu, Oct 10, 2013 at 8:10 PM, Andrea Giammarchiandrea.giammar...@gmail.com mailto:andrea.giammar...@gmail.com wrote: You are confining the problem in HTTP only scenarios while the solution provided by script src=lib/main.js ref=”assets.zip”/script No, you're right -- agree with you and Andrea, this is sweet. Are main.js and assets.zip two separate files, or is main.js expected to come from into assets.zip? The latter. I think the latter would be best because it would guarantee that the assets are there by the time main.js runs, as if they were local files, ready to be require()d synchronously. How would old browsers cope, though? They would load only lib/main.js (and possibly make a request storm, as Russell brought out elsewhere in this thread), so (synchronous) require of another member of assets.zip might or might not work. A prefetching link element might not suffice in old browsers, I'm pretty sure it won't. If the only way to cope with downrev browsers is to use Traceur, so be it. We just need to be sure we're not missing some clever alternative. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Oct 13, 2013 3:23 PM, Brendan Eich bren...@mozilla.com wrote: Erik Arvidsson wrote: Let's not kid ourselves. WeakMaps have bad user ergonomics and runtime ergonomics. I think at this point non method functions are much better. Hang on, relationships and new syntax can solve both performance and ergonomics concerns, we think. Perhaps you missed the March meeting where Mark discussed relationships (big meeting, it may have been near or even over a break). I did not miss it. The key insight is that with: obj@rel obj@rel = val we can avoid the dot dilemma of having to parameterize by scope, instead treat these two as rel.@@get(obj) rel.@@set(obj, val) respectively, under the hood. Mark observed further that where rel could be a weak map, it should not be implemented as an ephemeron table with all the GC costs that entails. Because such an object field relationship outlives all object instances, it is equivalent to a class or trait private member, and the value can be stored directly on the object. Using a WeakMap for rel is a bit too simplistic. We need to read and write through to the prototype but you are right that rel can be implemented using WeakMaps. The issue of proxy leaking is dodged by delegating to rel, which can itself by proxied in a membrane setting, IIRC. But at this point I should summon Mark to take over. My point is that it seems not everyone heard Mark's statement that weakmaps should not be used to implement relationships except in preprocessors targeting ES6 (assuming we get relationships into ES7). Exactly. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 12:45 PM, Kevin Smith zenpars...@gmail.com wrote: This is trivial with Symbols: let shuffle = Symbol(); Array.prototype[shuffle] = function() {...}; Only code that has access to the `shuffle` symbol may use the method: let shuffled = array[shuffle](); Unfortunately, such a construction will fail in a multi-realm (i.e. multiple frames) environment. Not if I register the symbol in the not-yet-specified symbol registry. Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Erik Arvidsson wrote: ... My point is that it seems not everyone heard Mark's statement that weakmaps should not be used to implement relationships except in preprocessors targeting ES6 (assuming we get relationships into ES7). Exactly. Ok, that's what I was hoping for. We need Traceur, not poorly-performing and unergonomic by-hand codings. To borrow from Dean Wormer: slow, hard to read, and hard to write is no way to go through life! ;-) /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Generic Bundling
my latest message was about this situation www/ my-assets/ js/ my-bundle.js css/ some.css image/ some.png assets.zip where latter contains the equivalent of the my-assets folder. The prefetching link won't do a thing in old browsers, might be a directive for modern suggesting a package.zip file to use instead of the folder name. Old browsers will do everything as they do today, new browsers have the ability to use one single package instead of requiring the file. As result: link rel=package name=my-assets type=application/zip href =assets.zip script src=my-assets/js/my-bundle.js/script will simply request that file through HTTP in old browsers, it will use the aliased zip file through my-assets if capable. It's actually very similar to initial proposal also creating a precedent for network aliases independent from mod_rewrite and friends (client/UA only mod_rewrite like approach) Cheers On Sun, Oct 13, 2013 at 12:34 PM, Brendan Eich bren...@mozilla.com wrote: Jorge Chamorro wrote: On 11/10/2013, at 03:53, Brendan Eich wrote: On Thu, Oct 10, 2013 at 8:10 PM, Andrea Giammarchi andrea.giammarchi@**gmail.com andrea.giammar...@gmail.com mailto: andrea.giammarchi@**gmail.com andrea.giammar...@gmail.com wrote: You are confining the problem in HTTP only scenarios while the solution provided by script src=lib/main.js ref=”assets.zip”/script No, you're right -- agree with you and Andrea, this is sweet. Are main.js and assets.zip two separate files, or is main.js expected to come from into assets.zip? The latter. I think the latter would be best because it would guarantee that the assets are there by the time main.js runs, as if they were local files, ready to be require()d synchronously. How would old browsers cope, though? They would load only lib/main.js (and possibly make a request storm, as Russell brought out elsewhere in this thread), so (synchronous) require of another member of assets.zip might or might not work. A prefetching link element might not suffice in old browsers, I'm pretty sure it won't. If the only way to cope with downrev browsers is to use Traceur, so be it. We just need to be sure we're not missing some clever alternative. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
If you really have to live with those restriction you do describe, there still is a low level solution working since ES 3 that keeps the implemented codebase of certain behaviors at one place without effecting any other code - function based traits and mixins. One could e.g. write ones own implementations of an Enumerable's [first], [last] accessors. var Enumerable_first_last = (function () { var Trait, first = function () { return this[0]; }, last = function () { return this[this.length - 1]; } ; Trait = function () { this.first = first; this.last = last; }; return Trait; }()); From that point one is free to decide of where to apply that trait. var str = JavaScript natively supports Traits, arr = str.split( ), coll = { 0: foo, 1: bar, 2: baz, length: 2 } ; It is totally fine to apply additional behavior separately to objects that are in need of it. Enumerable_first_last.call(arr); arr.first(); // JavaScript arr.last(); // Traits Enumerable_first_last.call(coll); coll.first(); // foo coll.last(); // bar One also could delegate this behavior to an objects prototype. Enumerable_first_last.call(String.prototype); // works for all [[String]] implementations that do allow access via [idx] str.first(); // J str.last(); // s This approach in its first step decouples implementation from having it directly effecting a system. The second step is about responsibility and making decisions. Peter On Sun, Oct 13, 2013 at 8:47 PM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: Prollyfilling is great too (perhaps you disagree?), and as its name suggests it happens *before* the method is added to the spec. So in your opinion adding a `.shuffle` method to an Array in a library I ship to users is a good idea if it makes my code clearer and nicer? I'm not saying I disagree, I'm not one of those people who passes an extra parameter for `undefined` in a function. I just think it can be very risky. When I have to work on big code bases that run JavaScript end to end using multiple frameworks and libraries on both sides, I find that extending object prototypes can be _very_ risky - and Prollyfilling (nice term by the way) has bitten me before. Sure, in _my_ code it can be very nice, but I expect libraries to have little to no side effects on my code and that's exactly the cases it can bite me. How exactly did that example fail? The differences in detail hardly matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry about the edge case differences. I don't think anyone today is doubting the enormous contribution PrototypeJS had and `.bind` was very useful in it and is very useful in ES5. However, running into edge cases and getting unexpected results is something I don't think people appreciate. The SweetJS case is just as interesting. There is no doubt some of the most interesting API additions have come from people extending natives and that says something. However, today when rather than writing 1000 line pages I see more and more 100 thousand lines code bases using multiple libraries - side effects that extending natives sound _very_ scary, and being able to extend the natives in a way that does not bite me is something I'd _really_ love to play with. Don't worry about syntax yet. Of course, I was just toying around. Like I've said before, pretty much anyone else in this discussion is more qualified to come with an actual solution than me. This must cost, and it does cost. Would you mind elaborating on that or linking to relevant discussion about the last proposal? I'd love to understand the issues involved and get a better understanding of the challenges something like this would bring. On Sun, Oct 13, 2013 at 9:37 PM, Brendan Eich bren...@mozilla.com wrote: Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 11:00 AM Brendan Eichbren...@mozilla.com mailto:bren...@mozilla.com wrote: No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Polyfilling is great _after_ the method has already been added to the spec. Prollyfilling is great too (perhaps you disagree?), and as its name suggests it happens *before* the method is added to the spec. I'm completely fine with adding an Array.prototype.map shim to IE8, the problem with adding a method that's not on the prototype yet is that it'll fail in case the spec is different from the implementation I chose. If you mentioned PrototypeJS, its `.bind` method is one such example. How exactly did that example fail? The differences in detail hardly matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry about the edge case differences. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension
Re: Scoped binding of a method to an object
Thanks, this really helped me understand the underlying issue here forcing dynamic resolution of scope here. It sounds a lot harder than I initially thought I have to say the fact this is so deeply rooted in the language semantics is somewhat surprising to me. That said, I think I see why behavioral typing would be act like this and I expect this to still be a lot harder than I imagine. Here is a counterexample based on the strawman's syntax: ... When I pass a parameter `a` to a function and call `a.where` , whether or not it's an extension method - don't I still have to do dynamic scope resolution? Doesn't it still have to walk the prototype chain until I find `.where` - just like if I pass an array-like with `.splice` and send it to a method using it and it has to figure out it's not Array.prototype.splice? Off the top of my head - what about for the duration of the scope of these methods we have a prototype right after Array.prototype - in this scenario. Doesn't this make `c` go to Object.prototype.where and then String.prototype.select and all `b` does is another prototype chain look up before reaching the extension? This is probably another naive suggestion though. On Sun, Oct 13, 2013 at 10:15 PM, Brendan Eich bren...@mozilla.com wrote: Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 11:19 AM Keeping a third parameter beyond object and property name seems unnecessary. Here is a counterexample based on the strawman's syntax: // In module LINQ's body: extension Array.prototype { where: Array.prototype.filter, select: Array.prototype.map } export function query(a, w, s) { return a.where(w).select(s); } import {query} from LINQ; Array.prototype.select = () = oops; var b = readData(); var w = ..., s = ...; var r = query(b, w, s); // So far, so good. Now let's try an array-like: var c = { length: 0 }; // and let's be mean: Object.prototype.where = () = oops for real!; String.prototype.select = x = x; // identity function // Fill c from b and query c with w and s: b.forEach(e = c[c.length++] = e); var s = query(c, w, s); // This must hold: assertEqual(s, oops for real!); The only way to make this work is for the code in LINQ's body, in function query, to look for 'where' in 'a' (whose type is not known statically) by passing a token for the extended scope of module LINQ's body. When 'a.where' is evaluated to call the method, if 'a' is an instance of Array.prototype with no shadowing 'where', in particular when it refers to 'b', then the extension method = Array.prototype.filter is found. When 'a' refers to 'c', however, the code in LINQ does not know this _a priori_, so again the lookup of 'where' in c must pass the scope token. But this time, because c is an array-like Object instance that does not delegate to Array.prototype, the extension 'where' method is not found. In my likely naive eyes, dynamic `this` gives us great power here. Thinking about other languages that deal with the problem. As far as I remember C# extension methods are just (really nice) syntactic sugar for statics. C# has static types and name lookup rules. JS has neither in full, although its name lookup rules are static within functions (and blocks in ES6), excluding 'with'. Is it difficult to convert something like: ``` Array.prototype.last = function(){ return this[this.length-1] } ``` To something like ``` function Array$prototype$last(param1){ return (function(){ return this[this.length-1] }).call(param1); } ``` ? You have not defined convert, and there's no client code that calls 'last' on a given array instance. Another way of saying this: your name mangling does nothing to help an array ('b' in my example) find its method. There's no static type, no class or traits. The lookup in LINQ to call a.where is fully dynamic. Same for any use of your last method. The name rendezvous must be via prototypal lookup. If you wrote client code in scope of the 'last' extension, e.g. var b = [1, 2, 3]; alert(b.last()); and expected some whole-program transformation (which we do not perform in JS, too much ambiguity -- think of computed property names, never mind 'with' and the global object and eval!) that results in var b = [1, 2, 3]; alert((b instanceof Array) ? Array$prototype$last.call(b) : b.last()); then you have essentially added the third (scope token) parameter by code expansion. Whether ?: or an if statement or polymorphic lookup is used, that's real added runtime cost, and it won't fly. /be -- Forwarded message -- From: Erik Arvidsson erik.arvids...@gmail.com mailto: erik.arvidsson@gmail.**com erik.arvids...@gmail.com To: Brendan Eich bren...@mozilla.com mailto:bren...@mozilla.com Cc: es-discuss es-discuss@mozilla.org mailto:es-discuss@mozilla.org** Date: Sun, 13 Oct 2013 13:32:23 -0400 Subject: Re: Scoped binding of a method to an object
Re: Scoped binding of a method to an object
Function traits and mixins are the bread and butter of JS. Being able to share functionality is the pumping heart of prototypical inheritance, especially in a behaviorally typed environment. Much like a possible issue I have with what Rick suggested (although mixins and decoration are not the same) - let's say you have ` Enumerable_first_last.call(arr)` , and then I `.map` or `.filter` that mixed in array - the resulting array no longer has the trait. I can of course call Object.mixin on the result of `.map` and override `.map` on a Enumerable_first_last but that's a tedious process I don't want to have to do for every trait (what if I add several? Do I now have to keep track and compose?) It's an interesting suggestion and a common pattern, but I really hope we can do better. On Mon, Oct 14, 2013 at 12:01 AM, Peter Seliger peter.seli...@googlemail.com wrote: If you really have to live with those restriction you do describe, there still is a low level solution working since ES 3 that keeps the implemented codebase of certain behaviors at one place without effecting any other code - function based traits and mixins. One could e.g. write ones own implementations of an Enumerable's [first], [last] accessors. var Enumerable_first_last = (function () { var Trait, first = function () { return this[0]; }, last = function () { return this[this.length - 1]; } ; Trait = function () { this.first = first; this.last = last; }; return Trait; }()); From that point one is free to decide of where to apply that trait. var str = JavaScript natively supports Traits, arr = str.split( ), coll = { 0: foo, 1: bar, 2: baz, length: 2 } ; It is totally fine to apply additional behavior separately to objects that are in need of it. Enumerable_first_last.call(arr); arr.first(); // JavaScript arr.last(); // Traits Enumerable_first_last.call(coll); coll.first(); // foo coll.last(); // bar One also could delegate this behavior to an objects prototype. Enumerable_first_last.call(String.prototype); // works for all [[String]] implementations that do allow access via [idx] str.first(); // J str.last(); // s This approach in its first step decouples implementation from having it directly effecting a system. The second step is about responsibility and making decisions. Peter On Sun, Oct 13, 2013 at 8:47 PM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: Prollyfilling is great too (perhaps you disagree?), and as its name suggests it happens *before* the method is added to the spec. So in your opinion adding a `.shuffle` method to an Array in a library I ship to users is a good idea if it makes my code clearer and nicer? I'm not saying I disagree, I'm not one of those people who passes an extra parameter for `undefined` in a function. I just think it can be very risky. When I have to work on big code bases that run JavaScript end to end using multiple frameworks and libraries on both sides, I find that extending object prototypes can be _very_ risky - and Prollyfilling (nice term by the way) has bitten me before. Sure, in _my_ code it can be very nice, but I expect libraries to have little to no side effects on my code and that's exactly the cases it can bite me. How exactly did that example fail? The differences in detail hardly matter; PrototypeJS trod a cow-path that ES5 paved. Most users don't worry about the edge case differences. I don't think anyone today is doubting the enormous contribution PrototypeJS had and `.bind` was very useful in it and is very useful in ES5. However, running into edge cases and getting unexpected results is something I don't think people appreciate. The SweetJS case is just as interesting. There is no doubt some of the most interesting API additions have come from people extending natives and that says something. However, today when rather than writing 1000 line pages I see more and more 100 thousand lines code bases using multiple libraries - side effects that extending natives sound _very_ scary, and being able to extend the natives in a way that does not bite me is something I'd _really_ love to play with. Don't worry about syntax yet. Of course, I was just toying around. Like I've said before, pretty much anyone else in this discussion is more qualified to come with an actual solution than me. This must cost, and it does cost. Would you mind elaborating on that or linking to relevant discussion about the last proposal? I'd love to understand the issues involved and get a better understanding of the challenges something like this would bring. On Sun, Oct 13, 2013 at 9:37 PM, Brendan Eich bren...@mozilla.comwrote: Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 11:00 AM Brendan Eichbren...@mozilla.com mailto:bren...@mozilla.com wrote: No, object detection,
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 8:40 PM, Brendan Eich bren...@mozilla.com wrote: Till Schneidereit mailto:t...@tillschneidereit.net October 13, 2013 11:28 AM And now it causes problem for TC39, browser vendors, sites that use it and end users. (The last group should be affected the least because the first three groups work together to prevent it, of course.) I think we agree. My point was that the objections are not definitive, not axiomatic enough. The costs are born later and by others. This is a recipe for social ills. Ok, we do agree, then. What we do about it is up to us, but just asserting that developers should stop extending primordials sounds like King Canute to me. Also agreed. It's still not entirely obvious to me what exactly we should do about it, sadly. And not only now, but going forward. Cow path paving requires the cows' ability to trod on the same ground that might be paved later. That very fact means that the cow paths might end up colliding with paved streets. I don't see how this basic conundrum can be resolved without a scope based resolution-mechanism (no pun intended). ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
This sort of decoration is nice and it's how I usually do this right now, but this requires me to wrap every array with an `XArray` call which is tedious, not to mention stuff like `.map` or `.reduce` would still return an Array which would result in more endless wrapping. On Sun, Oct 13, 2013 at 11:53 PM, Rick Waldron waldron.r...@gmail.comwrote: On Sun, Oct 13, 2013 at 2:00 PM, Benjamin (Inglor) Gruenbaum ing...@gmail.com wrote: Brendan Eich bren...@mozilla.com wrote: No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Polyfilling is great _after_ the method has already been added to the spec. I'm completely fine with adding an Array.prototype.map shim to IE8, the problem with adding a method that's not on the prototype yet is that it'll fail in case the spec is different from the implementation I chose. If you mentioned PrototypeJS, its `.bind` method is one such example. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. I have to say this surprises me, a performance issue is the last thing I expected. What about attaching a prototype as a closure variable, something (and this is a syntax I __don't__ like) like: ``` (function(use Array){ Array.prototype.contains = function() { ... ... // any code here has access to .contains, code that did not originate here does not have such access, much like a closure. // other code is free to use Array without any collisions. })() ``` Another solution is creating your own subclass with custom methods... class XArray extends Array { constructor(...args) { super(...args); } contains(arg) { ... } } Then all code in this application uses XArray and gets its custom contains Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sunday, October 13, 2013, Benjamin (Inglor) Gruenbaum wrote: This sort of decoration is nice and it's how I usually do this right now, but this requires me to wrap every array with an `XArray` call which is tedious, What do you mean by wrap? Using this looks like: let values = new XArray(1,2,3,4); values.contains(3); // this is the custom contains not to mention stuff like `.map` or `.reduce` would still return an Array That's incorrect. XArray.prototype.map would return an XArray instance and reduce always returns what you specify it to return, which can be anything. Rick which would result in more endless wrapping. On Sun, Oct 13, 2013 at 11:53 PM, Rick Waldron waldron.r...@gmail.comjavascript:_e({}, 'cvml', 'waldron.r...@gmail.com'); wrote: On Sun, Oct 13, 2013 at 2:00 PM, Benjamin (Inglor) Gruenbaum ing...@gmail.com javascript:_e({}, 'cvml', 'ing...@gmail.com'); wrote: Brendan Eich bren...@mozilla.com javascript:_e({}, 'cvml', 'bren...@mozilla.com'); wrote: No, object detection, polyfilling, and even prollyfilling are common and successful adaptationsp on the Web. Polyfilling is great _after_ the method has already been added to the spec. I'm completely fine with adding an Array.prototype.map shim to IE8, the problem with adding a method that's not on the prototype yet is that it'll fail in case the spec is different from the implementation I chose. If you mentioned PrototypeJS, its `.bind` method is one such example. Your subject recalls a defunct proposal to add lexically-scoped but heap-based -- therefore object property-lookup performance hindering -- extension properties. I have to say this surprises me, a performance issue is the last thing I expected. What about attaching a prototype as a closure variable, something (and this is a syntax I __don't__ like) like: ``` (function(use Array){ Array.prototype.contains = function() { ... ... // any code here has access to .contains, code that did not originate here does not have such access, much like a closure. // other code is free to use Array without any collisions. })() ``` Another solution is creating your own subclass with custom methods... class XArray extends Array { constructor(...args) { super(...args); } contains(arg) { ... } } Then all code in this application uses XArray and gets its custom contains Rick ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sun, Oct 13, 2013 at 11:50 PM, Domenic Denicola dome...@domenicdenicola.com wrote: From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Benjamin (Inglor) Gruenbaum not to mention stuff like `.map` or `.reduce` would still return an Array which would result in more endless wrapping. This is actually not true as of ES6; ES6 uses `this.constructor` to figure out how to create the returned instance, which means inherited versions of `map`/`reduce`/etc. will automatically return new `XArray`s. It's quite a clever trick IMO, so we should all thank Allen for pushing for it and doing the spec work to make it possible :) Here's to hoping that it'll actually work in practice and not break too many sites. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
Yeah, I don't see how it's going to happen either. Now that I get you meant dynamic as in contrary to lexical scoping having scoped object extensions seems very counter intuitive - especially given the direction the language is heading. Thanks for the discussion. On Mon, Oct 14, 2013 at 1:36 AM, Brendan Eich bren...@mozilla.com wrote: Benjamin (Inglor) Gruenbaum mailto:ing...@gmail.com October 13, 2013 2:28 PM Thanks, this really helped me understand the underlying issue here forcing dynamic resolution of scope here. It sounds a lot harder than I initially thought I have to say the fact this is so deeply rooted in the language semantics is somewhat surprising to me. That said, I think I see why behavioral typing would be act like this and I expect this to still be a lot harder than I imagine. Here is a counterexample based on the strawman's syntax: ... When I pass a parameter `a` to a function and call `a.where` , whether or not it's an extension method - don't I still have to do dynamic scope resolution? That's not dynamic scope, first (dynamic scope refers to scoping where an *unqualified* name's meaning cannot be determined lexically -- e.g., with or the global object in JS; inline event handlers in the DOM). Doesn't it still have to walk the prototype chain until I find `.where` - just like if I pass an array-like with `.splice` and send it to a method using it and it has to figure out it's not Array.prototype.splice? Of course. The meaning a dot-qualified name in JS indeed depends on prototype lookup. But the parameters to that lookup procedure are the starting (directly referenced) object and the property name -- and not the scope in addition, or any equivalent transformation (e.g., my ?: example -- not also it used instanceof and did not work when a direct shadowing method existed on the array). Off the top of my head - what about for the duration of the scope of these methods we have a prototype right after Array.prototype - in this scenario. Doesn't this make `c` go to Object.prototype.where and then String.prototype.select and all `b` does is another prototype chain look up before reaching the extension? This is probably another naive suggestion though. It is, if you mean dynamically altering the prototype chain of standard objects within a lexical extent. That does create dynamic scope, since the call graph is not statically decidable in general in JS, and calls out of the lexical extent would see the prototype chain extension too. Even if we could pin down the call graph, we do not want arbitrary mutations going in and out of scope of prototype chains. Anyway, I think at this point we've established what is required for any scoped object extensions. Please draw the conclusion. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Scoped binding of a method to an object
On Sunday, October 13, 2013, Brendan Eich wrote: Till Schneidereit wrote: OnSun, Oct 13, 2013 at 11:50 PM, Domenic Denicola dome...@domenicdenicola.com wrote: From: es-discuss [mailto:es-discuss-boun...@mozilla.org] On Behalf Of Benjamin (Inglor) Gruenbaum not to mention stuff like `.map` or `.reduce` would still return an Array which would result in more endless wrapping. This is actually not true as of ES6; ES6 uses `this.constructor` to figure out how to create the returned instance, which means inherited versions of `map`/`reduce`/etc. will automatically return new `XArray`s. It's quite a clever trick IMO, so we should all thank Allen for pushing for it and doing the spec work to make it possible:) Here's to hoping that it'll actually work in practice and not break too many sites. Yes, we are not nearly out of the woods on this one. In fact, at the September TC39 meeting, did we not agree that more work was needed, and to go back to the lab? Allen (editor) and Rick (notes taker) know. The work that remained was wrapped up in draft 19, published sept 27th. Allen should confirm (as always) Rick /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss