Re: Minimalist (why) classes ?
Good point. Note that you can easily do the same thing without copying, via prototypes: https://github.com/rauschma/proto-js On Nov 13, 2011, at 3:21 , Rick Waldron wrote: On Sat, Nov 12, 2011 at 7:08 PM, Brendan Eich bren...@mozilla.com wrote: snip Let's argue about specifics or we'll get nowhere. Do you think Irakli's selfish.js extend (https://github.com/Gozala/selfish/blob/master/selfish.js) is the way to go, or Prototype's quite different form? Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, resulting in new instances being able to modify values of the base object's properties if those values are elements of an array or property values of an object - because the array and object property themselves are references, not real copies. PrototypeJS is painfully obvious, Selfish requires a demonstration. I forked/cloned the repo and added a branch with a set of tests: The branch: https://github.com/rwldrn/selfish/tree/test The commit: https://github.com/rwldrn/selfish/commit/ee55af5ec00074005fa74e9d9eb4be4dc4db5163 An Object.extend() that creates an object full of references is certainly not the way to go. Rick /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 -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, Why does it matter that they don't deep copy? Deep copying is a difficult problem that needs to be standardized separately. I've personally avoided deep copying for this reason and don't use it anymore. One can accept that an extend is merely a shallow copy properties by reference, because this (although limited) behavior is easy to understand. I have a version of Object.extendhttps://github.com/Raynos/pd/blob/master/src/pd.js#L82 that is a shallow own merge. However having a deep copy mechanism that works without obscure edge-cases would be great. Of course it would be nice if we had the choice of deep vs shallow copy within the API. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
It depends on what kind of `extends` you mean: - Inheritance: Even though data being kept in prototypes is rare, it’s usually better to chain prototypes even when ignoring aliasing problems (no redundant properties, instanceof works transitively). Performance degradation should be negligible due to internal optimizations. - Merging objects: Shallow copy is the way to go. On Nov 13, 2011, at 11:08 , Jake Verbaten wrote: Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, Why does it matter that they don't deep copy? Deep copying is a difficult problem that needs to be standardized separately. I've personally avoided deep copying for this reason and don't use it anymore. One can accept that an extend is merely a shallow copy properties by reference, because this (although limited) behavior is easy to understand. I have a version of Object.extend that is a shallow own merge. However having a deep copy mechanism that works without obscure edge-cases would be great. Of course it would be nice if we had the choice of deep vs shallow copy within the API. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On 12/11/11 19:07, John J Barton wrote: This kind of discussion illustrates my point: JS is not sweet enough because we are missing core operations for constructing prototypes in a standard way. Agreed. I've always thought about JS objects as sets, but it feels weird that I don't get disjunction, intersection and other basic operations out of the box. Basically, I've missed primitives for: - Creating objects that share properties from other objects (Object.create) - Adding properties to an object (Object.extend) Object.extend(Object target, Object sources...) → Object (sources.reduce({|tgt, src| Object.keys(src).forEach({|key| tgt[key] = src[key]}) tgt }, target) Should `extend' copy all the properties? Only the own properties? I feel `own' properties make more sense. - Defining new objects that extends on the [[Prototype]], which is basically Object.create followed by copying the properties of one or more objects over to the new instance. (Object.clone? Object.inherit? I never felt `extend' quite says it all) Object.prototype.clone(Object parent, Object mixins...) → Object (Object.extend.apply(Object.create(parent), mixins)) - Merging (while possibly flattening, as objects can't have several [[Prototype]]s) objects. Object.merge(Object mixins...) → Object (x = Object.extend.apply({}, mixins)) Dicts are probably a better answer for this one though. - Creating instances from objects directly (new Stuff, Stuff.new), though I'm not sure there's much sense in having two different standard ways of doing the same thing. I guess JS is stuck with constructors =/ - Creating objects by removing/renaming certain properties from other objects, which is useful for object composition. Though I guess this would be handled by traits(?) Of course, you still need a better syntax to express it all, and the proposed extensions to object literals come close to minimalist classes: var foo = Base.clone({ method1() { }, method2() { }, get stuff() { } }) var foo = Base | { method1() { }, method2() { }, get stuff() { } } class foo extends Base { method1() { } method2() { } get stuff() { } } That is, if we disregard private and other modifiers. If such modifiers were added to the Object literal (meh?), it would be quite the same thing. Except a full-blown declarative class syntax could be better optimised and would allow for a sugary syntax if/when traits/type guards are added. var foo = Base | { #constant: 1, // or const @private_stuff: bar, // or private method1() { }, method2() { } get stuff() { } } class foo extends Base { @private_stuff: bar; // or private #constant: 1; // or const method1() { } method2() { } get stuff() { } } Except I'm not sure the @private could be made to work without creating confusing semantics around it, so object literals would still be one step behind. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
Should `extend' copy all the properties? Only the own properties? I feel `own' properties make more sense. I agree own makes more sense, we also want to specify whether we want to extend enumerable properties. Your example does not. - Defining new objects that extends on the [[Prototype]], which is basically Object.create followed by copying the properties of one or more objects over to the new instance. (Object.clone? Object.inherit? I never felt `extend' quite says it all) Object.prototype.clone(Object parent, Object mixins...) → Object (Object.extend.apply(Object.**create(parent), mixins)) I've been referring to this method as Object.makehttps://github.com/Raynos/pd/blob/master/src/pd.js#L120 it's defiantly a useful method, however I don't think clone, inherit or make are correct names for it. clone is probably the most suitable name, especially if it's on Object.prototype var foo = Base | { #constant: 1, // or const @private_stuff: bar, // or private method1() { }, method2() { } get stuff() { } } Except I'm not sure the @private could be made to work without creating confusing semantics around it, so object literals would still be one step behind. As far as I understand @private_stuff would desugar into a name object only available in scope of the object literal. var o = { @private_stuff: bar; method1() { } } var o = (function () { var private_stuff = name.create(); var ret = { method1() { } } ret[private_stuff] = bar; })(); I personally don't find that confusing. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
Except I'm not sure the @private could be made to work without creating confusing semantics around it, so object literals would still be one step behind. As far as I understand @private_stuff would desugar into a name object only available in scope of the object literal. The basic idea of private names is that you don't use names directly, but store them in a variable and use that variable whenever you need to refer to something: var _name = MyClass_private_a3cfb; function MyClass(name) { this[_name] = name; } The actual private names are very similar to _name above, but they are not strings, they are special objects that are never listed anywhere (one step beyond non-enumerable, if you will). Thus, the challenge is clear: You have to introduce variables such as _name in a manner that makes them accessible wherever you need them. var o = { @private_stuff: bar; method1() { } } var o = (function () { var private_stuff = name.create(); var ret = { method1() { } } ret[private_stuff] = bar; })(); I personally don't find that confusing. The latest ideas are about requiring a private section where you declare private_stuff. var obj = { private { private_stuff } @private_stuff: bar, method1() { return this.@private_stuff; } } It does desugar like you mention above. If you use constructor functions without any tricks, then scope is an issue: var private_stuff = name.create(); // it would be nice to have support for a private section here function MyClass(stuff) { this.@private_stuff = stuff; // same as this[private_stuff] } MyClass.prototype.method1 = function () { return this.@private_stuff; // same as this[private_stuff] } -- Dr. Axel Rauschmayer a...@rauschma.de twitter.com/rauschma Home: rauschma.de Blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Nov 13, 2011, at 5:08 AM, Jake Verbaten rayn...@gmail.com wrote: Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, Why does it matter that they don't deep copy? Deep copying is a difficult problem that needs to be standardized separately. It matters because I don't want data pollution across instances. It's not a hard problem at all, jQuery.extend() has had deep copy for years. I've personally avoided deep copying for this reason and don't use it anymore. One can accept that an extend is merely a shallow copy properties by reference, because this (although limited) behavior is easy to understand. I have a version of Object.extend that is a shallow own merge. However having a deep copy mechanism that works without obscure edge-cases would be great. Of course it would be nice if we had the choice of deep vs shallow copy within the API. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function proxies without explicit construct trap
Hi Andreas, All good points, and I don't recall any of them being intentional. Your points seem to suggest changing the semantics such that calling new fproxy() on a function proxy without a construct trap should perhaps just simply throw a TypeError. Now, in the direct proxies design, a missing [[Construct]] trap could simply forward to the [[Construct]] internal method of the target (not the call trap!). That would be cleaner (direct proxies no longer feature a virtual prototype, they reuse the target's prototype anyway) and seems to be where we were trying to take the current [[Construct]] trap default behavior. Unfortunately, since current proxies don't have a target, we chose the call trap, which isn't quite the right choice. Regarding the test case: I think it is broken (IMHO, it expects the most intuitive result. Since the current semantics don't align with that intuition, that's a good enough signal for me that we should probably change the behavior to throw a TypeError). I'll update the test case. Cheers, Tom 2011/11/10 Andreas Rossberg rossb...@google.com I think the specification of [[Construct]] for function proxies may not currently be doing what it is intended to do. If the proxy does not have a construct trap, the method simply delegates to the [[Construct]] method of the call trap. AFAICS, that has two consequences: 1. The prototype is taken from the call trap, not from the proxy. 2. If the trap returns a primitive value, that will be ignored and replaced with a freshly allocated object, as usual. It is not clear to me whether either was intended, but the former seems surprising, and the latter is inconsistent with the behaviour expected by the construct-primitive test case from http://hg.ecmascript.org/tests/harmony/. Any ideas? /Andreas ___ 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: Minimalist (why) classes ?
A few more thoughts... On Nov 13, 2011, at 5:08 AM, Jake Verbaten rayn...@gmail.com wrote: Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, Why does it matter that they don't deep copy? Deep copying is a difficult problem that needs to be standardized separately. I've personally avoided deep copying for this reason and don't use it anymore. One can accept that an extend is merely a shallow copy properties by reference, because this (although limited) behavior is easy to understand. Shallow copy is only good for one level of property lists whose assignment expressions are all primitive, anything that is a reference is going to allow the destination to mutate the source, this is wrong. I have a version of Object.extend that is a shallow own merge. However having a deep copy mechanism that works without obscure edge-cases would be great. Can you be specific? What obscure edge cases have you previously encountered? Of course it would be nice if we had the choice of deep vs shallow copy within the API. Agreed___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
However having a deep copy mechanism that works without obscure edge-cases would be great. Can you be specific? What obscure edge cases have you previously encountered? I don't have a list at hand, last time we talked about what it means to deep copy an arbitary ES-next structure we ran into questions of what it means to deep copy functions, closures and proxies. Deep copying data, i.e. anything that can be represented by JSON doesn't have too many edgecases. It would actually be nice to have an open lists of unsolved edge cases with generic deep copying. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Function proxies without explicit construct trap
On Nov 13, 2011, at 7:51 AM, Tom Van Cutsem wrote: Hi Andreas, All good points, and I don't recall any of them being intentional. Your points seem to suggest changing the semantics such that calling new fproxy() on a function proxy without a construct trap should perhaps just simply throw a TypeError. I recall a bit of intention: we wanted to default to calling the call trap with a new object bound to |this|, as is done for user-defined functions. /be Now, in the direct proxies design, a missing [[Construct]] trap could simply forward to the [[Construct]] internal method of the target (not the call trap!). That would be cleaner (direct proxies no longer feature a virtual prototype, they reuse the target's prototype anyway) and seems to be where we were trying to take the current [[Construct]] trap default behavior. Unfortunately, since current proxies don't have a target, we chose the call trap, which isn't quite the right choice. Regarding the test case: I think it is broken (IMHO, it expects the most intuitive result. Since the current semantics don't align with that intuition, that's a good enough signal for me that we should probably change the behavior to throw a TypeError). I'll update the test case. Cheers, Tom 2011/11/10 Andreas Rossberg rossb...@google.com I think the specification of [[Construct]] for function proxies may not currently be doing what it is intended to do. If the proxy does not have a construct trap, the method simply delegates to the [[Construct]] method of the call trap. AFAICS, that has two consequences: 1. The prototype is taken from the call trap, not from the proxy. 2. If the trap returns a primitive value, that will be ignored and replaced with a freshly allocated object, as usual. It is not clear to me whether either was intended, but the former seems surprising, and the latter is inconsistent with the behaviour expected by the construct-primitive test case from http://hg.ecmascript.org/tests/harmony/. Any ideas? /Andreas ___ 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 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: [Proxies] Refactoring prototype climbing in the spec
2011/11/10 Allen Wirfs-Brock al...@wirfs-brock.com On Nov 10, 2011, at 9:03 AM, Tom Van Cutsem wrote: Regarding property deletion: if an object is implemented as a proxy, and you would want to delete a property from that object, I'm not sure why you would want to circumvent triggering the delete trap? In http://wiki.ecmascript.org/doku.php?id=strawman:object_model_reformation I'm exploring explicitly distinguishing the semants of obj.propName and obj[expression] such that an object can explicitly define its obj[expression] behaviors without using a Proxy (note that currently by the time a Proxy is called, the distinction is already lost so even if you wanted to use a Proxy for this purpose they may not be adequate). In many cases (including the default), the object-specific handler for obj[expression] will delegate back to Object.getProperty/Object.setProperty (either directly or via a super call). But note that it can do so via direct [ ] syntax, as that would loop. This can actually all be modeled with a new Reference variant within the spec. that distinguishes . references from [ ] references. However, I also need to account for the delete operator and distinguish delete obj.propName from delete obj[expression] . This can be taken care of by the same reference extension (essentially References needs a delete method). A handler for deleting obj[expression]] may also want to delegate back to normal property deletion and for the same reason as for obj[exper] get/set handlers it can't directly use the syntactic form. Instead it needs to call an Object.deleteProperty function. Understood. BTW, rather than adding these methods to Object, I'm beginning to think it might be better to import them from a built-in reflection module. Indeed. Perhaps that built-in reflection module could be the same module that defines the default forwarding handler. Your note that we need an Object.deleteProperty method apart from the built-in syntax reminded me that the default forwarding handler for proxies is really all about providing method-based alternatives to things that can currently only be achieved through built-in syntax. In the direct proxies proposal, I proposed defining a Proxy.forward object that enables forwarding all operations interceptable by proxies to another object. A prototype implementation of it exists here: http://code.google.com/p/es-lab/source/browse/trunk/src/proxies/DirectProxies.js#1250 If you observe closely, you'll note that the default forwarding API is really the dual of the Proxy API. Proxies uniformly turn all sorts of operations on objects (whether triggered through syntax or built-in methods) into trap invocations, for instance: Object.getOwnPropertyDescriptor(proxy, name) = handler.getOwnPropertyDescriptor(name, target) name in proxy = handler.has(name, target) etc. The default forwarding API turns these trap invocations back into the original operations: Proxy.forward.getOwnPropertyDescriptor(name, target) = Object.getOwnPropertyDescriptor(target, name); Proxy.forward.has(name, target) = name in target etc. That's why the forwarding API is crucial for double lifting to work: if a handler is itself a proxy, then to intercept handler[trapName], we need to be able to generically forward the operation, which is made possible by writing Proxy.forward[trapName]. I proposed the name Proxy.forward since that looks very natural when writing handler code that simply wants to augment the default behavior: funtion makeChangeLogger(target) { return Proxy.for(target, { set: function(receiver, name, value, target) { log('property '+name+' on '+target+' set to '+value); return Proxy.forward.set(receiver, name, value, target); } });} However, it now seems to me that the methods encapsulated by Proxy.forward can be more generally useful for arbitrary meta-programming, not just for forwarding in the case of proxies. I see an opportunity here to kill two birds with one stone: we can introduce a reflection module (assume it's called Reflect for now) that contains the Proxy.forward methods. That would: a) obviate the need for Object.deleteProperty (now named Reflect.delete), Object.getProperty (Reflect.get) and Object.setProperty (Reflect.set). b) obviate the need for Proxy.forward (the above code snippet would call Reflect.set instead, which is even shorter) The design guideline for this Reflect module would be that the methods it exposes have _exactly_ the same name + parameter list as the Proxy API trap names. Not only does this retain consistency, it also enables easy double lifting (or perhaps other design patterns that want to treat operations on objects / Proxy traps generically). Cheers, Tom ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Nov 13, 2011, at 11:03 AM, Jake Verbaten rayn...@gmail.com wrote: However having a deep copy mechanism that works without obscure edge-cases would be great. Can you be specific? What obscure edge cases have you previously encountered? I don't have a list at hand, last time we talked about what it means to deep copy an arbitary ES-next structure we ran into questions of what it means to deep copy functions, closures and proxies. Can you point me to existing discussion threads? Deep copying data, i.e. anything that can be represented by JSON doesn't have too many edgecases. It would actually be nice to have an open lists of unsolved edge cases with generic deep copying. This would definitely be useful.___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Sun, Nov 13, 2011 at 4:51 PM, Rick Waldron waldron.r...@gmail.comwrote: On Nov 13, 2011, at 11:03 AM, Jake Verbaten rayn...@gmail.com wrote: However having a deep copy mechanism that works without obscure edge-cases would be great. Can you be specific? What obscure edge cases have you previously encountered? I don't have a list at hand, last time we talked about what it means to deep copy an arbitary ES-next structure we ran into questions of what it means to deep copy functions, closures and proxies. Can you point me to existing discussion threads? The only thing I can find is https://mail.mozilla.org/pipermail/es-discuss/2011-October/017337.html This particular thread talked about | and how to make it work on object references rather then object literals. Since | returns a new object it would have to clone the object reference in some correct manner. Deep copying data, i.e. anything that can be represented by JSON doesn't have too many edgecases. It would actually be nice to have an open lists of unsolved edge cases with generic deep copying. This would definitely be useful. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Nov 13, 2011, at 9:24 AM, Jake Verbaten wrote: On Sun, Nov 13, 2011 at 4:51 PM, Rick Waldron waldron.r...@gmail.com wrote: On Nov 13, 2011, at 11:03 AM, Jake Verbaten rayn...@gmail.com wrote: However having a deep copy mechanism that works without obscure edge-cases would be great. Can you be specific? What obscure edge cases have you previously encountered? I don't have a list at hand, last time we talked about what it means to deep copy an arbitary ES-next structure we ran into questions of what it means to deep copy functions, closures and proxies. Can you point me to existing discussion threads? The only thing I can find is https://mail.mozilla.org/pipermail/es-discuss/2011-October/017337.html Quoting with s/identify/identity/g: No, generalized object clone is relatively hard. Some other issues: It isn't just the [[Class]] internal property. It is all the other representational and behavior invariants implied by [[Class]] What if the object is a Proxy instance? How should private name properties be handled. What if there are identity based internal state relationships within the object. What if there are identity bases external relationships about the object (eg, it's used as a key in a WeakMap) etc. In other language clone has generally evolved into a little frame that allows application level control of some or all of these decisions. I'm not saying that some sort of generalized clone wouldn't be useful. Just that it's not so simple. Allen This particular thread talked about | and how to make it work on object references rather then object literals. Since | returns a new object it would have to clone the object reference in some correct manner. Deep copying data, i.e. anything that can be represented by JSON doesn't have too many edgecases. It would actually be nice to have an open lists of unsolved edge cases with generic deep copying. This would definitely be useful. See above! The hard cases include: 1. Closures. 2. Proxies. 3. Private names. 4. Internal hidden state. 5. Side-table entries mapped to the object's identity. /be___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Nov 13, 2011, at 9:30 AM, Brendan Eich wrote: The hard cases include: 1. Closures. 2. Proxies. 3. Private names. 4. Internal hidden state. 5. Side-table entries mapped to the object's identity. In the case of objects implemented by C++ or whatever the host implementation language might be, the internal or side-table state may not even be representable in JS, even in strings (do not want raw pointers, or machine addresses however obfuscated, to leak to an attacker). /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard @iter module unfriendly to collection builders
Another thing to consider is whether these functions belong in an iter module or in a reflect module? I'm leaning towards the letter. On Nov 12, 2011 12:05 PM, Brendan Eich bren...@mozilla.com wrote: On Nov 12, 2011, at 11:26 AM, Allen Wirfs-Brock wrote: The Iterators proposal includes the definition ( http://wiki.ecmascript.org/doku.php?id=harmony:iterators#standard_api ) of functions that are intended to support various common iteration patterns. For example, for ((k of keys(x)) { ...} for (v of values(x)) { ...} for ([k,v] of items(x)) {...} for (k of allKeys(x)) { ...} for (k of allValues(x)) { ...} for (i of allItems(x)) { ...} The use of these functions seems to be pretty much an essential part of the intended use of the for-of statement. The prior question is what, if anything, for (x of y) ... // and [x for x of y], etc. means. Should it throw if there's no @iterator private-named property in y *and* y is not a Proxy with an iterate trap? That is our current thinking. It may not be reflected well in the wiki. The alternative is to iterate over property values of an object denoted y that has no unstratified @iterator or stratified handler iterate trap. But that is hostile to collections and your [] proposal. OTOH I see no problem for collection writers if we make for-of throw on untrapped objects. Collection authors would bind @iterator, @elementGet, and @elementSet. Life would be grand. Right? /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: Minimalist (why) classes ?
On Sun, Nov 13, 2011 at 7:42 AM, Rick Waldron waldron.r...@gmail.com wrote: On Nov 13, 2011, at 5:08 AM, Jake Verbaten rayn...@gmail.com wrote: Neither of them are fit for standardization. Selfish and Prototype are both incapable of correctly deep copying arrays or objects, Why does it matter that they don't deep copy? Deep copying is a difficult problem that needs to be standardized separately. It matters because I don't want data pollution across instances. It's not a hard problem at all, jQuery.extend() has had deep copy for years. Just a couple of observations: 1) There are two different issues here: flatten vs retain [[Prototype]] links and shallow vs deep copy. 2) I think the choice should be different for methods and data. The first order effect of inheritance is to re-use methods; for this purpose shallow copies and re-use by [[Prototype]] links works well. However, if you adopt shallow copies or re-use by [[Prototype]] links, the non-method data is copied by reference, causing write onto derived objects to write onto ancestor object values. This is only rarely the desired outcome. In Gonzala's selfish and in his gist, I believe the implicit assumption is that developers should adopt a pattern of use: ancestor class objects will have only function properties. The |initialize| method will define data properties. In this way the shallow copy and the use of [[Prototype]] links works for the methods and the data is chained through calls to ancestor initialize(). I think this is also implicit in Object.create(): LHS object is expected to be a pile of methods. This makes a lot of sense and it meshes well with class-thinking. What it says is: adopt a different strategy for methods and for data. For methods, retain the [[Prototype]] links; for data, flatten. The first-order effect is the same as old PrototypeJS solution but the second order effect, data in [[Prototype]] links vs data on the object, is different. No, I do not have a concrete proposal. But it seems to me that Gonzala's gist extend() should attach the data properties to the instance not the type. It only matters when the inputs have data properties and in that case you probably don't want them on the [[Prototype]] linked object. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard @iter module unfriendly to collection builders
On Nov 13, 2011, at 10:17 AM, Erik Arvidsson wrote: Another thing to consider is whether these functions belong in an iter module or in a reflect module? I'm leaning towards the letter. Does it matter, apart from the name? I'd rather have more and more precisely defined modules than one reflect dumping ground. JS has built-in reflection, from day 1, arguably overloaded with base-level operations but part of the package deal. We won't be factoring all such unstratified reflection out. The @iter name is short and Python-inspired, it should match for-of loops, comprehensions, and generators. It could grow too large, but it wouldn't be larger than @reflect. If we end up with a standard prelude, some of these helpers could be imported by it. /be On Nov 12, 2011 12:05 PM, Brendan Eich bren...@mozilla.com wrote: On Nov 12, 2011, at 11:26 AM, Allen Wirfs-Brock wrote: The Iterators proposal includes the definition (http://wiki.ecmascript.org/doku.php?id=harmony:iterators#standard_api ) of functions that are intended to support various common iteration patterns. For example, for ((k of keys(x)) { ...} for (v of values(x)) { ...} for ([k,v] of items(x)) {...} for (k of allKeys(x)) { ...} for (k of allValues(x)) { ...} for (i of allItems(x)) { ...} The use of these functions seems to be pretty much an essential part of the intended use of the for-of statement. The prior question is what, if anything, for (x of y) ... // and [x for x of y], etc. means. Should it throw if there's no @iterator private-named property in y *and* y is not a Proxy with an iterate trap? That is our current thinking. It may not be reflected well in the wiki. The alternative is to iterate over property values of an object denoted y that has no unstratified @iterator or stratified handler iterate trap. But that is hostile to collections and your [] proposal. OTOH I see no problem for collection writers if we make for-of throw on untrapped objects. Collection authors would bind @iterator, @elementGet, and @elementSet. Life would be grand. Right? /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: Minimalist (why) classes ?
On Sun, Nov 13, 2011 at 9:34 AM, Brendan Eich bren...@mozilla.com wrote: On Nov 13, 2011, at 9:30 AM, Brendan Eich wrote: The hard cases include: 1. Closures. 2. Proxies. 3. Private names. 4. Internal hidden state. 5. Side-table entries mapped to the object's identity. In the case of objects implemented by C++ or whatever the host implementation language might be, the internal or side-table state may not even be representable in JS, even in strings (do not want raw pointers, or machine addresses however obfuscated, to leak to an attacker). I think we are on the wrong path here. I guess we followed: a standard extend() needs a copy-ish operation; a copyish operation is like cloning; cloning is hard; OMG. But let's back up. We are looking for one or a few operations such that: var a = op(b,c,d,...); creates a useful result when we use |a| and we are using existing JS libraries for guidance. By definition there are no show stoppers here. We are creating new objects from existing objects using operations available to JS devs, but in standard and recommended way. The only two things can stop us from being successful: irreconcilable differences and inertia. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Sun, Nov 13, 2011 at 2:36 AM, Axel Rauschmayer a...@rauschma.de wrote: It depends on what kind of `extends` you mean: - Inheritance: Even though data being kept in prototypes is rare, it’s usually better to chain prototypes even when ignoring aliasing problems (no redundant properties, instanceof works transitively). Performance degradation should be negligible due to internal optimizations. - Merging objects: Shallow copy is the way to go. Perhaps you mean: 'it depends on the use of the object returned by |extends()|'. But I don't understand your categories. Mine: Object-like: you want to use the returned object directly. I think a dev imagines extend() as a kind of initialization, a merger operation: var a = merge(b,c,d); In this case you do not expect deep copy, you expect shallow, reference copy. If I change d.color, I expect that a.color is changed. Or rather, I would say that a dev would not be surprised at this behavior. Class-like: you want to use the returned object indirectly, to create other objects via Foo.prototype/new Foo or similar operation. Here we are operating on two levels. In the abstract level we are combining objects to define factory; in the concrete level we are creating objects based on that factory. The data on the inputs to the abstract level are -- at most -- relevant as initial values for the concrete level. You want something like deep copy. As I mentioned elsewhere, the Object-like merge can be used (with care) on collections of methods then applied to Foo.prototype. That's how we get along now: one operation covers both cases just not always robustly. jjb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
I think this discussion drifted into slightly diff direction. What I intended to say was that today all major frameworks use same patter to do subclassing. They all implement different APIs to do the following: function subclass() { // init …. } subclass.prototype = Object.create(superclass) Object.defineProperty(subclass.prototype, 'constructor', { value: subclass }) subclass.prototype.method = function() { //... } Object.extend used in my gist is BTW same as backbone's .extend and is just a shortcut of the code above: var subclass = superclass.extend({ initialize: function() { // init ... }, method: function() { // …. } }) What I'm asking for is a standard function, no matter weather it's `Object.extend` or something else that makes it simple to do subclassing. Also lisper in me thinks that `Object.extend` method is better than dedicated class syntax cause it keeps language concise. In addition I think that if `Object.extend` will turn out to be broken it will be easier (not to say easy) to fix (`Object.extend = … `) then fixing `class Foo extends Bar`. Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ Address: 29 Rue Saint-Georges, 75009 Paris, France (http://goo.gl/maps/3CHu) On Sunday, 2011-11-13 at 13:21 , Brendan Eich wrote: On Nov 13, 2011, at 11:28 AM, John J Barton wrote: On Sun, Nov 13, 2011 at 9:34 AM, Brendan Eich bren...@mozilla.com (mailto:bren...@mozilla.com) wrote: On Nov 13, 2011, at 9:30 AM, Brendan Eich wrote: The hard cases include: 1. Closures. 2. Proxies. 3. Private names. 4. Internal hidden state. 5. Side-table entries mapped to the object's identity. In the case of objects implemented by C++ or whatever the host implementation language might be, the internal or side-table state may not even be representable in JS, even in strings (do not want raw pointers, or machine addresses however obfuscated, to leak to an attacker). I think we are on the wrong path here. I guess we followed: a standard extend() needs a copy-ish operation; a copyish operation is like cloning; cloning is hard; OMG. That's not what happened. Some people are happy with shallow copy of properties available to ES5 reflection, or even a for-in loop. Others (Rick?) want deep, at least as an option. Deep could skip any private/internal/etc. properties, for sure. But deep tends to get into trouble because if you don't stay shallow, you run immediately into item 1: Closures. How would those be deeply copied, including their lexical environments? But let's back up. We are looking for one or a few operations such that: var a = op(b,c,d,...); creates a useful result when we use |a| and we are using existing JS libraries for guidance. By definition there are no show stoppers here. I agree, other than inability to agree on what to standardize. We are creating new objects from existing objects using operations available to JS devs, but in standard and recommended way. The only two things can stop us from being successful: irreconcilable differences and inertia. Ok, but this is all meta-pep-talk. What should the reconcilable standard be? /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: Minimalist (why) classes ?
On Friday, 2011-11-11 at 18:38 , Brendan Eich wrote: Having written all this, I will repeat that I like your selfish work and the exemplar idea Thanks, that's really encouraging! ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: An array destructing specification choice
On Nov 12, 2011, at 4:25 PM, Axel Rauschmayer wrote: There is no requirement that ...r consume 1 element, It consumes 0 elements above. Sorry, misread your example -- we seem to agree that if there aren't enough elements, r gets a fresh empty array. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Minimalist (why) classes ?
On Nov 13, 2011, at 9:42 PM, Irakli Gozalishvili wrote: I think this discussion drifted into slightly diff direction. What I intended to say was that today all major frameworks use same patter to do subclassing. They all implement different APIs to do the following: function subclass() { // init …. } subclass.prototype = Object.create(superclass) Object.defineProperty(subclass.prototype, 'constructor', { value: subclass }) subclass.prototype.method = function() { //... } Yes, this is the heart of the matter. Not freezing, not shallow vs. deep property copying (where deep must deal with closures at least). Object.extend used in my gist is BTW same as backbone's .extend Ok, good to know. (Jashkenas, you didn't propose it!) and is just a shortcut of the code above: var subclass = superclass.extend({ initialize: function() { // init ... }, method: function() { // …. } }) What I'm asking for is a standard function, no matter weather it's `Object.extend` or something else that makes it simple to do subclassing. Allen has been trying to make it be a combo of | and .{. Agree there could be a method, say Object.subclass (what a concept!). Also lisper in me thinks that `Object.extend` method is better than dedicated class syntax cause it keeps language concise. Sorry, JS isn't LISP. In addition I think that if `Object.extend` will turn out to be broken it will be easier (not to say easy) to fix (`Object.extend = … `) then fixing `class Foo extends Bar`. It would be about as hard either way. /be Regards -- Irakli Gozalishvili Web: http://www.jeditoolkit.com/ Address: 29 Rue Saint-Georges, 75009 Paris, France On Sunday, 2011-11-13 at 13:21 , Brendan Eich wrote: On Nov 13, 2011, at 11:28 AM, John J Barton wrote: On Sun, Nov 13, 2011 at 9:34 AM, Brendan Eich bren...@mozilla.com wrote: On Nov 13, 2011, at 9:30 AM, Brendan Eich wrote: The hard cases include: 1. Closures. 2. Proxies. 3. Private names. 4. Internal hidden state. 5. Side-table entries mapped to the object's identity. In the case of objects implemented by C++ or whatever the host implementation language might be, the internal or side-table state may not even be representable in JS, even in strings (do not want raw pointers, or machine addresses however obfuscated, to leak to an attacker). I think we are on the wrong path here. I guess we followed: a standard extend() needs a copy-ish operation; a copyish operation is like cloning; cloning is hard; OMG. That's not what happened. Some people are happy with shallow copy of properties available to ES5 reflection, or even a for-in loop. Others (Rick?) want deep, at least as an option. Deep could skip any private/internal/etc. properties, for sure. But deep tends to get into trouble because if you don't stay shallow, you run immediately into item 1: Closures. How would those be deeply copied, including their lexical environments? But let's back up. We are looking for one or a few operations such that: var a = op(b,c,d,...); creates a useful result when we use |a| and we are using existing JS libraries for guidance. By definition there are no show stoppers here. I agree, other than inability to agree on what to standardize. We are creating new objects from existing objects using operations available to JS devs, but in standard and recommended way. The only two things can stop us from being successful: irreconcilable differences and inertia. Ok, but this is all meta-pep-talk. What should the reconcilable standard be? /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