with

# David Herman (14 years ago)

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?

# Mark S. Miller (14 years ago)

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?

# Dmitry Soshnikov (14 years ago)

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 havewith' if we hadn't used already it before.

Dmitry.

# David Herman (14 years ago)

<|

# David Herman (14 years ago)

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.

# David Flanagan (14 years ago)

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!

# David Herman (14 years ago)

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.)

# Russell Leggett (14 years ago)

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.

# Axel Rauschmayer (14 years ago)

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 }
# Dmitry Soshnikov (14 years ago)

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 useextends' 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.

# Peter van der Zee (14 years ago)

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.

# Dmitry Soshnikov (14 years ago)

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 withwith`, 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.

# Axel Rauschmayer (14 years ago)

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.

# Axel Rauschmayer (14 years ago)

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.

# Dmitry Soshnikov (14 years ago)

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.

# David Herman (14 years ago)

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!

# David Herman (14 years ago)

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.

# Russell Leggett (14 years ago)

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 {...}
# Dmitry Soshnikov (14 years ago)

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.

# Axel Rauschmayer (14 years ago)

[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” (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.

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

# David Herman (14 years ago)

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” (object obj with prototype proto). 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 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 }

We're already using of for a different purpose (for-of), and it just reads wrong here.

# David Herman (14 years ago)

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.

# Axel Rauschmayer (14 years ago)

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.

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!).

Going from P <--has-prototype-- o to P --has-instance--> o

is fine with me, but it’s not the directionality of [[Prototype]].

# David Herman (14 years ago)

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.

# Quildreen Motta (14 years ago)

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>

# David Herman (14 years ago)

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.

# David Herman (14 years ago)

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.

# Axel Rauschmayer (14 years ago)

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.

# Mike Samuel (14 years ago)

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 }) {}

# Axel Rauschmayer (14 years ago)

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):

  1. “the prototype is pointed to by the instance” versus
  2. ”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.

# David Herman (14 years ago)

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.

# David Herman (14 years ago)

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.

# Dmitry Soshnikov (14 years ago)

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 thex' object.

As a historical note: Prototype.js borrowed this Object.extend' from Ruby. Though, they placed it into the Object, not into theObject.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 a class syntax. There's no need for extends 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 simplelet' 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 preventsextends' 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.

# David Herman (14 years ago)

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 simplelet' 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 preventsextends' 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).

# Dmitry Soshnikov (14 years ago)

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 anextends` 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 byinclude' (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 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

Yes, true. This is (unfortunately) only for declaration.

the same I proposed to ES (to avoid new keyword object' I used simplelet' 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.

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' andval', 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 preventsextends' 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 asbeget', etc.

Dmitry.

# Brendan Eich (14 years ago)

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.

# David Herman (14 years ago)

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.

# Brendan Eich (14 years ago)

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.

# David Herman (14 years ago)

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.

# David Herman (14 years ago)

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.

# Brendan Eich (14 years ago)

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.

# Brendan Eich (14 years ago)

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.

# David Herman (14 years ago)

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. ;)

# Brendan Eich (14 years ago)

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.