Re: time to trim mustache
Object.decorate seems to fit the bill I think. On another note, using an array and the as of yet non-standardized but still useful function name property is a lot more palatable and succinct and is much closer to the desired improved object literal syntax. I've been partial to the following reimagining of Object.extend as Object.decorate which supports arrays of named functions as well as objects and also setters/getters which existing extend functions don't support usually. Object.defineProperty(Object, 'decorate', { configurable: true, writable: true, value: function decorate(o){ var a, b, c, d; for (a in arguments) { if (a) { if (Array.isArray(b = arguments[a])) { // array of named functions for (c = 0; c b.length; c++) { if (typeof b[c] === 'function' b[c].name) { Object.defineProperty(o, b[c].name, { value: b[c], configurable: true, writable: true }); } } } else { // object for (c in b) { // use getDesc instead of hasOwn to support get/set if (d = Object.getOwnPropertyDescriptor(b, c)) { if (d.get || d.set) { Object.defineProperty(o, c, d); } else { // purposefully trigger accessors if they exist o[c] = d.value; } } } } } } return o; } }); ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
I just want to (re)express my (and many others) concern about new syntax. While Object.extend adds useful feature (Although I think Object.define would be more appropriate name) I don't think new syntax is really necessary. I do think that new syntax needs a lot more justification then new semantics. I also would argue that it's a good idea to alway make syntax changes in a separate iteration from the one where associated semantics have being introduced. That would allow both community and come tee to see these semantics in practice and having more knowledge to decide what syntax sugar would work best, if any new syntax even will turn out to be necessary. One of these things is installing private named properties upon an existing object. As currently specified, those could not be communicated to an extend function via an object literal because we have disallowed any form of refection upon private named properties. Object.extend could not see them on the literal object in order to copy them. Trying to solve this problem by saying that Object.extend has special reflection privileges would violate the encapsulation that the non-relection on private name properties was intended to provided. But many other variations of this would do the job as well without a new syntax: Object.extend(target, privates( name1, value1, name2, value2 )) Anther ES6 specific semantic that has always been part of the mustache proposal is the correct binding of methods with super references. I've described this many times. So I'll just describe it again other than to reinforce that mustache is the great way to dynamically associate super referencing method to an object without running into the pitfalls that arise with the defineMethod alternative. I see how with mustache we can live without defineMethld. But omitting reflection APIs is pretty dangerous path to go with IMO. JS has being great as it was always possible to fix things that were not working for you. I have feeling that providing semantics only through new syntax may take away this great power of JS. Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ On Monday, 2012-06-04 at 09:45 , Brendan Eich wrote: Kevin Smith wrote: Thanks Dave, Of the 3 use cases you mentioned, I think unique names are probably sufficient for 1 and 3. For the second use case (an inaccessible piece of data associated with an object), would not a weak map also be appropriate? No, WeakMaps have two problems we've covered in this list: 1. Less efficient than private names. This matters when you can least afford it, and it matters for private names used to program in the large using objects in JS. WeakMaps require special GC handling and they're an extra object with internal mutable state. Private name objects are flat, frozen, and can be optimized a lot harder. 2. You cannot abstract property access: function get(obj, prop) { return obj[prop]; } works with a private name object referenced by prop. No such abstraction can be done with a weak map. /be ___ es-discuss mailing list es-discuss@mozilla.org (mailto: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: time to trim mustache
On 5 June 2012 21:30, Irakli Gozalishvili rfo...@gmail.com wrote: I just want to (re)express my (and many others) concern about new syntax. While Object.extend adds useful feature (Although I think Object.define would be more appropriate name) I don't think new syntax is really necessary. I do think that new syntax needs a lot more justification then new semantics. Sorry, do you mean the new `Name` object stuff? ( http://wiki.ecmascript.org/doku.php?id=harmony:private_name_objects) Or...? Still finding my feet, but not seeing any private stuff in AWB's extension literals (except by association with `Name` objects). -- T.J. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
On Jun 5, 2012, at 1:30 PM, Irakli Gozalishvili wrote: I just want to (re)express my (and many others) concern about new syntax. While Object.extend adds useful feature (Although I think Object.define would be more appropriate name) I don't think new syntax is really necessary. I do think that new syntax needs a lot more justification then new semantics. I also would argue that it's a good idea to alway make syntax changes in a separate iteration from the one where associated semantics have being introduced. That would allow both community and come tee to see these semantics in practice and having more knowledge to decide what syntax sugar would work best, if any new syntax even will turn out to be necessary. One of these things is installing private named properties upon an existing object. As currently specified, those could not be communicated to an extend function via an object literal because we have disallowed any form of refection upon private named properties. Object.extend could not see them on the literal object in order to copy them. Trying to solve this problem by saying that Object.extend has special reflection privileges would violate the encapsulation that the non-relection on private name properties was intended to provided. But many other variations of this would do the job as well without a new syntax: Object.extend(target, privates( name1, value1, name2, value2 )) I'm not exactly sure what you privates function returns (which is the actual value that is passed to extend) but it can't be an object where name1 and name 2 are property names because the current rules of private name enumerations would prevent them from being enumerated. Also I'm assuming that in a typical case you will want to install a related set of public and private methods on an object. I guess you might express this as: const private1 = new Name; const private2 = new Name; const private3 = new Name; Object.extend(target, { publicMethod1() {...this[private3]...}, publicMethod2() {...this[private2]()...}, publicDate1: 42, get publicGet () {return this[private1]} }); Object.extend(target, privates( //assume private returns a object kind known to Object.extend that is capable of iterating over the name values it was constructed with private1, undefined, //private1 need to be a data valued property, not a method . Let's assume that any non-function value is an indication of that intent private2, function(x) {...this[private1]...}, //note that traditional function declaration must be used. = doen' t have dynamic this and concise methods are not available here private3, accessor({get: function() {return this[private2](this[private1])}}) //accessor produces some sort of descriptors that identifies the need to add an accessor property }); more likely you would want to get it all into a single extend call, perhaps by making the privates be an additional argument or perhaps you intended this version of extends to support multiple arguments. In either case you would have const private1 = new Name; const private2 = new Name; const private3 = new Name; Object.extend(target, { publicMethod1() {...this[private3]...}, publicMethod2() {...this[private2]()...}, publicDate1: 42, get publicGet () {return this[private1]} }, privates( //assume private returns a object of kind known to Object.extend that is capable of enumerating the name values it was constructed with private1, undefined, //private1 needs to be a data valued property, not a method . Let's assume that any non-function value is an indication of that intent private2, function(x) {...this[private1]...}, //note that traditional function declaration must be used. = doen' t have dynamic this and concise methods are not available here private3, accessor({get: function() {return this[private2](this[private1])}}) //accessor produces some sort of descriptor that identifies the need to add an accessor property ) ); In either case, once you have to start defining helper functions that generate argument descriptors like above, I don't see a lot of advantage over using Object.defineProperty/defineProperties: const private1 = new Name; const private2 = new Name; const private3 = new Name; Object.defineProperties(target, { publicMethod1: {value: function() {...this[private3]...}, configurable: true}, publicMethod2: {value: function() {...this[private2]()...}, configurable: true} publicDate1: {value:42, enumerable: true, writable: true, configurable: true}, publicGet : {get: function () {return this[private1]}, enumerable: true, writable: true, configurable: true} }; //private name properties probably can't use defineProperties because of the private name reflection probation Object.defineProperty(target, private1, {value:undefined,
Re: time to trim mustache
Thanks Dave, Of the 3 use cases you mentioned, I think unique names are probably sufficient for 1 and 3. For the second use case (an inaccessible piece of data associated with an object), would not a weak map also be appropriate? So far I don't see that the benefit of private names (as opposed to just unique names) outweighs the additional object model complexity. As far as I can tell, all of the use cases for private names can be addressed with unique names and weak maps. Am I wrong? Regards, kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
Kevin Smith wrote: Thanks Dave, Of the 3 use cases you mentioned, I think unique names are probably sufficient for 1 and 3. For the second use case (an inaccessible piece of data associated with an object), would not a weak map also be appropriate? No, WeakMaps have two problems we've covered in this list: 1. Less efficient than private names. This matters when you can least afford it, and it matters for private names used to program in the large using objects in JS. WeakMaps require special GC handling and they're an extra object with internal mutable state. Private name objects are flat, frozen, and can be optimized a lot harder. 2. You cannot abstract property access: function get(obj, prop) { return obj[prop]; } works with a private name object referenced by prop. No such abstraction can be done with a weak map. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
On May 31, 2012, at 10:26 PM, David Herman wrote: It's become clear to me that mustache syntax is not well motivated. As a simple update for objects, there's little it can do that Object.extend couldn't do. Probably not surprisingly, I strongly disagree. First, WRT motivation. It's motivation is almost exactly that of object literals. In classic JavaScript, there is nothing that an object literal can do that can't be done with multiple imperative steps using the new operator, assignment expressions, Object.defineProperty calls (for accessor properties), etc. Yet many JS programmer greatly prefer using an object level to describe construction of a singleton object over using such discrete imperative steps, In JavaScript: The Good Parts, Crock even lists object literals as one of the beautiful features of JavaScript. The are arguably the best way to describe singleton objects in JavaScript. The motivation for mustache is the same but applied to extending the structure of a pre-existing object in a pleasant and concise manner that does not require multiple imperative steps. There are many situations where it is necessary to add a package of properties to a pre-allocated object: defining the properties for the prototype object that is automatically created for a constructor function, adding instance specific properties to an instance object within a constructor; adding constructor properties to a constructor function; attaching methods to the pure data trees created by JSON.parse, adding client specific properties to any object returned from a library constructor, etc. In ES6, with maxmin classes we will also have the need to added instance properties within a class constructor and to add class-side properties to a class as these are not currently directly support by the proposed class definition syntax. These can (and now are) all done in multiple imperative steps. Mustache allows all of these sorts of object extensions to be accomplished using the exact same beautiful object literal syntax. Of course you can argue that, you would get the same thing via an Object.extend function with an object literal passed as an argument. On a purely functional basis, that is true, for ES5 level semantics. However, I argue that this lacks the concise beauty of mustache. However, when we move into ES6 there are things that we have not yet figured out how to accomplish with an extends function but which simply fall out of mustache's design. One of these things is installing private named properties upon an existing object. As currently specified, those could not be communicated to an extend function via an object literal because we have disallowed any form of refection upon private named properties. Object.extend could not see them on the literal object in order to copy them. Trying to solve this problem by saying that Object.extend has special reflection privileges would violate the encapsulation that the non-relection on private name properties was intended to provided. It would permit any agent to use Object.extend to copy private name properties (include properties that are intended to server as type brands from any object to any other object. Anther ES6 specific semantic that has always been part of the mustache proposal is the correct binding of methods with super references. I've described this many times. So I'll just describe it again other than to reinforce that mustache is the great way to dynamically associate super referencing method to an object without running into the pitfalls that arise with the defineMethod alternative. I see how with mustache we can live without defineMethld. I don't see howwithout defineMethod we can live without super binding mustache. There is strong motivation for mustache and there are important things it can do that are not currently addressed by any Object.extend proposal that I have seen. I thought with my cascades proposal that it might gain more justification (to allow the fluent aka chainable style even for methods that return void instead of `this`), but even that's fairly weak tea. And we haven't even really discussed what semantics it should have for nested objects: replace (aka shallow) or recursively update (aka deep)? To me, cascades where never an essential use case for mustache. I think mustache have plenty of justification as originally proposed. I was happy to explore extending it to encompass the cascade use cases but the fact that those extensions seem to result in seeming insurmountable issues doesn't relate to the original unextended mustache proposal. (BTW, I think the semantics for nest cascades is pretty obvious. But won't sidetrack on it here). This debate over mustache/cascade/etc just isn't a worthwhile use of time. And it's not on target for ES6 anyway. It's time to set this aside and just focus on standardizing an Object.extend API (or possibly
Re: time to trim mustache
Hi Allen, I agree with your sentiments on the usefulness of mustache with respect to extending an object, but I think the point that brings it down is the fact that it will confuse developers with the put/define distinction. It just looks too much like batch assignment. Cascade (or the more specific batch-assignment) would be useful, but whether the gain in usefulness is worth the added language complexity is something that would need to be quantified. My hunch is that batch assignment would only provide a minor improvement. Regarding super references outside of class bodies: I agree with Luke that this is a foot gun. The class body provides an easy to understand meaning for super. Outside of the class body, that meaning is going to be subtle, probably too subtle to be worth it. When adding methods to objects, we can always just create an explicit variable to hold the super reference. Regarding private names: I'm not convinced that private, non-reflective names are unproblematic in and of themselves. I would personally like to see more exploration on this front, with concrete use-cases. What useful things can we do with private names that we cannot do with globally unique names? Regards, kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
On Jun 1, 2012, at 8:52 AM, Kevin Smith wrote: Regarding private names: I'm not convinced that private, non-reflective names are unproblematic in and of themselves. I would personally like to see more exploration on this front, with concrete use-cases. What useful things can we do with private names that we cannot do with globally unique names? Briefly, some high-level rationale: // - 1. Paving cowpaths: Crockford's closures-for-private-properties pattern but without the per-instance costs: function CrockClass() { var myPrivateData = ...; // one copy per instance this.myMethod = function(...) { ... myPrivatedata ... } } // versus: var myPrivateName = new Name(); function ES6Class() { this[myPrivateName] = ...; } ES6Class.prototype.myMethod = function(...) { ... this[myPrivateName] ... } 2. Untamperable object properties: var score = new Name(); // no cheating from the console! function GamePlayer() { this[score] = 0; } 3. Classes that are easier to subclass without name clash concerns: // super.js var myPrivateName = new Name(); function MySuperClass() { this[myPrivateName] = ...; } // sub.js var myPrivateName = new Name(); function MySubClass() { this[myPrivateName] = ...; // no clash :) } // - I agree that unique is often private enough. I still favor private names that can either be unique or private depending on your needs. And maybe they should default to unique, not to private. But it should still be easy to make them truly private. For cases where you truly need robust information hiding, private names are more ergonomic than closures. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
On Fri, Jun 1, 2012 at 10:16 AM, David Herman dher...@mozilla.com wrote: 1. Paving cowpaths: Crockford's closures-for-private-properties pattern but without the per-instance costs: function CrockClass() { var myPrivateData = ...; // one copy per instance this.myMethod = function(...) { ... myPrivatedata ... } } // versus: var myPrivateName = new Name(); function ES6Class() { this[myPrivateName] = ...; } ES6Class.prototype.myMethod = function(...) { ... this[myPrivateName] ... } By the way, I just wrote a more-or-less real-life example for this yesterday, to help Hixie with speccing something in HTML: http://www.xanthir.com/blog/b4JB0 ~TJ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: time to trim mustache
On Jun 1, 2012, at 12:26 AM, Allen Wirfs-Brock wrote: These can (and now are) all done in multiple imperative steps. Mustache allows all of these sorts of object extensions to be accomplished using the exact same beautiful object literal syntax. A beautiful syntax for something that can be done with a single function call an an object literal is *very* weak motivation. Syntax isn't cheap. I probably need to write a blog post about this. For syntax to be worth adding, it has to clear a higher bar than API's. If we can write an API that does something perfectly well and a new syntax only saves a handful of characters, it's not enough. Of course you can argue that, you would get the same thing via an Object.extend function with an object literal passed as an argument. On a purely functional basis, that is true, for ES5 level semantics. However, I argue that this lacks the concise beauty of mustache. An analogy: you could say the same thing about keyword arguments; writing f(width: 320, height: 240) is arguably more beautiful than f({ width: 320, height: 240 }) because the language is saying exactly what you mean without need for boilerplate. But that boilerplate is only two characters, so it's not worth the additional language complexity to add support for it. Another analogy: Smalltalk gets along great with using blocks for control abstractions because, again, it's only two skinny little characters of boilerplate. One of these things is installing private named properties upon an existing object. As currently specified, those could not be communicated to an extend function via an object literal because we have disallowed any form of refection upon private named properties. We dropped computed property names in object literals, so we don't even have any way of putting private names on an object literal anyway. The sets of things that you could express with mustache but not with Object.extend is fast dwindling for ES6. This debate over mustache/cascade/etc just isn't a worthwhile use of time. And it's not on target for ES6 anyway. It's time to set this aside and just focus on standardizing an Object.extend API (or possibly two, one for shallow, one for deep). Worthwhileness is simply your opinion, not mine. Anything we collectively decide we need in ES6 can be in ES6. Mustache was demoted to strawman. Proposals in strawman are not accepted for ES6. We can certainly break our own process if we need to, but it provides a useful check on moving too fast. If there's anything we should be careful about, it's new syntax. Again, I need to write a blog post about this. Object.extend is also not currently proposed for ES6 so I don't see how you can argue that it is more on target . It's not. We can certainly *discuss* things that are not on target for ES6, and I claim that Object.extend is something that would be of more value for us to discuss now, because as soon as we come to some agreement, developers can polyfill it and use it immediately. We should pave that cowpath because it's the more immediately solvable problem, regardless of whether it ends up in ES6. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss