Make comma at the end of line optional

# Алексей (7 years ago)

Now we have a great syntax improvement that allows us to put comma at the end of arguments lists, object and array definitions. So in multiline definition last line could have the same signature as others (not only in multiline, but multiline definition benefits the most).

I would like to propose syntax that would allow to each line looks like the last:

const object = { x: 1 y: 2 z: 3 }

The rule here: for multiline arguments list, object or array declaration if line is a complete statement and next line is not an operator than consider it as complete argument (field, element) declaration.

Not an operator so you could use

const condition = true const objext = { x: condition ? 0 : 1 y: 2 z: 3 }

It is really like ASI but without bugs with "[", "(" and "/" - they should be consider as a start of a new declaration

# Bob Myers (7 years ago)

Yes, ASI has been such a great success, let's extend it to commas.

# Claude Pache (7 years ago)

There are [no LineTerminator here] rules in the ES grammar, in order to prevent the most pernicious trap when using ASI:

return // implicit semicolon here
a = b

Those [no LineTerminator here] rules have not been included in constructs that don’t need them. As a result:

const object = {
    get // no implicit comma here
    y: 2
    
    z: x // no implicit comma here
    in: "foo"
}

So, no, it’s not a good idea.

# Алексей (7 years ago)

Sorry, but I don't see any problems with example you provide:

const object = { get // not a complete declaration statement - so no implicit comma here y: 2 // continuation of a previous line

z: x // complete declaration statement and next line is not an operator - implicit comma here in: "foo" }

2017-09-12 18:53 GMT+03:00 Claude Pache <claude.pache at gmail.com>:

# dante federici (7 years ago)

What benefit does this give the language?

# Алексей (7 years ago)

Will reduce the noise created around the real essence of a program

2017-09-12 19:27 GMT+03:00 dante federici <c.dante.federici at gmail.com>:

# Naveen Chawla (7 years ago)

Time saving:

  1. Automatically handle accidentally omitted commas, if used
  2. Saves having to add them in the first place
# Jeremy Martin (7 years ago)

const object = { get // not a complete declaration statement - so no implicit comma here y: 2 // continuation of a previous line }

The get declaration actually is a valid declaration (see shorthand property names here: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015 ).

# Claude Pache (7 years ago)

Le 12 sept. 2017 à 18:00, Алексей <agat00 at gmail.com> a écrit :

Sorry, but I don't see any problems with example you provide:

const object = { get // not a complete declaration statement - so no implicit comma here y: 2 // continuation of a previous line

z: x // complete declaration statement and next line is not an operator - implicit comma here in: "foo" }

This is not how ASI works. A implicit semicolon is not added when a declaration would be complete, but when the next token would produce a syntax error.

# Алексей (7 years ago)

Yes, I have correct my self about it in a next letter. The point is that it doesn't change the rule

2017-09-12 19:32 GMT+03:00 Jeremy Martin <jmar777 at gmail.com>:

# Naveen Chawla (7 years ago)

I don't think ASI matters in relation to this proposal

# Алексей (7 years ago)

Yes you are right it is not related to ASI in the implementation details. Only in form of usage

2017-09-12 19:40 GMT+03:00 Naveen Chawla <naveen.chwl at gmail.com>:

# dante federici (7 years ago)

I think the only place I see as a current inconsistency is with class definitions vs object definitions. It probably should have been looped into the object shorthand definition:

tc39/proposal-class-fields

class MyClass {
  prop = 123
  constructor() {}
  method() {}
}

vs

const myObj = {
  prop: 123,
  constructor(){},
  method(){},
};

Also, to wit on the class-fields proposal and this issue: tc39/proposal-class-fields#7

# Jordan Harband (7 years ago)

Punctuation isn't noise.

# Алексей (7 years ago)

Don't you think that line break is a strong punctuation by itself?

2017-09-12 19:54 GMT+03:00 Jordan Harband <ljharb at gmail.com>:

# Jordan Harband (7 years ago)

Of course not:

var arr = [
  1, 2, 3
  4
];

If JS was the kind of language where a line break definitively ended a statement, that'd be a different story - but it's not.

# kdex (7 years ago)

I'm not sure how your text editor is set up, but you may or may not be able to tell soft-wrapping apart from an actual EOL character if you have long lines.

I don't like the idea of making whitespace of any kind significant, which is why I would agree with Jordan.

# Claude Pache (7 years ago)

Le 12 sept. 2017 à 18:57, Алексей <agat00 at gmail.com> a écrit :

Don't you think that line break is a strong punctuation by itself?

It could have been. Unfortunately, in JS, it is not.

Automatic semi-colon insertion (ASI) could be seen as an attempt to have their cake and eat it too. Or, as a compromise between the two options by making some line breaks significant (e.g., the one after return).

But in general, line breaks are not significant enough to allow to introduce ASI-like rules after the fact, that would work reliably enough.

BTW, the title of the thread, “Make comma at the end of line optional”, reveals a probable misunderstanding of the feature. In JS, semicolons are not “optional”, they are “automatically inserted”. That makes a difference when parsing:

a = b
+c
# Jordan Harband (7 years ago)

I prefer to describe semicolons as so required that the engine inserts them for you if you forget ;-)

# Алексей (7 years ago)

The reason why we have a discussions about whether to rely on ASI or insert them manually is because ASI has problems (return is one of them). And they can't be fixed because fixes are not backward compatible. Based on this experience it would be possible to determine the rules that would not have that gaps or their kind.

2017-09-12 20:32 GMT+03:00 Claude Pache <claude.pache at gmail.com>:

# Алексей (7 years ago)

You should have a reason to write it like this. And if you have than

var arr = [
  1, 2, 3
  4
];

would probably be better than

var arr = [
  1, 2, 3,
  4
];

And even if you don't - you always have an option to insert a coma at the end on the line

But in most cases dropping of a comma at the end would not reduce the readability but only remove the duplicated (by a line break) punctuation

Would you agree that

var a = {
  x: 1
  y: 2
}

is not reading worse than

var a = {
  x: 1,
  y: 2
}

?

2017-09-12 20:10 GMT+03:00 Jordan Harband <ljharb at gmail.com>:

# dante federici (7 years ago)

In terms of style, and in terms of version control, either of these are fine:

const obj = {
  x: 10
  y: 23
};
// or
const obj2 = {
  x: 10,
  y: 23,
};

The mixed case is the most obnoxious one:

const bad = {
  x: 12,
  y: 7
}

However, as pointed out, there is ambiguity with:

const obj = {
  get
  x: 10
  y
  z: 24
  get
  myMethod() {
  }
}

I just don't see optional comma in a collection as a useful feature for the language -- "whitespace matters" always makes me uncomfortable, especially since there are different standards for line breaks across machines (looking at you \r\n), whereas the , token, which is already used to delineate arguments, is suited exactly for this job.

The one thing I still have a gripe over is the class definition syntax -- where neither , or ; are used at the end of method expressions.

# Jeremy Martin (7 years ago)

*> The reason why we have a discussions about whether to rely on ASI or

insert them manually is because ASI has problems (return is one of them). *

This seems to come from the perspective that ASI was a poorly specified feature, as opposed to a recovery mechanism for poorly terminated statements.

That being said, even with ASI completely removed from the discussion, your proposal has some significant barriers to overcome -- most notably the lack of backwards compatibility.

Examples have already been provided where your proposal would change the semantics of *already *valid code. E.g.,

const get = "foo";

const obj = { get y: 2 };

console.log(obj.get); // under current rules: undefined // under your new proposal: "foo"

If you introduce new rules to resolve that ambiguity or to preserve backwards compatibility, you've now created a situation similar to ASI, where developers have to remember a list of exceptions before they elide a comma.

Even in the absence of backwards compatibility concerns, you need to provide a persuasive argument that the cost-benefit ratio justifies the effort, and judging from initial feedback, I think that will be an uphill battle.

# Allen Wirfs-Brock (7 years ago)

On Sep 12, 2017, at 11:22 AM, dante federici <c.dante.federici at gmail.com> wrote:

The one thing I still have a gripe over is the class definition syntax -- where neither , or ; are used at the end of method expressions.

Look at the grammar.

; is not part of the concise method production, but it is still perfectly fine to insert a a ; at the immediate end of a concise method. This is exactly like function declarations. A ‘;` is not a required part of a function declaration, but you can put one there if you want.

function f() {};

class C {
   m() {};
   n() {};
}  //you can put a ;  here, too if you want
# Алексей (7 years ago)

Am... no. Right now this example would just not work. For now this code is invalid.

2017-09-12 21:33 GMT+03:00 Jeremy Martin <jmar777 at gmail.com>:

# Jeremy Martin (7 years ago)

Apologies, I was butchering the property getter syntax. With the correct syntax, the backwards compatibility concern remains, however:

const get = "foo";

const obj = {
  get
  y() { return 2 }
};

console.log(obj.get);
// current: `undefined`
// under this proposal: `"foo"`

You can try it yourself here: es6console.com/j7hy49k4

# Алексей (7 years ago)

Yes, you are right, there is a problem for an object definition. Can't think of any good idea how to overcome this scenario :(

2017-09-12 21:48 GMT+03:00 Jeremy Martin <jmar777 at gmail.com>:

# Michał Wadas (7 years ago)

On the margin: currently that's syntax error. The only ambiguity that I see is shorthand for variable called get followed by method.

# dante federici (7 years ago)

I mean, it's the general case of the "get" and "set" when defining a method: www.ecma-international.org/ecma-262/6.0/#sec-method-definitions-runtime-semantics-propertydefinitionevaluation

That being said, there's a lot of "you just shouldn't do that" in javascript. Looking at you, undefined not being a reserved word.

Syntax aside, a question that hasn't been sufficiently answered is what value does this actually add other than "I don't want to type ,"? Arguments for "easier to read code" I would absolutely disagree with, since it may be easier for one person, but not another. Giving a "line break matters" is a terrible answer, since that would break a ton of backwards compatibility.

# Алексей (7 years ago)

Think of it from a different way: if there would be no ',' how would you react on the idea of adding it? Peaty sour every one would decide that would be a complete nonsense. On the other side there is a discussion about possibility of make it optional where different people have different opinions. And no, it wouldn't break a tone of code - at list for now we came to only one quite exotic case with "get" and "set". But yes, the fact that it exists making it impossible. At list in such form

2017-09-12 23:09 GMT+03:00 dante federici <c.dante.federici at gmail.com>:

# Tab Atkins Jr. (7 years ago)

On Tue, Sep 12, 2017 at 1:49 PM, Алексей <agat00 at gmail.com> wrote:

Think of it from a different way: if there would be no ',' how would you react on the idea of adding it? Peaty sour every one would decide that would be a complete nonsense.

This sort of hypothetical isn't useful; you're not proposing switching over to solely comma-less, you're proposing a mixture of comma and comma-less being allowed. That has very different ergonomics than either all-comma or all-comma-less.

The hypothetical comma-less language would also have made many different syntax decisions over the years to accommodate that, which current JS has not made. This causes the sorts of problems that Claude/etc have pointed out.

# Jerry Schulteis (7 years ago)

I tried out "automatic comma insertion" on some real-world code examples; in my opinion it decreases code readability.It solves the problem of needing to change two lines when adding to the end of a list, but that already has many solutions (the awful comma-first style, allowing trailing commas, just deal with it, syntax-aware diff).

On Tuesday, September 12, 2017, 3:09:51 PM CDT, dante federici <c.dante.federici at gmail.com> wrote:  

I mean, it's the general case of the "get" and "set" when defining a method:www.ecma-international.org/ecma-262/6.0/#sec-method-definitions-runtime-semantics-propertydefinitionevaluation

That being said, there's a lot of "you just shouldn't do that" in javascript. Looking at you, undefined not being a reserved word. Syntax aside, a question that hasn't been sufficiently answered is what value does this actually add other than "I don't want to type ,"? Arguments for "easier to read code" I would absolutely disagree with, since it may be easier for one person, but not another. Giving a "line break matters" is a terrible answer, since that would break a ton of backwards compatibility._______________________________________________ es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es

# Jordan Harband (7 years ago)

I would take commas over a mixture a thousand times over; I'd do the same with semicolons - it's not the presence or absence of these tokens that causes a problem, it's the ambiguity.

Introducing the same horrific ambiguity around semicolons, for commas, does not sound like a good idea.

# Matthew Robb (7 years ago)

Okay what would be the cons to allowing semi colons in place of commas in object literals?

I have an aversion to dangling commas. They're like,

# dante federici (7 years ago)

I can totally feel the, English break with, Commas especially, as a part of speech; Semicolons do a great job of delineating sentences and statements; But I have a special heart for separating bits from bytes.

I guess a return is a period?

Either way --- I think my opinions are:

  • end of statement style is a linting concern
  • there's no benefit from comma optional => lint + fix can warn or make right in the exact get/set case
  • ASI is... a stopgap
  • srsly go to coffeescript or sugarjs if you want to type less (P.S. don't)
# Naveen Chawla (7 years ago)

Can't get be relegated to a reserved/keyword, like let, yield and await were? Just curious about that kind of process & decision?...

# Isiah Meadows (7 years ago)

I can assure you that will likely never happen, because it's a pretty obvious identifier to use in more generic or high-context scenarios. (Think: get(foo, bar), and I've done that plenty of times.)

# Naveen Chawla (7 years ago)

Very interesting point. Is there another way to get this optional comma proposal through while being backwards compatible? I really like the idea.

If it worked like ASI, then surely it would allow the multi-line get case?:

{
    get
    x() //valid syntax after "get", so no comma inserted
}

Can someone remind me of the problem doing it this way, if any? (I'm not sure it has been mentioned yet)

# Boris Zbarsky (7 years ago)

On 9/13/17 9:05 AM, Naveen Chawla wrote:

Can someone remind me of the problem doing it this way, if any?

You mean apart from all the existing footguns ASI has?

# Jeremy Martin (7 years ago)

*> Can someone remind me of the problem doing it this way, if any? (I'm not

sure it has been mentioned yet)*

The problem is in how this proposal has currently been structured:

*> [...] if line is a complete statement and next line is not an operator

than consider it as complete argument (field, element) declaration.*

In the provided example...

{
    get
    x() //valid syntax after "get", so no comma inserted
}

... the get line is a valid, complete shorthand property declaration, so a comma would be inserted, and thus changing the semantics of already valid code.

As is the case with virtually all potential syntax ambiguities, this can be worked around through exceptions and extra rules regarding when commas are/aren't inserted, but that tends this proposal towards the same idiosyncratic footguns that come with ASI.

This is obviously a subjective analysis, but this proposal seems to introduce too much wtfjs material in exchange for too little in time/character savings.

# Naveen Chawla (7 years ago)

I'm not really familiar with ASI but they key factor mentioned in this discussion is this (by Claude Pache):

*A implicit semicolon is not added when a declaration would be complete, but when the next token would produce a syntax error. *

By this behaviour (a modification to the initial "complete statement produces comma" version of this proposal), everything would work perfectly, no?

The multi-line get would not produce a comma, and hence the scheme is backwards compatible, right?

Please provide a counter-example if I have missed something.

As for the benefit, the time savings in not having to debug accidentally omitted commas and not having to add them in the first place are, I think, an improvement. And of course those who want to continue using commas everywhere, can:

function doStuff(
    x
    y
    z
){
}
const
   x = 5
   y = 6
   z = 7

Great to hear those counter-examples as I don't know enough about ASI, and the related subject, to picture the pitfalls (sorry for my ignorance on this). Also it would be good for reference on this proposal...

# Jeremy Martin (7 years ago)

Quick side note regarding multiple variable declarations: both versions of this proposal (OP's newline-based proposal and the ASI-inspired version) result in code breakage:

const
   x = 5
   y = 6
   z = 7

Under existing ASI rules, this is currently equivalent to:

const x = 5;
// y and z are global
y = 6;
z = 7;

If we use newline based comma insertion (or give ASI-style comma insertion precedence over semicolon insertion), then this proposal would result in the following equivalent:

const
  x = 5,
  // y and z are now lexically scoped constants
  y = 6,
  z = 7;

Unless I'm missing something, both of those scenarios definitely preclude multiple variable declarations from this proposal.

That being said, the ASI-inspired semantics seems like it could have more legs in other contexts, although I would personally argue that too little is offered in exchange for the cognitive overhead of a new rule with ASI-style exceptions attached to it (i.e.., "comma before newlines, except after get, and set, variable declarations, ...").

# Алексей (7 years ago)

Yes, this is the reason why I didn't mention the variable declaration in initial proposal - it is 100% valid syntax in current implementation (and 100% relative error in strict mode)

But the design problems of ASI are incomparable with a special case of get and set

2017-09-13 17:55 GMT+03:00 Jeremy Martin <jmar777 at gmail.com>:

# Boris Zbarsky (7 years ago)

On 9/13/17 9:57 AM, Naveen Chawla wrote:

By this behaviour (a modification to the initial "complete statement produces comma" version of this proposal), everything would work perfectly, no?

If by "perfectly" you mean "have hard-to-predict somewhat nonlocal behavior that makes any code relying on this a hard-to-read footgun", then the answer might be "yes". For pretty much any other definition of "perfectly", I'm fairly sure the answer is "no".

Great to hear those counter-examples as I don't know enough about ASI,

Still in the context of ASI, here are some examples of why ASI is a bad idea:

  1. What does this return?

    function f() { return 5; }

  2. What does this alert?

    var str = "hello"; var x = str [x].forEach(() => alert(x))

Now back to automatic comma insertion... In your example:

function doStuff( x y z ){ }

if someone changes doStuff to take an array as the second arg and you modify the call as:

function doStuff( x [y] z ){ }

suddenly you need to insert a comma after the "x" to preserve the right semantics, no? This is not terribly intuitive or obvious. It gets even worse in a situation like this:

function doStuff( x /* The next argument is an array for good reasons that we will now expound on in a long comment, etc, etc */ [y] ){ }

Quick, tell me without testing this or looking at the spec for a while whether this is a valid call to doStuff, with one argument, or a syntax error that would trigger comma insertion.

But more generally, if you just use your favorite search engine on the phrase "automatic semicolon insertion", you will get a slew of articles explaining the pitfalls.

# Naveen Chawla (7 years ago)

x <whitespace> [y] would be invalid syntax, right?

So

x
[y]

would automatically insert a comma in the case of a function call arguments list, right?

That's exactly what would be desired. What am I missing?

# Bob Myers (7 years ago)

Personally, I am annoyed by the extra typing required for spaces. I propose that we have a new kind of ASI: automatic SPACE insertion.

For instance, you could then write

    functionfoobar(){return42;}
```js
# Isiah Meadows (7 years ago)

What about...

  • variable (var)

  • donuts (do)

  • forest (for)

  • awaiter (await, module-specific)

  • async (caolan/async)

  • className (class)

  • letters (let)

  • constants (const)

Fun fact: all of these are valid, and many of them are relatively common. Please consider the ramifications of such a feature before proposing them.

# Tab Atkins Jr. (7 years ago)

I believe Bob was engaging in reductio ad absurdum, Isiah. ^_^

# Isiah Meadows (7 years ago)

Oh okay. Granted, that's not always a safe assumption on this list, though...

(It's actually a bit of a refreshing surprise when people present well-researched proposals here, to be honest.)

# Jeremy Martin (7 years ago)

> What am I missing?

Nothing with respect to function arguments, AFAICT.

But to beat the dead-cognitive-overhead horse again, the rules around ACI (Automatic Comma Insertion) appear to require too many exceptions. We've already covered:

  • ACI doesn't apply at all between variable declarations
  • ACI has exceptions around getter/setter properties in object literals.

I hadn't thought of these before, but there's also:

  • ACI would need exceptions in object and array literals following yield in generator functions.
  • ACI would need exceptions in object and array literals following await in async functions.

I would wager this isn't an exhaustive list yet, either.

To be clear, these aren't exceptions in the grammar itself (the ASI-style "insert comma if next token would generate a syntax error" is sufficient to handle all of these cases), but they are exceptions that developers and tooling would need to hold onto, and IMHO, relegate the purported readability improvements.

# Isiah Meadows (7 years ago)

If something requires so much special casing just to work, it's fundamentally broken and best avoided altogether. Sloppy mode is fundamentally broken. eval is fundamentally broken. TC39 people have already generally accepted this as truth. Could we avoid adding more broken features to the language? Just saying.

(TL;DR: Just let this thread die.)

# J Decker (7 years ago)

Within the context of an array or object definition I could see implementing automatic commas between elements.... but not outside; think the thread is straying a little from the original post (const isn't available in either context). But only between completed expressions/function definitions. It wouldn't be horribly hard to option that into my json-6 parsing... just still don't really think I'm a fan anyway. (but that doesn't have to deal with get/set/function definitions).

# Boris Zbarsky (7 years ago)

On 9/13/17 1:55 PM, Naveen Chawla wrote:

x <whitespace> [y] would be invalid syntax, right?

Wrong.

What am I missing?

This is exactly why automatic X insertion with complicated rules is a bad idea for all values of X. ;)

# Алексей (7 years ago)

Thank you for good summary. If this discussion would appears in future than your mail is a great link to starts from

2017-09-13 22:08 GMT+03:00 Jeremy Martin <jmar777 at gmail.com>:

# Allen Wirfs-Brock (7 years ago)

On Sep 13, 2017, at 12:00 PM, Tab Atkins Jr. <jackalmage at gmail.com> wrote:

I believe Bob was engaging in reductio ad absurdum, Isiah. ^_^

or reductio ad FORTRAN

# Reinis Ivanovs (7 years ago)

The "some examples" of ASI problems might as well say "all", since there aren't more than the two listed cases worth mentioning, and even the return one is kind of contrived, because putting line breaks after return isn't usually a thing. It also doesn't follow that ASI would be a "bad idea"; remembering not to start lines with brackets or parens is easy (especially with a linter, which people should be using anyway), and the benefit is less visually noisy code and a bit less typing. The same can't be said for comma insertion, because commas aren't as noticable or often used as semicolons, and the syntax would have more 'gotchas' than with ASI, so it's just not worth it.

# Alexander Jones (7 years ago)

IIFEs start with a (. Putting line breaks before certain expressions can help improve clarity. Your mind is made up but I have to protest. ASI sucks. And the extra cognitive overhead it causes is utterly pointless. If you don’t want to type them, why not program your editor to actually insert ; and a linebreak at the same time when you want to terminate a statement?

Many problems arise from parsing ambiguities — when writing code authors know exactly what they intend, why make future readers second guess?

# kai zhu (7 years ago)

-1 for code-maintainability. i don’t see the benefits justifying the extra complexity and rules it adds to javascript style-guides and linters (and those who follow them).