Allowing object field name shorthand

# Sebastian Malton (7 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20170622/e5549da5/attachment

# T.J. Crowder (7 years ago)

Can you expand on the benefits vs. costs (e.g., complexity, clarity)?

I ask because I'm not immediately seeing a lot of benefit, but I'm seeing various costs:

  1. It adds more hidden behavior (creating the object).

  2. It makes object initializers more confusing to human readers. The syntaxes {"a.b": 42} and {[a.b]: 42} are already both valid, and do quite different things from each other; adding {a.b: 42} with yet a third, different, behavior seems problematic (to me). The benefits of computed property names were strong enough to justify the second syntax above, but are the benefits of this sufficient for a third?

  3. It adds complexity to object initializer processing, both in the obvious way (has to figure out to create the hidden object or possibly several nested hidden objects), and around the fact that object initializers are processed in source code order.

Re that third point, consider this code using this new notation:

const o = {
    a.a: one(),
    b: two(),
    a.b: three()
};

Those functions should be called in the order one, two, three, which means adding to the object on a later on in the initializer; it can't just become:

const o = {
    a: {          // WRONG
        a: one(),
        b: three()
    },
    b: two()
};

...because three would be called before two. I suppose the logic could still be source code order, and the engine would break apart the identifier, check to see if the first part already exists on the object and use its value if so, add an object if not; rinse, repeat. If so, it raises the question:

const o = {
    a: 1,
    a.b: 42
};

Is that a syntax error? (No, wait, it can't be; 1 could be any expression.) A runtime error? A silent runtime failure as const o = {a: 1}; a.b = 42; would be? Suppose we changed a: 1 to a: null? const o = {a: null}; a.b = 42; would throw, should this new syntax throw in that case?

Weighed against those, the only real benefit I see is that it's slightly more concise in the case of an object with a single property; but as of even a second property, it's more verbose.

Sorry, this ran longer than I meant it to. Not trying to bash the idea, these are just the things that jumped out at me and I type fairly quickly. :-)

-- T.J. Crowder

# Sebastian Malton (7 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20170622/fa308cc6/attachment-0001

# Bob Myers (7 years ago)

On Thu, Jun 22, 2017 at 10:23 PM, Sebastian Malton <sebastian at malton.name>

wrote:

In my opinion the notation of {"n.b": 1} should equate to {n.b: 1} so that object field retrieval is consistent.

That's a hugely breaking change.

# T.J. Crowder (7 years ago)

On Thu, Jun 22, 2017 at 5:53 PM, Sebastian Malton <sebastian at malton.name> wrote:

I would say that the easiest benefit would be the shorthand.

But as I pointed out, it's not shorthand unless the object only has one property. As of the second property, it's only more concise if the main property name is just one character; at two characters, it's a tie; and from three characters it's less concise. From three properties onward it's less concise even with a single-character top-level name:

// One property
let o = {ex: {b: 1}};         // Current
let o = {ex.b: 1};            // Proposed; shorter
// Two properties, main property's name is only two characters:
let o = {ex: {b: 1, c: 2}};   // Current
let o = {ex.b: 1, ex.c: 2};   // Proposed; same
// Two properties, main property's name is 3+ characters:
let o = {foo: {b: 1, c: 2}};  // Current
let o = {foo.b: 1, foo.c: 2}; // Proposed; longer
// Three properties:
let o = {a: {b: 1, c: 2, d: 3}};  // Current
let o = {a.b: 1, a.c: 2, a.d: 3}; // Proposed; longer

At that point it blossoms:

// Four properties
let o = {a: {b: 1, c: 2, d: 3, e: 4}};    // Current
let o = {a.b: 1, a.c: 2, a.d: 3, a.e: 4}; // Proposed; longer
// Five properties
let o = {a: {b: 1, c: 2, d: 3, e: 4, f: 5}};      // Current
let o = {a.b: 1, a.c: 2, a.d: 3, a.e: 4, a.f: 5}; // Proposed; longer

I have shown it to people and it apparently help with mongo integration.

How, precisely?

  1. I don't think that hidden behaviours is necessarily bad.

We'll just have to disagree there. :-)

  1. In my opinion the notation of {"n.b": 1} should equate to {n.b: 1} so that object field retrieval is consistent.

That's not going to happen. Again, {"a.b": 1} is already valid syntax. It creates an object with a property called a.b (which is a perfectly valid property name) with the value 1. See: jsfiddle.net/nwydgju2

  1. I also believe that this sort of thing could make configs easier to read

We'll have to disagree there, as well. :-) Moreover, making "configs" with JavaScript isn't really a goal, as far as I know.

-- T.J. Crowder

# Sebastian Malton (7 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20170622/c9f8c0e5/attachment-0001

# T.J. Crowder (7 years ago)

If you know it's already valid syntax, then why suggest it mean something else? Breaking changes require extremely compelling justification (and new language modes, à la strict mode, which I don't think there's any appetite for at present).

I'm still not seeing any solid benefits to repeating the top-level field name.

I'll step back at this point, I've raised the issues / concerns that came to me.

Best,

-- T.J. Crowder

# kai zhu (7 years ago)

-1 this is a terrible idea in terms of debugging and code-maintennance. when debugging someone else's unfamiliar code, i now have to add an extra-check for quotes around the key.

# J Decker (7 years ago)

On Thu, Jun 22, 2017 at 7:56 AM, Sebastian Malton <sebastian at malton.name>

wrote:

I would like to propose that the dot or '.' is allowed in object field names so that the following are allowed.

var obj = { field1: "val" , field2.field3: 3, field2.field4: true };

This is much like var obj = { field1: 3 field2 : 4 field3 : obj.field2+3 }

which falls apart because obj isn't technically fully defined, and doesn't have a field2. So your second field2.field4 wouldn't be able to reference the previous object created for field2.field3.

it would be a huge complexity for engines to create objects....

# Sebastian Malton (7 years ago)

I don't see how this is like referencing the object a field is in during object construction. Yes field2.field4 would not be able to reference field2.field3 but that is not what I am proposing. I am proposing a syntactic sugar for nested objects

# Michael Kriegel (7 years ago)

I also vote against this. A further problem could be duplication of field names in large objects. Imagine there is a field2.field3.field4.field5 in the beginning of your object and then another one 100 lines below. Using the currently well defined way to define nested objects at least groups fields which belong to an object.

var obj = { field1: "val" , field2.field3: 3, //hundrets of lines field2.field3: true };

Also it is much shorter, not to repeat the field names each time:

var obj = { field1: "val" , field2:{ field3: 3, field4: true } };

Michael

# Mark (7 years ago)

Another -1 for this.

It adds complexity to object initializer processing, both in the obvious way (has to figure out to create the hidden object or possibly several nested hidden objects), and around the fact that object initializers are processed in source code order.

Exactly, this proposal assumes nested objects and that the nested key is referencing that object. But to assume this is problematic. What if the user wants the nested value to be something other than a plain object? with this approach, they’re stuck with just creating native objects.

Not that it isn’t a good idea, but I think the negative effects of this change outweigh the benefit. ​

# Ron Buckton (7 years ago)

There is one place where I could see this syntax being useful, though with different semantics, is a feature from C# that I seen used to good effect: Dotted names for shorthand property assignments.

For example:

const results = books.map(x => ({
  x.isbn,
  x.title,
  x.category.categoryName
}));

// creates: [{ isbn: 123456789, title: “…”, categoryName: “…” }, …]

In this example, the actual name for the property is the rightmost identifier of the expression. This differs from the proposal at the start of this thread, but may also be worth considering.

Ron

(My apologies for formatting as I wrote this up on my phone)

From: Mark<mailto:mark at heyimmark.com>

Sent: Sunday, June 25, 2017 10:09 AM To: Michael Kriegel<mailto:michael.kriegel at actifsource.com>; es-discuss at mozilla.org<mailto:es-discuss at mozilla.org>

Subject: Re: Allowing object field name shorthand

Another -1 for this.

It adds complexity to object initializer processing, both in the obvious way (has to figure out to create the hidden object or possibly several nested hidden objects), and around the fact that object initializers are processed in source code order.

Exactly, this proposal assumes nested objects and that the nested key is referencing that object. But to assume this is problematic. What if the user wants the nested value to be something other than a plain object? with this approach, they’re stuck with just creating native objects.

Not that it isn’t a good idea, but I think the negative effects of this change outweigh the benefit.

On Fri, Jun 23, 2017 at 1:27 AM Michael Kriegel <michael.kriegel at actifsource.com<mailto:michael.kriegel at actifsource.com>> wrote:

I also vote against this. A further problem could be duplication of field names in large objects. Imagine there is a field2.field3.field4.field5 in the beginning of your object and then another one 100 lines below. Using the currently well defined way to define nested objects at least groups fields which belong to an object.

var obj = { field1: "val" , field2.field3: 3, //hundrets of lines field2.field3: true };

Also it is much shorter, not to repeat the field names each time:

var obj = { field1: "val" , field2:{ field3: 3, field4: true } };

Michael

On 23.06.2017 04:13, Sebastian Malton wrote:

I don't see how this is like referencing the object a field is in during object construction. Yes field2.field4 would not be able to reference field2.field3 but that is not what I am proposing. I am proposing a syntactic sugar for nested objects

On 2017-06-22 10:05 PM, J Decker wrote:

On Thu, Jun 22, 2017 at 7:56 AM, Sebastian Malton <sebastian at malton.name<mailto:sebastian at malton.name>> wrote:

I would like to propose that the dot or '.' is allowed in object field names so that the following are allowed.

var obj = { field1: "val" , field2.field3: 3, field2.field4: true };

This is much like var obj = { field1: 3 field2 : 4 field3 : obj.field2+3 }

which falls apart because obj isn't technically fully defined, and doesn't have a field2. So your second field2.field4 wouldn't be able to reference the previous object created for field2.field3.

it would be a huge complexity for engines to create objects....

Sebastian

# T.J. Crowder (7 years ago)

(Sorry, just seeing this as it went to my spam folder - Ron, Google claims it "failed microsoft.com extra verification" or something like that.)

In this example, the actual name for the property is the rightmost identifier of the expression. This differs from the proposal at the start of this thread, but may also be worth considering.

Very different, and much more useful and interesting. It builds on the shorthand notation from ES2015 that does that for variables:

const answer = 42;
const o = {answer};
console.log(o.answer); // 42

...by allowing for it with object properties as well:

const o1 = {answer: 42};
const o2 = {o1.answer};
console.log(o2.answer); // 42

I really like that idea. Would be good to see a proposal for a champion to consider.

It would need to take both kinds of property accessors into account, and address the runtime semantics of the expression evaluating the property name. E.g.:

const names = {
    get name() {
        console.log("Getting name 'answer'");
        return "answer";
    }
};
const o1 = {answer: 42};
const o2 = {o1[names.name]};
console.log(o2.answer); //42

Presumably the above would output:

Getting name 'answer'
42

e.g., the name accessor is only run once. (Accessor side-effects only for the purposes of example, natch.)

-- T.J. Crowder