with
On Wed, Nov 16, 2011 at 11:24 PM, David Herman <dherman at mozilla.com> wrote:
Someone who shall remain nameless shot this down when I floated it privately. But I just have to throw this out there, because I kind of can't stop myself falling in love with it...
We used to have this (mis-)feature for dynamically extending scope chains, and despite being ill-conceived, it did have this elegant syntax spelled "with." In ES5 strict, we banned that feature, and it's not coming back for ES6, or ever.
Now we want a (good) feature for dynamically extending prototype chains. And here's this old keyword, just lying around unused...
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I don't get it yet. What do you mean by "dynamically extending prototype chains"? What does the above expression do and evaluate to?
On 17.11.2011 11:24, David Herman wrote:
Someone who shall remain nameless shot this down when I floated it privately. But I just have to throw this out there, because I kind of can't stop myself falling in love with it...
We used to have this (mis-)feature for dynamically extending scope chains, and despite being ill-conceived, it did have this elegant syntax spelled "with." In ES5 strict, we banned that feature, and it's not coming back for ES6, or ever.
Now we want a (good) feature for dynamically extending prototype chains. And here's this old keyword, just lying around unused...
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
So? Who's with me?
Yeah-yeah, the idea is still the same and is discussed here. Just
keyword changes. with' just sounds fine in this case (when I was proposing declarative form of:
let foo extends bar with { ... }' -- I
also wanted to use it, but thought that it will be too verbose to use
two keywords, though...).
However, we nevertheless had/have the semantics for `with', and it may cause confusion. Moreover, you need to specify that [noNewLineHere] should be inserted, in other case its:
obj; with ( ...) { label: 12 }
I still think extends' fits nice here. But would glad to have
with' if
we hadn't used already it before.
Dmitry.
<|
On Nov 16, 2011, at 11:28 PM, Dmitry Soshnikov wrote:
However, we nevertheless had/have the semantics for `with', and it may cause confusion.
Right, that's the natural objection. But... with-statements are dead, long live with-expressions!
Moreover, you need to specify that [noNewLineHere] should be inserted
I don't think there's any need -- you'd only get with-expressions in ES6, and with-statements don't exist.
On 11/16/11 11:30 PM, David Herman wrote:
<|
On Nov 16, 2011, at 11:27 PM, Mark S. Miller wrote:
On Wed, Nov 16, 2011 at 11:24 PM, David Herman <dherman at mozilla.com <mailto:dherman at mozilla.com>> wrote:
Someone who shall remain nameless shot this down when I floated it privately. But I just have to throw this out there, because I kind of can't stop myself falling in love with it... We used to have this (mis-)feature for dynamically extending scope chains, and despite being ill-conceived, it did have this elegant syntax spelled "with." In ES5 strict, we banned that feature, and it's not coming back for ES6, or ever. Now we want a (good) feature for dynamically extending prototype chains. And here's this old keyword, just lying around unused... obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I don't get it yet. What do you mean by "dynamically extending prototype chains"? What does the above expression do and evaluate to?
I was confused by the "extending prototype chains" too, because the word 'with' made me think that you were proposing to replace .{ instead of replacing <|.
I completely understand the temptation to reuse the keyword, however.
We all want redemption in the end!
On Nov 16, 2011, at 11:27 PM, Mark S. Miller wrote:
On Wed, Nov 16, 2011 at 11:24 PM, David Herman <dherman at mozilla.com> wrote: obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I don't get it yet. What do you mean by "dynamically extending prototype chains"? What does the above expression do and evaluate to?
My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for <|. So the above expression evaluates to the same as
obj <| { foo: 12 } <| { bar: 13 } <| { baz: 17 }
which in turn, if I've got this right, would be equivalent to
Object.create(Object.create(Object.create(obj, { foo: { value: 12,
enumerable: true,
configurable: true,
writable: true } }),
{ bar: { value: 13,
enumerable: true,
configurable: true,
writable: true } }),
{ baz: { value: 17,
enumerable: true,
configurable: true,
writable: true } })
since in this example I only used the object literal variant. (The function, array, etc variants do things that Object.create can't do.)
since in this example I only used the object literal variant. (The function, array, etc variants do things that Object.create can't do.)
I think this is ultimately the downfall of 'with' as a complete replacement for <| or extends. It works pretty well on objects but no others.
SomeFunc with function(){...}
Does not read nearly as well.
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I like the idea! As it is syntactically different in this role, errors should be easy to spot.
But I think with
“points in the wrong direction” (object obj
with prototype proto
). That is, to me, it suggests a pointer going from prototype to object.
My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for <|. So the above expression evaluates to the same as
obj <| { foo: 12 } <| { bar: 13 } <| { baz: 17 }
The above example demonstrates just how well the <| operator works. The main objection to it is that it looks wrong in some fonts? Unless there is a general grawlix objection, something arrow-y would be great.
Is there a list of symbols that have already been rejected? Seeing the preposition “with", I feel like suggesting “of” (prototype proto
of object obj
), but I think that has been rejected before (and is taken by the for loop).
obj of { foo: 12 } of { bar: 13 } of { baz: 17 }
On 17.11.2011 11:41, David Herman wrote:
On Nov 16, 2011, at 11:27 PM, Mark S. Miller wrote:
On Wed, Nov 16, 2011 at 11:24 PM, David Herman <dherman at mozilla.com <mailto:dherman at mozilla.com>> wrote:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I don't get it yet. What do you mean by "dynamically extending prototype chains"? What does the above expression do and evaluate to?
My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for <|. So the above expression evaluates to the same as
obj <| { foo: 12 } <| { bar: 13 } <| { baz: 17 }
which in turn, if I've got this right, would be equivalent to
Object.create(Object.create(Object.create(obj, { foo: { value: 12,
enumerable: true,
configurable: true, writable: true } }), { bar: { value: 13, enumerable: true, configurable: true, writable: true } }), { baz: { value: 17, enumerable: true, configurable: true, writable: true } })
since in this example I only used the object literal variant. (The function, array, etc variants do things that Object.create can't do.)
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
In order to avoid confusion with with', which had old and used for years semantics, I still propose to use
extends' instead.
Is it just great that we have the same inheritance model as for simple objects as well as for classes?
// object inherits var foo extends bar { x: 100 }
// class inherits class Foo extends Bar { constructor (x, y, z) { ... } }
P.S.: Scala e.g. uses a similar approach. But they use `object' keyword when inheriting from objects:
object foo extends bar { ... }
Though, they also may use `with' in this context:
object foo extends bar with baz { ... }
thus baz is a mixin. The same with classes:
class Foo extends Bar with baz { .... }
Dmitry.
On Thu, Nov 17, 2011 at 12:53 PM, Dmitry Soshnikov <dmitry.soshnikov at gmail.com> wrote:
My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for <|. So the above expression evaluates to the same as
....
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
David is talking about the proposed <| operator, to replace that with
with
, initializing an object with a given object as prototype. Not
extending... anything.
On 17.11.2011 15:57, Peter van der Zee wrote:
On Thu, Nov 17, 2011 at 12:53 PM, Dmitry Soshnikov <dmitry.soshnikov at gmail.com> wrote:
My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for<|. So the above expression evaluates to the same as ....
Once again, it's absolutely the same approach which I showed yesterday with using
extends' (https://mail.mozilla.org/pipermail/es-discuss/2011-November/018478.html). David is talking about the proposed<| operator, to replace that with
with`, initializing an object with a given object as prototype. Not extending... anything.
As well as I do.
When `extends' keyword is used in other langs for inheritance, does it extend something in respect of copying own properties? Of course not. It's just links an object with its prototype/class. Exactly for this it was reserved in ES.
`extends' is the best in respect that it's used for exactly this purpose in many other languages, and therefore, other users will fill familiar with it.
I can accept `with' for mixins as was shown in previous letter.
Dmitry.
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
The only thing new about David’s proposal (and intentionally so) is that the symbol with
is being reused. So there shouldn’t be any surprise that it looks like many things that we have seen already.
“Once again” also sounds impolite, but maybe that’s just me.
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
The only thing new about David’s proposal (and intentionally so) is that the symbol
with
is being reused. So there shouldn’t be any surprise that it looks like many things that we have seen already.
I’m might be wrong about that, though, but using <| in the extended manner that he shows has been proposed before.
On 17.11.2011 16:04, Axel Rauschmayer wrote:
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
The only thing new about David’s proposal (and intentionally so) is that the symbol
with
is being reused. So there shouldn’t be any surprise that it looks like many things that we have seen already.
I'd accept it if it hadn't old semantics. Moreover, it's used in some languages (in e.g. hypothetical lang from "Essentials of computer programs" book, IIRC).
I'd better reuse it for mixins while inheriting as shown in previous letter.
“Once again” also sounds impolite, but maybe that’s just me.
I polite with everyone, though I don't need permissions to ask question. If you have found something rough in my "tone", you may always ignore it. And "once again", -- because it's really "once again", since I wrote about in the previous letter ;)
Dmitry.
On Nov 17, 2011, at 3:53 AM, Dmitry Soshnikov wrote:
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
My point has absolutely nothing to do with semantics and everything to do with syntax. And extends
fails completely as the syntax. It's backwards -- the prototype doesn't extend the own-properties!
On Nov 17, 2011, at 12:10 AM, Russell Leggett wrote:
since in this example I only used the object literal variant. (The function, array, etc variants do things that Object.create can't do.)
I think this is ultimately the downfall of 'with' as a complete replacement for <| or extends. It works pretty well on objects but no others.
SomeFunc with function(){...}
Does not read nearly as well.
Interesting. I don't think it reads badly, but I can see it not being as intuitive as the object literal form. But lots of operators would look confusing if you didn't know what they mean (e.g., || or && or ^ or %). Once you know that with
simply means prototype extension, I don't think it reads that badly. Subjective, I guess.
On Thu, Nov 17, 2011 at 8:08 AM, David Herman <dherman at mozilla.com> wrote:
On Nov 17, 2011, at 3:53 AM, Dmitry Soshnikov wrote:
Once again, it's absolutely the same approach which I showed yesterday with using `extends' ( esdiscuss/2011-November/018478).
My point has absolutely nothing to do with semantics and everything to do with syntax. And
extends
fails completely as the syntax. It's backwards -- the prototype doesn't extend the own-properties!Look closer - it is being used as a prefix operator, not an infix operator.
extends Proto {...}
This works well with any of the proposal "class as operator"
class extends Proto {...}
class Point2d extends Point {...}
On 17.11.2011 17:08, David Herman wrote:
On Nov 17, 2011, at 3:53 AM, Dmitry Soshnikov wrote:
Once again, it's absolutely the same approach which I showed yesterday with using `extends' (esdiscuss/2011-November/018478).
My point has absolutely nothing to do with semantics and everything to do with syntax.
Well, at least in semantics we're agree; it's already good.
And
extends
fails completely as the syntax.
This is why it's so wide-spread in other languages for inheritance, right? ;)
`extends' is here for years in many langs for exactly to chain an object with its prototype or class (the langs which first come in mind are: Java, PHP, Scala, CoffeeScript, Dart, others). It's not used to copy own properties!
As well, as it's not used to copy own properties in Ruby (in case if you want to argue with that Object.extend copies own properties in JS libs)! -- exactly from there was borrowed Object.extend to Prototype.js. In Ruby it just /chains/ an object with yet another "prototype" (hidden meta-class which inherits from mixin module).
So `extends' is for inheritance. And was even reserved in ES.
It's backwards -- the prototype doesn't extend the own-properties!
Hope I made it more clear.
Once again (sorry, Axel Rauschmayer, you may skip this phrase ;)), I'm not against `with', I'm just worry about that it had/has diff. semantics. But. We may re-use it for mixins.
Dmitry.
Dmitry.
[cc-ing es-discuss again]
On Nov 17, 2011, at 14:20 , Russell Leggett wrote:
On Thu, Nov 17, 2011 at 6:17 AM, Axel Rauschmayer <axel at rauschma.de> wrote:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I like the idea! As it is syntactically different in this role, errors should be easy to spot.
But I think
with
“points in the wrong direction” (objectobj
with prototypeproto
). That is, to me, it suggests a pointer going from prototype to object.My first answer was glib, sorry. I'm proposing `with' as a replacement syntax for <|. So the above expression evaluates to the same as
obj <| { foo: 12 } <| { bar: 13 } <| { baz: 17 }
The above example demonstrates just how well the <| operator works. The main objection to it is that it looks wrong in some fonts? Unless there is a general grawlix objection, something arrow-y would be great.
I would agree with you, except that it would never happen. When would you ever say
obj <| { foo: 12 } <| { bar: 13 } <| { baz: 17 }
When you could just use one literal
obj <| { foo:12, bar:13, baz:17 }
If <| changed to allow non-literal RHS values, I could see it getting more use
obj <| comparable <| enumerable <| {...}
but right now, that has a big hurdle and I've yet to see anybody but me propose a solution.
True, that’s the catch. Then it works for composing an inheritance hierarchy (as in mixins as abstract subclasses).
Another idea for extends
(if there is more than one object that is being extended):
extends(comparable, enumerable, foo, bar) { ... }
Axel
On Nov 17, 2011, at 3:17 AM, Axel Rauschmayer wrote:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I like the idea! As it is syntactically different in this role, errors should be easy to spot.
But I think
with
“points in the wrong direction” (objectobj
with prototypeproto
). That is, to me, it suggests a pointer going from prototype to object.
Well, ultimately the directionality is arbitrary. In my proposal it's "prototype obj
with instance blah
". This results in LTR whereas the other way ends up RTL. JS is built around English, so LTR seems more appropriate (with all due sympathy to our Hebrew-speaking programmers!).
The above example demonstrates just how well the <| operator works. The main objection to it is that it looks wrong in some fonts? Unless there is a general grawlix objection, something arrow-y would be great.
Every font I ever see it in looks terrible, and there is a general grawlix objection. This is largely an aesthetic thing, but aesthetics matter and people react very strongly against <| or funky Unicode symbols. (The latter just ain't gonna happen.)
Is there a list of symbols that have already been rejected? Seeing the preposition “with", I feel like suggesting “of” (prototype
proto
of objectobj
), but I think that has been rejected before (and is taken by the for loop).obj of { foo: 12 } of { bar: 13 } of { baz: 17 }
We're already using of
for a different purpose (for-of), and it just reads wrong here.
On Nov 17, 2011, at 5:13 AM, Russell Leggett wrote:
Look closer - it is being used as a prefix operator, not an infix operator.
extends Proto {...}
There have been a few alternatives discussed in the previous thread. IMO, in each one of them, extends
is awkward. The one you're talking about:
extends p { foo: 1, bar: 2, baz: 3 }
is stilted -- English is SVO (subject-verb-object) not VSO. We don't say "loves JavaScript Russ" but rather "Russ loves JavaScript." Plus we don't have any binary prefix expression operators in JS so that sticks out, too.
If it's infix, you have to make `extends' RTL:
{ foo: 1, bar: 2, baz: 3 } extends p
As I said in response to Axel, LTR is preferable in JS.
But finally, there's the grammatical issue: extends
makes sense as part of either a declaration or a boolean operator. In a declaration we'd be declaring that X extends Y. In a boolean operator we'd be asking whether X extends Y. But what we're talking about here is an operator for constructing a new object: the result of X extended with Y. Grammatically, extendedwith or extendedby would fit better, but of course look terrible.
This works well with any of the proposal "class as operator"
class extends Proto {...} class Point2d extends Point {...}
I'm not tying my suggestion to classes at all. I like classes fine, and don't think they need to be built up from tiny lego pieces. We can use extends
as part of the class syntax without having to have extends
mean something on its own.
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
I like the idea! As it is syntactically different in this role, errors should be easy to spot.
But I think
with
“points in the wrong direction” (objectobj
with prototypeproto
). That is, to me, it suggests a pointer going from prototype to object.Well, ultimately the directionality is arbitrary. In my proposal it's "prototype
obj
with instanceblah
". This results in LTR whereas the other way ends up RTL. JS is built around English, so LTR seems more appropriate (with all due sympathy to our Hebrew-speaking programmers!).
Going from P <--has-prototype-- o to P --has-instance--> o
is fine with me, but it’s not the directionality of [[Prototype]].
On Nov 17, 2011, at 5:55 AM, Axel Rauschmayer wrote:
Going from P <--has-prototype-- o to P --has-instance--> o is fine with me, but it’s not the directionality of [[Prototype]].
I know Allen felt strongly about LTR here. I'm pretty sure I agree with him.
I'm not sure if it's just me, but I find it quite awkward. Perhaps it's the subtle room for confusion with legacy code -- even though ES.next won't have `with', yeah, I know, but still, seeing this piece of code:
( ... ) var x = obj with { ( long-ass object literal here ) } with ({ foo: 1 })
foo += 1 ( ... )
Which, without context, is still confusing. Am I looking at an ES5 legacy snippet that introduces a new object in the EnvironmentRecord chain, or am I looking at a piece of code that builds a new object from chaining prototypes?
That said, I still find `Parent <| { object-literal }' simpler and more direct on what's happening.
2011/11/17 David Herman <dherman at mozilla.com>
On Nov 17, 2011, at 5:16 AM, Dmitry Soshnikov wrote:
And
extends
fails completely as the syntax.This is why it's so wide-spread in other languages for inheritance, right? ;)
In other languages it's not a stand-alone operator but a part of class syntax. (I don't know Ruby, so maybe you'll correct me there.)
`extends' is here for years in many langs for exactly to chain an object with its prototype or class (the langs which first come in mind are: Java, PHP, Scala, CoffeeScript, Dart, others). It's not used to copy own properties!
As well, as it's not used to copy own properties in Ruby (in case if you want to argue with that Object.extend copies own properties in JS libs)! -- exactly from there was borrowed Object.extend to Prototype.js. In Ruby it just chains an object with yet another "prototype" (hidden meta-class which inherits from mixin module).
So `extends' is for inheritance. And was even reserved in ES.
I've never had a problem with using extends
as part of a class
syntax. There's no need for extends
to stand on its on.
Hope I made it more clear.
Sorry I misunderstood which syntax you were promoting (prefix rather than infix). I explained in my reply to Russ why I think it doesn't work.
Once again (sorry, Axel Rauschmayer, you may skip this phrase ;)), I'm not against `with', I'm just worry about that it had/has diff. semantics. But. We may re-use it for mixins.
I'm not sure how much I agree with your argument about confusion with the old semantics. Re: "once again" -- I did reply to that point last night, and you didn't reply to that. But maybe my answer was too cute. To elaborate:
On the one hand: for JS programmers who already know the language, I don't think it's that confusing to learn that with
statements were banned and now there's a new with
expression. For newbies, they arguably don't have to learn the old form, so there's nothing to confuse.
On the other hand: there is the fact that ES3 and non-strict ES5 code will exist indefinitely into the future, so when reading code, people would probably end up having to disambiguate what they're looking at based on the language version. That's a valid concern.
I also agree that with
fits very well as future syntax for mixins or traits, and that's a direction we ought to work towards (post-ES6). And it might also be confusing to use with
as both a part of the class syntax and an expression operator.
As I say, I'm not sure how much I agree, but they're valid concerns.
On Nov 17, 2011, at 5:37 AM, Axel Rauschmayer wrote:
[cc-ing es-discuss again]
On Nov 17, 2011, at 14:20 , Russell Leggett wrote:
If <| changed to allow non-literal RHS values, I could see it getting more use
obj <| comparable <| enumerable <| {...}
but right now, that has a big hurdle and I've yet to see anybody but me propose a solution.
Allen's semantics for <| depends on the RHS being a literal, because it infers the [[Class]] and such from the literal, and because it takes any private names from the object literal form.
True, that’s the catch. Then it works for composing an inheritance hierarchy (as in mixins as abstract subclasses).
Another idea for
extends
(if there is more than one object that is being extended):extends(comparable, enumerable, foo, bar) { ... }
I'm not sure what the semantics of this would be. Are you inventing multiple-prototype inheritance? That's not going to happen.
True, that’s the catch. Then it works for composing an inheritance hierarchy (as in mixins as abstract subclasses).
Another idea for
extends
(if there is more than one object that is being extended):extends(comparable, enumerable, foo, bar) { ... }
I'm not sure what the semantics of this would be. Are you inventing multiple-prototype inheritance? That's not going to happen.
Single inheritance, a prototype chain composed from the given objects, in the given order. An infix operator is probably better for this, though.
2011/11/17 David Herman <dherman at mozilla.com>:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
Does the below fit your syntax and isn't it lexically ambiguous with the old "with"?
obj with ({ foo: 12 }) {}
Going from P <| o to P --with-instance--> o is fine with me, but it’s not the directionality of [[Prototype]].
I know Allen felt strongly about LTR here. I'm pretty sure I agree with him.
I might be misunderstanding, but note that in both cases above, P comes first, o comes second. It’s just a matter of how one interprets the prototype relationship (in which direction the “pointer” goes):
- “the prototype is pointed to by the instance” versus
- ”the prototype has an instance”
But it is possible that #1 can only be properly expressed by something grawlixy, so it might be a moot point.
On Nov 17, 2011, at 6:20 AM, Axel Rauschmayer wrote:
I'm not sure what the semantics of this would be. Are you inventing multiple-prototype inheritance? That's not going to happen.
Single inheritance, a prototype chain composed from the given objects, in the given order. An infix operator is probably better for this, though.
That would have to mutate the prototypes of existing objects. We're not going to add new ways to mutate prototypes.
On Nov 17, 2011, at 6:26 AM, Mike Samuel wrote:
2011/11/17 David Herman <dherman at mozilla.com>:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
Does the below fit your syntax and isn't it lexically ambiguous with the old "with"?
obj with ({ foo: 12 }) {}
This was discussed above; there's no ambiguity if the new language doesn't have with statements. Quildreen and Dmitry have both objected to the confusion to the reader caused by the ambiguity between language versions, though.
On 17.11.2011 18:10, David Herman wrote:
On Nov 17, 2011, at 5:16 AM, Dmitry Soshnikov wrote:
And
extends
fails completely as the syntax.This is why it's so wide-spread in other languages for inheritance, right? ;)
In other languages it's not a stand-alone operator but a part of class syntax. (I don't know Ruby, so maybe you'll correct me there.)
True about that `extends' is limited only for classes in other langs (except Scala, e.g. -- that's mentioned, it may extend objects as well and this is I propose for ES also).
About Ruby: it uses < for inheritance of classes, e.g.:
class Foo < Bar end
And uses `.extend' instance method (inherited from Object) for imperative delegation-based mixing. A module can be mixed to a simple object:
module Foo def bar print "Hello" end end
x = {} x.extend(Foo)
x.bar() # "Hello"
Thus, notice, it's exactly delegation-based inheritance -- if I change
the method in the module Foo (e.g. redefine the bar' method), the changes are reflected on the
x' object.
As a historical note: Prototype.js borrowed this Object.extend' from Ruby. Though, they placed it into the Object, not into the
Object.prototype' since hadn't control of enumerable attribute. Also
they made own proprieties copying, but not delegation inheritance. The
reason -- they couldn't. But if the could, very likely we would have the
same implementation in JS libs as in Ruby.
Anyway, Ruby is not on the list, so sorry everyone for diverting your attention from ES. Let's back to it.
`extends' is here for years in many langs for exactly to chain an object with its prototype or class (the langs which first come in mind are: Java, PHP, Scala, CoffeeScript, Dart, others). It's not used to copy own properties!
As well, as it's not used to copy own properties in Ruby (in case if you want to argue with that Object.extend copies own properties in JS libs)! -- exactly from there was borrowed Object.extend to Prototype.js. In Ruby it just /chains/ an object with yet another "prototype" (hidden meta-class which inherits from mixin module).
So `extends' is for inheritance. And was even reserved in ES.
I've never had a problem with using
extends
as part of aclass
syntax. There's no need forextends
to stand on its on.
OK, though, I'd like again to notice Scala:
object foo extends bar { ... }
class Foo extends bar { ... }
the same I proposed to ES (to avoid new keyword object' I used simple
let' or `var'):
let foo extends bar { x: 100 }
Is equivalence of:
let foo = Object.create(bar, {x: {value: 100}});
And as I understand correctly it syntactically differs from your proposed `with' only in:
let foo = bar with { x: 100 };
and I like it. It really reflects the essence. As well as `extends' above as I see.
Thus, answering your mail (sorry for not answered before), I can't say,
whether extends' is infix or prefix. I don't completely understood on "can be conditional keywords", but what prevents
extends' to be the same?
Hope I made it more clear.
Sorry I misunderstood which syntax you were promoting (prefix rather than infix). I explained in my reply to Russ why I think it doesn't work.
I didn't understand myself yet which syntax I'd like to see technically. I know that I like it visually. Well, as well as with `with'.
Dmitry.
On Nov 17, 2011, at 6:41 AM, Dmitry Soshnikov wrote:
And uses `.extend' instance method (inherited from Object) for imperative delegation-based mixing.
Sure, so that's just a method then, not an extends
keyword.
OK, though, I'd like again to notice Scala:
object foo extends bar { ... }
class Foo extends bar { ... }
Right; in Scala it's still only part of a declaration syntax. Just in terms of being readable English, I don't think extends
works as an operator. I think it only works as part of a declaration ("I declare that X extends Y"), or it would work as a boolean operator ("does X extend Y?"), but it doesn't work as an operator that creates a new object. You could do something like
extend X with Y
but that would require a new reserved work extend
. And it would be awkward to chain:
extend (extend X with Y) with Z
the same I proposed to ES (to avoid new keyword
object' I used simple
let' or `var'):let foo extends bar { x: 100 }
There are a number of things I don't like about this, but primarily the fact that it changes the uniform syntax of let
or var
. Notice how Scala always uses a special prefix keyword that is built to work with extends
.
Thus, answering your mail (sorry for not answered before), I can't say, whether
extends' is infix or prefix. I don't completely understood on "can be conditional keywords", but what prevents
extends' to be the same?
Oops, late night brain freeze. I meant to say "contextual keywords." When there's a grammar context that doesn't allow arbitrary identifiers, we can allow specific identifiers with custom meanings without them actually being reserved words. That's what we're doing for "of" in the for-of loop, and that's what we're doing for the "is" and "isnt" operators. They aren't reserved words.
But it doesn't work for prefix operators unless you use a reserved word. We have extends
as a reserved word, so that works. But I don't like it for reasons of English, as I explained above (and in an earlier email).
On 17.11.2011 21:11, David Herman wrote:
On Nov 17, 2011, at 6:41 AM, Dmitry Soshnikov wrote:
And uses
.extend' instance method (inherited from Object) for imperative delegation-based mixing. Sure, so that's just a method then, not an
extends` keyword.
Yep. And just a small note (to close the topic with Ruby): this
.extend' method is imperative form of the declarative version there which is done by
include' (keyword) operator and is used in classes:
module M def foo print "M.foo" end end
class A include M # module is mixed to the class def bar print "A.bar" end end
a = A.new a.foo() # "M.foo" a.bar() # "M.bar"
And using `.extend' objects (inc. classes) may the same mix modules to them. E.g.:
A.extend(OtherModule) a.extend(OtherModule)
And all this is delegation-based (in fact, just adding another prototype for inheritance), but not copying of own properties.
Anyway, conclude with Ruby.
OK, though, I'd like again to notice Scala:
object foo extends bar { ... }
class Foo extends bar { ... } Right; in Scala it's still only part of a declaration syntax.
Yes, it's true, the form looks nice only with declarations. Seems it's not the best to pass it as an expression, e.g. creating intermediate object and passing it directly to a function. However with `with' it looks pretty nice:
(function (foo) { ... })(obj with {x : 10})
Just in terms of being readable English, I don't think
extends
works as an operator. I think it only works as part of a declaration ("I declare that X extends Y"), or it would work as a boolean operator ("does X extend Y?"), but it doesn't work as an operator that creates a new object. You could do something likeextend X with Y
but that would require a new reserved work
extend
. And it would be awkward to chain:extend (extend X with Y) with Z
Yes, true. This is (unfortunately) only for declaration.
the same I proposed to ES (to avoid new keyword
object' I used simple
let' or `var'):let foo extends bar { x: 100 } There are a number of things I don't like about this, but primarily the fact that it changes the uniform syntax of
let
orvar
.
And I primarily already don't like it (OK, not so like it ;)) because it's hard to use with expressions. "Only-declarations" protocol isn't the best.
Notice how Scala always uses a special prefix keyword that is built to work with
extends
.
It depends. Some programmers may claim Scala for abusing with many
keywords. E.g. var' and
val', which even can be hard distinguishable
on some fonts for people with not so good vision, etc.
Thus, answering your mail (sorry for not answered before), I can't say, whether
extends' is infix or prefix. I don't completely understood on "can be conditional keywords", but what prevents
extends' to be the same? Oops, late night brain freeze. I meant to say "contextual keywords." When there's a grammar context that doesn't allow arbitrary identifiers, we can allow specific identifiers with custom meanings without them actually being reserved words. That's what we're doing for "of" in the for-of loop, and that's what we're doing for the "is" and "isnt" operators. They aren't reserved words.
It's interesting. I see.
(so it will be possible to do: var is = 10; and at the same time `obj is foo' ? OK.)
But it doesn't work for prefix operators unless you use a reserved word. We have
extends
as a reserved word, so that works. But I don't like it for reasons of English, as I explained above (and in an earlier email).
I agreed on expressions as I said above. Well, if to introduce such an
op, then perhaps with' is better than new kw such as
beget', etc.
Dmitry.
On Nov 17, 2011, at 6:39 AM, David Herman wrote:
On Nov 17, 2011, at 6:26 AM, Mike Samuel wrote:
2011/11/17 David Herman <dherman at mozilla.com>:
obj with { foo: 12 } with { bar: 13 } with { baz: 17 }
Does the below fit your syntax and isn't it lexically ambiguous with the old "with"?
obj with ({ foo: 12 }) {}
This was discussed above; there's no ambiguity if the new language doesn't have with statements.
This would require migration through two steps. One to ES5 strict to get rid of the with above (which relies on ASI). The second to ES.next or whatever retasks 'with'.
Also, using 'with' around object literals makes me want functional record update. IIRC we've talked about that before.
On Nov 17, 2011, at 12:56 PM, Brendan Eich wrote:
This would require migration through two steps. One to ES5 strict to get rid of the with above (which relies on ASI). The second to ES.next or whatever retasks 'with'.
I don't understand this-- that's already the case, since there's no with-statement in ES6.
Also, using 'with' around object literals makes me want functional record update. IIRC we've talked about that before.
That's one of the things I like about with
for this: prototype extension is already a great mechanism for functional update on objects.
On Nov 17, 2011, at 1:27 PM, David Herman wrote:
On Nov 17, 2011, at 12:56 PM, Brendan Eich wrote:
This would require migration through two steps. One to ES5 strict to get rid of the with above (which relies on ASI). The second to ES.next or whatever retasks 'with'.
I don't understand this-- that's already the case, since there's no with-statement in ES6.
What is already the case?
If I have code of the kind Mike Samuel showed:
obj with ({ foo: 12 }) {}
and I migrate directly into ES-whatever with 'with' as you propose (instead of <|), then I do not get an early error.
Also, using 'with' around object literals makes me want functional record update. IIRC we've talked about that before.
That's one of the things I like about
with
for this: prototype extension is already a great mechanism for functional update on objects.
Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties, the chaining is observable many ways (methods on the prototype, not only reflection APIs), there are two objects not one.
On Nov 17, 2011, at 1:30 PM, Brendan Eich wrote:
If I have code of the kind Mike Samuel showed:
obj with ({ foo: 12 }) {}
and I migrate directly into ES-whatever with 'with' as you propose (instead of <|), then I do not get an early error.
Understood.
Also, using 'with' around object literals makes me want functional record update. IIRC we've talked about that before.
That's one of the things I like about
with
for this: prototype extension is already a great mechanism for functional update on objects.Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties,
That's precisely what makes it analogous to FRU. You functionally update (i.e., update without mutating) by shadowing.
the chaining is observable many ways (methods on the prototype, not only reflection APIs), there are two objects not one.
Yes it's observable, but it's a very natural fit. It's how I do FRU today, using Object.create.
On Nov 17, 2011, at 2:08 PM, David Herman wrote:
On Nov 17, 2011, at 1:30 PM, Brendan Eich wrote:
If I have code of the kind Mike Samuel showed:
obj with ({ foo: 12 }) {}
and I migrate directly into ES-whatever with 'with' as you propose (instead of <|), then I do not get an early error.
Understood.
So I'm ready to give up, because of this issue and because of the fact of pre-ES6 and post-ES6 code co-existing indefinitely into the future (and the corresponding confusion that could ensue for reading code).
Shame, because I think it's gorgeous.
On Nov 17, 2011, at 2:08 PM, David Herman wrote:
Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties,
That's precisely what makes it analogous to FRU. You functionally update (i.e., update without mutating) by shadowing.
Mutating [[Prototype]] is still mutation :-P.
The fact that you get a chain of two or more objects instead of one is the big thing about this that makes it not FRU to me. We don't have records, of course, but squinting hard at objects might make them look as pretty (need beer goggles ;-). But only own properties of a single object, so I'd want FRU of this kind:
let o = { p:1, r:3 }; let u = { o where p:1, q:2 };
and u would have own p, q, and r.
On Nov 17, 2011, at 2:15 PM, Brendan Eich wrote:
On Nov 17, 2011, at 2:08 PM, David Herman wrote:
Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties,
That's precisely what makes it analogous to FRU. You functionally update (i.e., update without mutating) by shadowing.
Mutating [[Prototype]] is still mutation :-P.
The fact that you get a chain of two or more objects instead of one is the big thing about this that makes it not FRU to me. We don't have records, of course, but squinting hard at objects might make them look as pretty (need beer goggles ;-). But only own properties of a single object, so I'd want FRU of this kind:
let o = { p:1, r:3 }; let u = { o where p:1, q:2 };
and u would have own p, q, and r.
And the punchline -- mutating o.p = 4 would not change u.p. With your Object.create scheme, unless you freeze (could do for record-ness), you get unwanted sharing if there are references out there to the un-updated record-object.
On Nov 17, 2011, at 2:15 PM, Brendan Eich wrote:
On Nov 17, 2011, at 2:08 PM, David Herman wrote:
Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties,
That's precisely what makes it analogous to FRU. You functionally update (i.e., update without mutating) by shadowing.
Mutating [[Prototype]] is still mutation :-P.
Who's mutating [[Prototype]]? This is Object.create.
The fact that you get a chain of two or more objects instead of one is the big thing about this that makes it not FRU to me. We don't have records, of course, but squinting hard at objects might make them look as pretty (need beer goggles ;-). But only own properties of a single object, so I'd want FRU of this kind:
let o = { p:1, r:3 }; let u = { o where p:1, q:2 };
and u would have own p, q, and r.
Yes, this is of course a different semantics than prototype extension. I'm not sure there's a "canonical" definition of what FRU means in the presence of mutation. I think Ocaml agrees with you, FWIW. The cost model of prototype extension can be nice, since you aren't repeatedly copying the entire structure. (Of course, lookups can get more expensive.)
Anyway, I've already cried uncle. Not that I'm gonna stop using Object.create for FRU any time soon. ;)
On Nov 17, 2011, at 2:29 PM, David Herman wrote:
On Nov 17, 2011, at 2:15 PM, Brendan Eich wrote:
On Nov 17, 2011, at 2:08 PM, David Herman wrote:
Prototype extension or delegation is not the same as FRU at all -- the delegating object can shadow proto-properties,
That's precisely what makes it analogous to FRU. You functionally update (i.e., update without mutating) by shadowing.
Mutating [[Prototype]] is still mutation :-P.
Who's mutating [[Prototype]]? This is Object.create.
I was thinking u.proto = o :-P.
Someone who shall remain nameless shot this down when I floated it privately. But I just have to throw this out there, because I kind of can't stop myself falling in love with it...
We used to have this (mis-)feature for dynamically extending scope chains, and despite being ill-conceived, it did have this elegant syntax spelled "with." In ES5 strict, we banned that feature, and it's not coming back for ES6, or ever.
Now we want a (good) feature for dynamically extending prototype chains. And here's this old keyword, just lying around unused...
So? Who's with me?