Your search - "|>" - did not match any documents
The page you want is harmony:proto_operator It suggests pronouncing it as "prototype of". However, in most conversations I've been in we've called it triangle.
the proposed operator symbol is <| not |>
On Wed, Oct 12, 2011 at 5:52 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
The page you want is harmony:proto_operator
Thanks! Cool, in my uninformed opinion this operator is what Object.create() should have been.
It suggests pronouncing it as "prototype of". However, in most conversations I've been in we've called it triangle.
var nObj = p <| {name: 'foo'}; "p overwritesThePrototypeIn {name:'foo'}"
Array.create=function(proto,props) {return Object.defineProperties(proto <| [ ], props)};
"proto overwritesThePrototypeIn []"
let subclass = superclass <| function () {}; 'superclass overwritesThePrototypeIn an anonymous empty function
I guess overwritiesPrototype is descriptive. prototypeOf sounds like extraction to me, but likely to be the choice in the end. " p triangle {name:'foo'}" I don't think so.
the proposed operator symbol is <| not |>
I suppose you'd have more luck with folks like me if you called it Object.createSimple(). Then when we whined about the name being long, slip <| in on us.
jjb
On 10/12/2011 07:57 PM, John J Barton wrote:
On Wed, Oct 12, 2011 at 5:52 PM, Allen Wirfs-Brock <allen at wirfs-brock.com <mailto:allen at wirfs-brock.com>> wrote:
The page you want is http://wiki.ecmascript.org/doku.php?id=harmony:proto_operator
Thanks! Cool, in my uninformed opinion this operator is what Object.create() should have been.
I agree, and the current Object.create should be Object.createFromPropertyDescriptors. But I could settle for newHeir or makeHeir.
It suggests pronouncing it as "prototype of". However, in most conversations I've been in we've called it triangle.
var nObj = p <| {name: 'foo'}; "p overwritesThePrototypeIn {name:'foo'}"
I think of it as the (make/new) heir operator, and read that code "nObj gets p's (new) heir the object with name 'foo'"
Array.create=function(proto,props) {return Object.defineProperties(proto<|[ ], props)};
"proto overwritesThePrototypeIn []" "proto's new heir the empty array"
let subclass = superclass<|function () {};
'superclass overwritesThePrototypeIn an anonymous empty function "let subclass be superclass' heir, an empty function."
Jay
Whilst mentioning Object.createSimple, is there any plan for having matching functions for all this declaritive syntax?
On Oct 13, 2011 8:17 AM, "Jay Skeer" <jpp at seanet.com> wrote:
**
On 10/12/2011 07:57 PM, John J Barton wrote: > > On Wed, Oct 12, 2011 at
5:52 PM, Allen Wirfs-Brock ... I agree, and the current Object.create should be Object.createFromPropertyDescriptors. But I could settle for newHeir or makeHeir.
It suggests pronouncing it as "prototype of". However, in most
conversations I've been in we'v... I think of it as the (make/new) heir operator, and read that code "nObj gets p's (new) heir the object with name 'foo'"
Array.create=function(proto,props) {return Object.defineProperties(proto <| [ ], props)}; > > > ... "proto's new heir the empty array"
let subclass = superclass <| function () {}; > > 'superclass
overwritesThePrototypeIn an ano... "let subclass be superclass' heir, an empty function."
Jay
On Oct 13, 2011, at 3:59 AM, Jake Verbaten wrote:
Whilst mentioning Object.createSimple, is there any plan for having matching functions for all this declaritive syntax?
We do not want functions that mutate the [[Prototype]] internal property of existing objects. See
Quote (with correction, s/can/cannot/):
"Another difference from the function approach is that the function cannot assume it is being passed a new object or even any object of the kind it is expect. The <| ooperator is syntactically required in the current proposal to have a literal form as its right operand so both implementations and human code readers can determine by examination what [[Class]] of object is being created."
On Thu, Oct 13, 2011 at 12:08 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 3:59 AM, Jake Verbaten wrote:
Whilst mentioning Object.createSimple, is there any plan for having matching functions for all this declaritive syntax?
We do not want functions that mutate the [[Prototype]] internal property of existing objects. See
Quote (with correction, s/can/cannot/):
"Another difference from the function approach is that the function can* not* assume it is being passed a new object or even any object of the kind it is expect. The <| ooperator is syntactically required in the current proposal to have a literal form as its right operand so both implementations and human code readers can determine by examination what [[Class]] of object is being created."
I'm sure that was a typo but ooperator could be a really clever name for <| syntax :)
Could the problem of mutating the [[Prototype]] not be solved by returning a new object with the [[Prototype]] set as the LHS and having the same [[Class]] and own properties as the RHS. I would change the semantics slightly.
The only forseeable issue is how to handle closures.
On Thu, Oct 13, 2011 at 9:08 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 3:59 AM, Jake Verbaten wrote:
Whilst mentioning Object.createSimple, is there any plan for having matching functions for all this declaritive syntax?
We do not want functions that mutate the [[Prototype]] internal property of existing objects. See
Quote (with correction, s/can/cannot/):
"Another difference from the function approach is that the function can* not* assume it is being passed a new object or even any object of the kind it is expect. The <| ooperator is syntactically required in the current proposal to have a literal form as its right operand so both implementations and human code readers can determine by examination what [[Class]] of object is being created."
But literal RHS makes the prototypeOverwrite operator <| dramatically less useful and not JavaScripty. I want to compose objects: var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args); With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
jjb
On Oct 13, 2011, at 12:43 PM, John J Barton wrote:
But literal RHS makes the prototypeOverwrite operator <| dramatically less useful and not JavaScripty.
Nice assertions.
First, mutable proto is in four of five browsers and IE is tempted to support (developers want it). <| is the reformed version of mutable proto that serves the main use-case: presetting [[Prototype]] of a fresh object of any class that has a literal form.
I want to compose objects: var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args);
You want something else, then. Just because you want B does not mean A is useless or less useful or not JavaScripty.
With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
Object.extend is on the agenda. It's not the same as <|. Two different tools for two or more different jobs.
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
On Oct 13, 2011, at 12:43 PM, John J Barton wrote:
But literal RHS makes the prototypeOverwrite operator <| dramatically less useful and not JavaScripty.
Nice assertions.
First, mutable proto is in four of five browsers and IE is tempted to support (developers want it). <| is the reformed version of mutable proto that serves the main use-case: presetting [[Prototype]] of a fresh object of any class that has a literal form.
Hrm. Lost my "Second".
I was making an argument about utility based on the proto de-facto standard. That addressed "less useful".
For "non JavaScripty" I was thinking of saying "is too!" but that's just a counter-assertion ;-). Really, proto is controversial in full but not in concept, so long as mutating an existing object's [[Prototype]] is disallowed.
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
Anyway, it seems to me proto is out there in most JS engines. It's used enough that IE feels some heat to support. It is therefore "pretty useful" and "de-facto JavaScripty".
But the more important thing to say is that proto use-cases that do not mutate [[Prototype]] of an old-born object are legitimate. One such use-case is "array with custom prototype".
On Oct 13, 2011, at 9:42 AM, Jake Verbaten wrote:
Could the problem of mutating the [[Prototype]] not be solved by returning a new object with the [[Prototype]] set as the LHS and having the same [[Class]] and own properties as the RHS. I would change the semantics slightly.
The only forseeable issue is how to handle closures.
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 identify based internal state relationships within the object. What if there are identify 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.
Another strong use-case is functions with a custom prototype.
I would love to build whole apis with callable objects with their own prototype chains.
On Oct 13, 2011 6:29 PM, "Brendan Eich" <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote: > On Oct 13, 2011, at 12:43
PM, John J Barton wrot... Hrm. Lost my "Second".
I was making an argument about utility based on the proto de-facto standard. That addressed "less useful".
For "non JavaScripty" I was thinking of saying "is too!" but that's just a counter-assertion ;-). Really, proto is controversial in full but not in concept, so long as mutating an existing object's [[Prototype]] is disallowed.
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
Anyway, it seems to me proto is out there in most JS engines. It's used enough that IE feels some heat to support. It is therefore "pretty useful" and "de-facto JavaScripty".
But the more important thing to say is that proto use-cases that do not mutate [[Prototype]] of an old-born object are legitimate. One such use-case is "array with custom prototype".
/be
I want to compose objects: >> var result = cookUpTheBehavior(goodies,
stuff) <| initializ...
On Thu, Oct 13, 2011 at 10:29 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
...
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
I guess this is a performance argument? (I don't buy then) Or is it just
harder to spec the copy ? (but extend needs the same logic) Or?
But the more important thing to say is that proto use-cases that do not mutate [[Prototype]] of an old-born object are legitimate.
One such use-case is "array with custom prototype".
To be honest the "subclassing of builtin" examples that are cited for <| do not motivate. Perhaps you are just assuming that the new feature will work for normal devs and are trying to illustrate that it has even more power.
I want to compose objects: var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args);
You want something else, then. Just because you want B does not mean A is useless or less useful or not JavaScripty.
With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
Object.extend is on the agenda. It's not the same as <|. Two different tools for two or more different jobs.
I want these two tools to work together! I want a standard property cloner and a composition operation that creates objects from a behavior object and data object. Wouldn't that be nice?
jjb
On Oct 13, 2011, at 2:19 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 10:29 AM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
... Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
I guess this is a performance argument? (I don't buy then)
No, the semantics observably differ. Object.setPrototypeOf follows the "set" convention that suggests it mutates the [[Prototype]] of its first parameter, but TC39 won't agree to mutate existing objects' [[Prototype]] internal property values, even though many engines support that via writable proto.
So let's say we call the function Object.make. Then consider:
let o1 = {q: 99}; let o2 = Object.make({p: 27}, o1); assert(o2 !== o1); o2.q = 100; assert(o1.q === 99);
That's not how <| works. If you still think such an Object.make is useful, we can debate that. But it's not obvious that we need yet another Object method, if it is not equivalent to <|, and in light of Object.extend.
Or is it just harder to spec the copy ? (but extend needs the same logic) Or?
The case for copy-with-[[Prototype]]-preset has not been made until just recently. There's no precedent in the field (writable proto is used to preset without making a copy). We don't have a strawman.
To be honest the "subclassing of builtin" examples that are cited for <| do not motivate. Perhaps you are just assuming that the new feature will work for normal devs and are trying to illustrate that it has even more power.
No, those are real use-cases!
YMMV but we didn't get here by making stuff up that developers don't already do via proto hacks.
I want to compose objects: var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args);
You want something else, then. Just because you want B does not mean A is useless or less useful or not JavaScripty.
With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
Object.extend is on the agenda. It's not the same as <|. Two different tools for two or more different jobs.
I want these two tools to work together! I want a standard property cloner and a composition operation that creates objects from a behavior object and data object. Wouldn't that be nice?
I'm not saying B, but not A. I am saying A (your clone with new proto) is neither clearly justified based on de-facto standards, nor well-specified. See Allen's reply about cloning issues.
On Thu, Oct 13, 2011 at 11:51 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 2:19 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 10:29 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
...
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
I guess this is a performance argument? (I don't buy then)
No, the semantics observably differ. Object.setPrototypeOf follows the "set" convention that suggests it mutates the [[Prototype]] of its first parameter, but TC39 won't agree to mutate existing objects' [[Prototype]] internal property values, even though many engines support that via writable proto.
(Sorry, I misplaced my comment, I have none about setPrototypeOf)
So let's say we call the function Object.make. Then consider:
let o1 = {q: 99}; let o2 = Object.make({p: 27}, o1); assert(o2 !== o1); o2.q = 100; assert(o1.q === 99);
That's not how <| works.
Darn, now I'm lost again. I would have said "That's how <| works" :-( I would have said o2 = {p:27} <| o1; // aka Object.make() o2 is {q:99, [[ProtoLink]]: {p:27}} so o2 !== o1 true o2.q = 100; o2 is now {q:100, [[ProtoLink]]:{p:27}} o1.q === 99 true, but irrelevant Obviously I've misunderstood something. jjb
On Thu, Oct 13, 2011 at 3:13 PM, John J Barton <johnjbarton at johnjbarton.com>wrote:
On Thu, Oct 13, 2011 at 11:51 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Oct 13, 2011, at 2:19 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 10:29 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
...
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
I guess this is a performance argument? (I don't buy then)
No, the semantics observably differ. Object.setPrototypeOf follows the "set" convention that suggests it mutates the [[Prototype]] of its first parameter, but TC39 won't agree to mutate existing objects' [[Prototype]] internal property values, even though many engines support that via writable proto.
(Sorry, I misplaced my comment, I have none about setPrototypeOf)
So let's say we call the function Object.make. Then consider:
let o1 = {q: 99}; let o2 = Object.make({p: 27}, o1); assert(o2 !== o1); o2.q = 100; assert(o1.q === 99);
That's not how <| works.
Darn, now I'm lost again. I would have said "That's how <| works" :-( I would have said o2 = {p:27} <| o1; // aka Object.make() o2 is {q:99, [[ProtoLink]]: {p:27}} so o2 !== o1 true o2.q = 100; o2 is now {q:100, [[ProtoLink]]:{p:27}} o1.q === 99 true, but irrelevant Obviously I've misunderstood something.
Simply stated, the triangle operator lets you set the prototype of an object if and only if that object has not yet been observably instantiated. It's a small tradeoff, but it gives us many of the benefits of mutable protos without the known hazards.
[snip]
I want to compose objects:
var result = cookUpTheBehavior(goodies, stuff) <| initializeTheState(args);
You want something else, then. Just because you want B does not mean A is useless or less useful or not JavaScripty.
With a decent Object.extend() we'd have a clean way to build objects without having to look up Crockford's web pages every time we try a different variation.
Object.extend is on the agenda. It's not the same as <|. Two different tools for two or more different jobs.
I want these two tools to work together! I want a standard property cloner and a composition operation that creates objects from a behavior object and data object. Wouldn't that be nice?
I agree with this - at least in the sense that I think it might be an appropriate time to take a higher level perspective of all the aspects of JavaScript object definition and reuse. That seems to be a lot of what is being discussed now from class literals to the <| operator to new <Object>
to traits. I understand the value of decomposing these ideas down into orthogonal part which can be used independently and combined to create a variety of useful abstractions. However, I think that creating something cohesive is really important, and in the end we will want to provide a clear path for the common cases.
I find it a problem that there is a standard pattern in JavaScript for creating "classes" but there isn't a real name for it. We have constructor functions and prototypes. Even the Rhino book is forced to say, "For lack of a better term, I will use the word "class" informally in this chapter." Then if you want to extend one of these things, you'll have to basically resort to a library or some recipe of your own. It's black magic. And worse, all the built-ins use the pattern, so we're basically going to have it around forever.
I understand that this is sort of what <| is for, and it is potentially what class literals are for, I guess my point is just that I think it should be a high priority for es.next to result in some definitive way of saying:
- create a thing Foo, including its constructor and at the very least methods (including get/set methods)
- create a Bar that extends Foo, including its constructor...
This is what Coffeescript provides with class and extend. I get the feeling that using class would be too loaded. If class is going to be used it sounds like people would like more than to have sugar for the existing pattern, they would like more and they don't want to harm future proposals. I think this is fair so I would say take the word "class" off the table. This is the reason I had previously proposed <| as more of a generic extension operator. It's already doing a lot of magic when it comes to functions and arrays.
I'm not sure exactly what the answer is, I'll try to think of something better to propose, I just feel like hashing out the individual pieces like <| and .{ and Object.extend etc. are all discussions that are worse off for not discussing how they should all work together.
On Oct 13, 2011, at 3:13 PM, John J Barton wrote:
Darn, now I'm lost again. I would have said "That's how <| works" :-( I would have said o2 = {p:27} <| o1; // aka Object.make()
No, <| does not accept non-literal RHS forms.
That's intentional and that's the whole difference.
On Thu, Oct 13, 2011 at 12:59 PM, Dean Landolt <dean at deanlandolt.com> wrote:
On Thu, Oct 13, 2011 at 3:13 PM, John J Barton < johnjbarton at johnjbarton.com> wrote:
On Thu, Oct 13, 2011 at 11:51 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Oct 13, 2011, at 2:19 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 10:29 AM, Brendan Eich <brendan at mozilla.com>wrote:
On Oct 13, 2011, at 1:17 PM, Brendan Eich wrote:
...
Object.getPrototypeOf is the "get" API in ES5. For the "preset" API we want syntax at least, to avoid copying literals passed to a functional API. We could have the functional API too but it differs in making a copy of whatever object is passed in as the "RHS", as Jake just wrote. It would not be Object.setPrototypeOf.
I guess this is a performance argument? (I don't buy then)
No, the semantics observably differ. Object.setPrototypeOf follows the "set" convention that suggests it mutates the [[Prototype]] of its first parameter, but TC39 won't agree to mutate existing objects' [[Prototype]] internal property values, even though many engines support that via writable proto.
(Sorry, I misplaced my comment, I have none about setPrototypeOf)
So let's say we call the function Object.make. Then consider:
let o1 = {q: 99}; let o2 = Object.make({p: 27}, o1); assert(o2 !== o1); o2.q = 100; assert(o1.q === 99);
That's not how <| works.
Darn, now I'm lost again. I would have said "That's how <| works" :-( I would have said o2 = {p:27} <| o1; // aka Object.make() o2 is {q:99, [[ProtoLink]]: {p:27}} so o2 !== o1 true o2.q = 100; o2 is now {q:100, [[ProtoLink]]:{p:27}} o1.q === 99 true, but irrelevant Obviously I've misunderstood something.
Sorry I misunderstood was Brendan's comment "That's not how <| works". He meant "Such an Object.make() would be similar to <| but <| intentionally requires literal RHS." I thought me meant "even if <| allowed object on the RHS it still would not work this way".
Simply stated, the triangle operator lets you set the prototype of an object if and only if that object has not yet been observably instantiated. It's a small tradeoff, but it gives us many of the benefits of mutable protos without the known hazards.
Of course I disagree, but at least I understand thanks, jjb
On Oct 13, 2011, at 6:00 PM, John J Barton wrote:
Simply stated, the triangle operator lets you set the prototype of an object if and only if that object has not yet been observably instantiated. It's a small tradeoff, but it gives us many of the benefits of mutable protos without the known hazards.
Of course I disagree, but at least I understand thanks,
Can you make the case for changing an "old-born" object's [[Prototype]]?
I ask because I perpetrated this long ago in implementing writable proto in SpiderMonkey, including the cycle detection required to prevent iloops. And then other browsers except (IIRC) IE reverse-engineered. So most implementors have sunk the cost. That doesn't mean it is good sunk cost, or that there are not ongoing taxes from writable proto.
But we may as well hear your use-case (I know of others, e.g. John-David Dalton's fusejs.com and Thomas Fuch's zeptojs.com, but they either want only to preset proto on newborns, or [we think] have better solutions in ES6 [e.g. proxies]).
On Thu, Oct 13, 2011 at 3:27 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 13, 2011, at 6:00 PM, John J Barton wrote:
Simply stated, the triangle operator lets you set the prototype of an
object if and only if that object has not yet been observably instantiated. It's a small tradeoff, but it gives us many of the benefits of mutable protos without the known hazards.
Of course I disagree, but at least I understand thanks,
Can you make the case for changing an "old-born" object's [[Prototype]]?
I ask because I perpetrated this long ago in implementing writable proto in SpiderMonkey, including the cycle detection required to prevent iloops. And then other browsers except (IIRC) IE reverse-engineered. So most implementors have sunk the cost. That doesn't mean it is good sunk cost, or that there are not ongoing taxes from writable proto.
But we may as well hear your use-case (I know of others, e.g. John-David Dalton's fusejs.com and Thomas Fuch's zeptojs.com, but they either want only to preset proto on newborns, or [we think] have better solutions in ES6 [e.g. proxies]).
I don't have an opinion on mutating proto; I've not see good or bad come of it.
I was disagreeing with the <| (protoLinkSet?) operator's restriction on LHS to object literals. (I'm trying a different name)
Dean's characterization I should have objected to, rather than disagreeing with it. Given: var o2 = p <| {a: 'b'}; you can choose to imagine that the RHS object gets [[ProtoLink]] set to |p| then becomes |o2|, but you can equally imagine that |o2| becomes an object by initializing o2.[[ProtoLink]] = p and copying the properties from the literal declaration. The latter description has the same result, no JS developer can tell the difference. The first imagines mutation of an non-existent object; the second imagines copying during initialization with no mutation.
Suppose for a moment we allowed objects on the RHS: var o3 = p <| o2; Would we imagine that o2 was mutated in any way? I don't think so. Maybe there are binary ops that mutate operands, but they don't come to mind. So the entire business about mutation of [[ProtoLink]] is not related to my interest in allowing object expressions on the RHS of protoLinkSet operator.
I hope this is clearer, jjb
On Oct 13, 2011, at 3:55 PM, John J Barton wrote:
Suppose for a moment we allowed objects on the RHS: var o3 = p <| o2; Would we imagine that o2 was mutated in any way? I don't think so. Maybe there are binary ops that mutate operands, but they don't come to mind. So the entire business about mutation of [[ProtoLink]] is not related to my interest in allowing object expressions on the RHS of protoLinkSet operator.
Note that my original thoughts that lead to <| included the possibility that the RHS could be an arbitrary expression. In order to avoid [[Prototype]] mutation that meant that the RHS would have to be shallow cloned to produce a new object whose [[Prototype]] was the LHS value. The semantics of cloning is not as trivial as somebody seems to assume and the primary use case I was trying to address ("subclass" Arrays , Functions, and other objects with special implementation level behaviors) didn't require it. So it punted and specified that the RHS must be a literal. This left open the possibility that at some future date we might want to reconsider that restriction.
I still haven't found a really compelling use case for a non-literal <| RHS and a good definition for object cloning is still a nut to crack. But both plausibly might occur.
On Thu, Oct 13, 2011 at 4:26 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
On Oct 13, 2011, at 3:55 PM, John J Barton wrote:
Suppose for a moment we allowed objects on the RHS: var o3 = p <| o2; Would we imagine that o2 was mutated in any way? I don't think so. Maybe there are binary ops that mutate operands, but they don't come to mind. So the entire business about mutation of [[ProtoLink]] is not related to my interest in allowing object expressions on the RHS of protoLinkSet operator.
Note that my original thoughts that lead to <| included the possibility that the RHS could be an arbitrary expression. In order to avoid [[Prototype]] mutation that meant that the RHS would have to be shallow cloned to produce a new object whose [[Prototype]] was the LHS value. The semantics of cloning is not as trivial as somebody seems to assume and the primary use case I was trying to address ("subclass" Arrays , Functions, and other objects with special implementation level behaviors) didn't require it. So it punted and specified that the RHS must be a literal. This left open the possibility that at some future date we might want to reconsider that restriction.
Thank you for this clear background information.
I still haven't found a really compelling use case for a non-literal <| RHS and a good definition for object cloning is still a nut to crack. But both plausibly might occur.
The use case is the same as Object.extend(): the flexible construction of objects from objects. Object.extend() is used in two ways: 1) To compose behaviors, and 2) To compose state properties. At present we no simple way to go from 1 and 2 to 1+2. Instead we have to do a dance with a function and its .prototype property (or I guess we can mutate proto ;-).
And obviously a good definition of object cloning would be needed for Object.extend() and it would answer your second objection.
jjb
On Oct 13, 2011, at 5:08 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 4:26 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
I still haven't found a really compelling use case for a non-literal <| RHS and a good definition for object cloning is still a nut to crack. But both plausibly might occur.
The use case is the same as Object.extend(): the flexible construction of objects from objects. Object.extend() is used in two ways: 1) To compose behaviors, and 2) To compose state properties. At present we no simple way to go from 1 and 2 to 1+2. Instead we have to do a dance with a function and its .prototype property (or I guess we can mutate proto ;-).
I'm not certain where you see [[Prototype]] modification entering into what you are describing, but I'll assuming that for 1 you want to compose the behaviors into a prototype and that for 2 you want the state to compose into an instance that references the prototype. This all seems like it is expressible in ES5 user level code, using some subset and combination of Object.getOwnPropertyNames, Object.getOwnPropertyDescriptor, Object.create, and Object.defineProperty/defineProperties. You would probably want to define some helper functions
But you could certainly get to a function with a signature like: function compose(proto, composibleBehaviorList, instanceState)
Which you might use like var obj = compose(Super, [mixin1, mixin2, mixin3], {instVar1: 1, instVar2});
where obj ends up as a new object with own instance variables instVar1 and instVar2 and a [[Prototype]] that references a new object that merges all the own properties of mixin1, mixin2, and mixin2. That object's [[Prototype]] would be Super.
No post instantiation [[Prototype]] modification and all doable using ES5 functions.
I actually did something even simpler, using just Object.create and some application specific mixin functions, in my jsmirros project. See allenwb/jsmirrors/blob/master/mirrors.js
What the above techniques doesn't handle is "subclassing" Array or other magic built-ins. It also wouldn't property handle ES6 private named properties but that is an intentional limitation become some of us don't want to allow reflection to expose private names.
And obviously a good definition of object cloning would be needed for Object.extend() and it would answer your second objection.
I don't think they are the same thing at all. Object.extend is just copying properties into a preexisting object. It is not trying to create an new exact duplicate (except for object identify) of an existing object that is a work-alike equivalent of the original object. For cloning you have non-property based object characteristics and application specific identity invariants that complicate matters. It isn't clear that these issues occur in the same way for Object.extend
On Thu, Oct 13, 2011 at 6:08 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
On Oct 13, 2011, at 5:08 PM, John J Barton wrote:
On Thu, Oct 13, 2011 at 4:26 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
I still haven't found a really compelling use case for a non-literal <| RHS and a good definition for object cloning is still a nut to crack. But both plausibly might occur.
The use case is the same as Object.extend(): the flexible construction of objects from objects. Object.extend() is used in two ways: 1) To compose behaviors, and 2) To compose state properties. At present we no simple way to go from 1 and 2 to 1+2. Instead we have to do a dance with a function and its .prototype property (or I guess we can mutate proto ;-).
I'm not certain where you see [[Prototype]] modification entering into what you are describing,
I have not said it did; in fact I said it did not. Mutating [[Prototype]] is not the issue; Literal RHS is the issue.
but I'll assuming that for 1 you want to compose the behaviors into a prototype and that for 2 you want the state to compose into an instance that references the prototype. This all seems like it is expressible in ES5 user level code, using some subset and combination of Object.getOwnPropertyNames, Object.getOwnPropertyDescriptor, Object.create, and Object.defineProperty/defineProperties. You would probably want to define some helper functions
Sure we can, using way less than ES5, because we already do all of this hackery.
And obviously a good definition of object cloning would be needed for Object.extend() and it would answer your second objection.
I don't think they are the same thing at all. Object.extend is just copying properties into a preexisting object. It is not trying to create an new exact duplicate (except for object identify) of an existing object that is a work-alike equivalent of the original object. For cloning you have non-property based object characteristics and application specific identity invariants that complicate matters. It isn't clear that these issues occur in the same way for Object.extend
You lost me here. I should have objected to the requirement of a object cloning definition I guess.
The particular variant of Object.extend() I use does not overwrite the LHS. It creates a new object, copies the LHS into it, then the RHS, then returns it. So the LHS can be a literal, for example to override some functions in the RHS. I think of it as a function representing binary operator. (Other versions extend() do other things, exactly why a standard would be good, but leave that for now).
Now let's invent Object.make(protoLink, props) (or createSimple()...). Let's cause make() to give the same result as <| for any pair of values valid for <|. Now when props is an object expression, what is the result of Object.make(protoLink, props)? I would want var a1 = Object.make(Object.prototype, a) to be the same structure as var a2 = Object.extend({}, a); This is what I meant by "obviously a good definition ... would be needed for extend and it would answer you second objection": whatever rules apply to the RHS in extend() should apply to the RHS in make().
And of course I would like this to be true for <| as well.
jjb
The difference is that object.extend returns objects where as object.make returns things with the same type as the second operand.
So object.extend (obj, someFunction) is easy.
where as object.make(obj, someFunction) returns a function. Now clearly its a new function so it doesnt share closure state. But then how can you say the returned function is the same as someFunction?
This is just one of the edge cases. I would love an object.make as well. But I cant tell you how to handle all the edgecases.
On Oct 14, 2011 3:48 AM, "John J Barton" <johnjbarton at johnjbarton.com>
wrote:
On Thu, Oct 13, 2011 at 6:08 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>
wrote: > > > On Oct 13, 2...
I have not said it did; in fact I said it did not. Mutating [[Prototype]] is not the issue; Literal RHS is the issue.
but I'll assuming that for 1 you want to compose the behaviors into a
prototype and that for 2 ...
Sure we can, using way less than ES5, because we already do all of this hackery.
And obviously a good definition of object cloning would be needed
for Object.extend() and i...
You lost me here. I should have objected to the requirement of a object cloning definition I guess.
The particular variant of Object.extend() I use does not overwrite the LHS. It creates a new object, copies the LHS into it, then the RHS, then returns it. So the LHS can be a literal, for example to override some functions in the RHS. I think of it as a function representing binary operator. (Other versions extend() do other things, exactly why a standard would be good, but leave that for now).
Now let's invent Object.make(protoLink, props) (or createSimple()...). Let's cause make() to give the same result as <| for any pair of values valid for <|. Now when props is an object expression, what is the result of Object.make(protoLink, props)? I would want var a1 = Object.make(Object.prototype, a) to be the same structure as var a2 = Object.extend({}, a); This is what I meant by "obviously a good definition ... would be needed for extend and it would answer you second objection": whatever rules apply to the RHS in extend() should apply to the RHS in make().
And of course I would like this to be true for <| as well.
jjb
On Fri, Oct 14, 2011 at 12:56 AM, Jake Verbaten <raynos2 at gmail.com> wrote:
The difference is that object.extend returns objects where as object.make returns things with the same type as the second operand.
So object.extend (obj, someFunction) is easy.
where as object.make(obj, someFunction) returns a function. Now clearly its a new function so it doesnt share closure state. But then how can you say the returned function is the same as someFunction?
Sorry I don't understand. I can't imagine any way that object.make() will return its second argument and that is the only way the returned function would be the same as the second argument.
This is just one of the edge cases. I would love an object.make as well. But I cant tell you how to handle all the edgecases.
The only open question about Object.make(obj, someFunction) that goes beyond the questions for the protoLink operator <| relates to the difference between someFunction and a literal function declaration.
jjb
On Oct 14, 2011, at 10:45 AM, John J Barton wrote:
On Fri, Oct 14, 2011 at 12:56 AM, Jake Verbaten <raynos2 at gmail.com> wrote: The difference is that object.extend returns objects where as object.make returns things with the same type as the second operand.
So object.extend (obj, someFunction) is easy.
where as object.make(obj, someFunction) returns a function. Now clearly its a new function so it doesnt share closure state. But then how can you say the returned function is the same as someFunction?
Sorry I don't understand. I can't imagine any way that object.make() will return its second argument and that is the only way the returned function would be the same as the second argument.
Yikes, ambiguous language.
Jake clearly meant "same" as in "twin" or "clone". You are the one advocating functional purity -- fresh objects, no observable mutation. For Object.make to be like <| this means the result is not a clone of the first argument, rather of the second.
But then Jake's point about closures becomes crucial. Does the function and its environment get cloned? Closure environments contain mutable bindings.
This is just one of many "edge cases" already mentioned that plague attempts to define cloning such that you get the "same" kind of object as the second parameter, a twin or clone.
So for the path you are advocating, pure functions that make fresh objects, you need to specify cloning. That is a tall order. And it's not obviously needed, since the de-facto standard that <| is codifying and constraining is the preset-proto use case. There's no common clone pattern in the field, AFAIK.
This is just one of the edge cases. I would love an object.make as well. But I cant tell you how to handle all the edgecases.
The only open question about Object.make(obj, someFunction) that goes beyond the questions for the protoLink operator <| relates to the difference between someFunction and a literal function declaration.
This sounds like vehement agreement, but you didn't say what that open question is. It's exactly the "cloning" question.
On Fri, Oct 14, 2011 at 8:46 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Oct 14, 2011, at 10:45 AM, John J Barton wrote:
On Fri, Oct 14, 2011 at 12:56 AM, Jake Verbaten <raynos2 at gmail.com> wrote:
The difference is that object.extend returns objects where as object.make returns things with the same type as the second operand.
So object.extend (obj, someFunction) is easy.
where as object.make(obj, someFunction) returns a function. Now clearly its a new function so it doesnt share closure state. But then how can you say the returned function is the same as someFunction?
Sorry I don't understand. I can't imagine any way that object.make() will return its second argument and that is the only way the returned function would be the same as the second argument.
Yikes, ambiguous language.
Jake clearly meant "same" as in "twin" or "clone". You are the one advocating functional purity -- fresh objects, no observable mutation. For Object.make to be like <| this means the result is not a clone of the first argument, rather of the second.
But then Jake's point about closures becomes crucial. Does the function and its environment get cloned? Closure environments contain mutable bindings.
This is just one of many "edge cases" already mentioned that plague attempts to define cloning such that you get the "same" kind of object as the second parameter, a twin or clone.
So for the path you are advocating, pure functions that make fresh objects, you need to specify cloning. That is a tall order. And it's not obviously needed, since the de-facto standard that <| is codifying and constraining is the preset-proto use case. There's no common clone pattern in the field, AFAIK.
To my way of thinking this argument is backwards. In effect you are saying that we can't support object expressions because we can't support function expressions.
The priority use cases for setProtoLink operator <| RHS should be objects. Once we have a solution for objects, then we can expand to functions. The common pattern in the field is construction of objects. I've never heard anyone override the Function.prototype for a function literal. It may be useful indeed, I'm not saying it's not. But supporting this should not prevent us from solving the common case.
Note that Allen already has special logic for functions on the RHS. In the case case that the RHS is a function. I think what devs want from object.make(obj, someFunction) is a function object with the prototype logic Allen has for <| that runs the function |someFunction| when called. This does not sound hard, but ok maybe it is.
jjb
On Oct 14, 2011, at 9:33 AM, John J Barton wrote:
On Fri, Oct 14, 2011 at 8:46 AM, Brendan Eich <brendan at mozilla.com> wrote: On Oct 14, 2011, at 10:45 AM, John J Barton wrote: So for the path you are advocating, pure functions that make fresh objects, you need to specify cloning. That is a tall order. And it's not obviously needed, since the de-facto standard that <| is codifying and constraining is the preset-proto use case. There's no common clone pattern in the field, AFAIK.
To my way of thinking this argument is backwards. In effect you are saying that we can't support object expressions because we can't support function expressions.
No.
First, functions are objects.
Second, as Allen pointed out, many non-function objects have private state, out-of-sight identity relations (side table mappings), etc., that are crucial to the correct operation of their methods. A clone intrinsic would have to be extensible to encompass such state and relations.
The priority use cases for setProtoLink operator <| RHS should be objects.
We're not even agreeing to set proto on an existing, referenced object, so please don't assert too much. To be persuasive, you should say why it is a priority to preset the [[Prototype]] of a clone of a (here I guess you must mean) plain old object (Object constructor).
Who said that's a priority? The <| proposal takes pains to work with functions for another high-priority use-case: constructor subclassing.
Once we have a solution for objects, then we can expand to functions.
See above. To make the case for "setProtoLink", you have to take on the clone problem squarely, not try to dodge it by starting with vanilla Object instances with no hidden side-table mappings.
The common pattern in the field is construction of objects.
Yes, but that does not require clone!
It's clear that if I am to follow any of Allen's posts I need to learn what |> means.
I looked through some of the email and the wiki, but I don't know what to look for really.
I guess this is a binary operator, so we should be able to say "operator <something>". Furthermore it seems like the concept behind |> (which sounds
interesting) could be independent of the syntax (which I have issues with). So we could resort to a (searchable, pronounceable, conventional) function name in a pinch.
Any hints? jjb