ES6 in Chromium proposal: spread & rest operators

165 views
Skip to first unread message

man...@google.com

unread,
Nov 26, 2018, 5:00:23 PM11/26/18
to Chromium-dev
Proposing to move spread and rest to the "allowed features" section of the es style guide.

Spread Syntax

let a = [1, 2, 3];
let max = Math.max(...a);

Rest Syntax

let a = [1, 2, 3, 4, 5];
let
[first, second, ...rest] = a;

Benefits
Elegant alternative to `concat` concatenating

Before
let someNumbers = [1, 2, 3];
let moreNumbers
= [5, 6];
let allNumbers
= someNumbers.concat(4, moreNumbers, 7, 8);

After
let someNumbers = [1, 2, 3];
let moreNumbers = [5, 6];
let allNumbers = [...
someNumbers, 4, ...moreNumbers, 7, 8];

Clearer than .slice when copying

Before
let copy = allNumbers.slice();

After
let copy = [...allNumbers];

Invoking variadic functions

Before
let max = copy[0];
copy
.forEach(a => max = Math.max(a, max));

After
let max = Math.max(copy);

Defining Variadic functions.

Before
let sum2 = (a, b) => a + b;
let sum3
= (a, b, c) => a + b + c;
let sum4
= (a, b, c, d) => a + b + c + d;
let sum
= array => array.reduce((a, b) => a + b);

// or
function sumArguments() {
 
return arguments.reduce((a, b) => a + b);
}

let mySum
= sum3(a, b, c); // problematic when later changed to sum 4 numbers.

After
let sum = a => a.reduce((b, c) => b + c);

let mySum
= sum(a, b, c);

Compatibility:
Supported by iEnter code here...
Works with closure, eslint and clang.

dpapad

unread,
Nov 26, 2018, 5:24:07 PM11/26/18
to Chromium-dev, mich...@chromium.org, Scott Chen, Christopher Lam, Dan Beam, Hector Carmona, Esmael El-Moslimany, Rebekah Potter
Thanks for starting this thread. FWIW, I had stated a CL to update the styleguide here (which also included destructuring assignment), but did not get to sending a proposal.

On Monday, November 26, 2018 at 2:00:23 PM UTC-8, man...@google.com wrote:
Proposing to move spread and rest to the "allowed features" section of the es style guide.

Spread Syntax

let a = [1, 2, 3];
let max = Math.max(...a);

Rest Syntax

let a = [1, 2, 3, 4, 5];
let
[first, second, ...rest] = a;


This example also uses "destructuring assignment" which is a different feature, and not part of this proposal thread. Should we make it part of it, so that we don't need a separate thread?

man...@google.com

unread,
Nov 27, 2018, 10:14:09 AM11/27/18
to Chromium-dev
typo on "Invoking variadic functions" section. After example, should read

let max = Math.max(...copy);

PhistucK

unread,
Nov 27, 2018, 12:04:37 PM11/27/18
to man...@google.com, Chromium-dev
The last example seems to have some issues (in the before and the after does not use this feature).

PhistucK


On Tue, Nov 27, 2018 at 5:14 PM manukh via Chromium-dev <chromi...@chromium.org> wrote:
typo on "Invoking variadic functions" section. After example, should read

let max = Math.max(...copy);

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/4e768964-a5d5-472a-80a7-719ea16834e5%40chromium.org.

man...@google.com

unread,
Nov 27, 2018, 12:39:03 PM11/27/18
to Chromium-dev
another typo, apologies, the "Defining Variadic functions" "after" example should read


let sum = (...a) => a.reduce((b, c) => b + c);

dmca...@chromium.org

unread,
Nov 27, 2018, 2:24:31 PM11/27/18
to Chromium-dev
Thanks for starting this!

I am a bit confused by the after code sample in "Defining Variadic Functions".

// Original example

let sum
= a => a.reduce((b, c) => b + c);
let mySum
= sum(a, b, c);

Assuming a, b, and c are numeric, wouldn't sum(a, b, c) ignore b and c?

I would expect the parameters of sum to be defined with the spread operator, like this.

// With spread syntax
let sum
= (...a) => a.reduce((b, c) => b + c);

man...@google.com

unread,
Nov 27, 2018, 3:26:19 PM11/27/18
to Chromium-dev
Also proposing to  move destructuring to the "allowed features" section of the es style guide.

Syntax

let [one, two] = [1, 2];
let
{ten, eleven} = {ten: 10, eleven: 11};


// skipping
let
[one, two, , four] = [1, 2, 3, 4];
let
{ten, eleven, thirteen} = {ten: 10, eleven: 11, twelve: 12, thirteen: 13};


// renaming
let
{ten, x: eleven} = {ten: 10, x: 11, twelve: 12};


// unwrapping nested objects
let
{wrap: {wrap2: {fifty}}} = {wrap: {wrap2: {fifty: 50}}};


// default values
let
[zero = 0, xnull = 0, xfalse = 0] = [undefined, null, false];
let
{cats = 0, dogs = 0, firstName = '', lastName = ''} = {dogs: 3, firstName: 'x'};
let
{surname: lastName = ''} = {surname: 'false'};

Benefits

1. Conciseness

Before

people.forEach(person => {
  processFirstName
(person.name.first);
  processLastName
(person.name.last);
  processAge
(person.age);
  processFull
(`${person.name.first} ${person.name.last}`, person.age);
});

Or

people.forEach(person => {
  let first
= person.name.first;
  let
last = person.name.last;
  let age
= person.age;
  processFirstName
(first);
  processLastName
(last);
  processAge
(age);
  processFull
(`${first} ${last}`, age);
});

After

people.forEach(({name: {first, last},  age}) => {
  processFirstName
(first);
  processLastName
(last);
  processAge
(age);
  processFull
(`${first} ${last}`, age);
});

2. Explicit function interfaces

Before

// unclear what the parameter `settings` should look like without looking at sample invocations.
function updatePage(settings) {};

After

function updatePage({bgColor, fontColor, fontSize}) {};

This issue is mitigated when type annotations are available.

3. Explicit naming of array items

Before

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let lineMatch
= htmlText.match(textRegex);

printLarge
(lineMatch[1]);
print(lineMatch[2]);
printOrDefault
(lineMatch[3], '.');

Or

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let lineMatch
= htmlText.match(textRegex);
let firstWord
= lineMatch[1];
let remainingSentence
= lineMatch[2];
let punctuation
= lineMatch[3];

printLarge
(firstWord);
print(remainingSentence);;
printOrDefault
(punctuation, '.');

After

let htmlText = '<p>The blue fox ate the moon grass.</p>';
let textRegex
= /\>([A-Z]\w+) ((?:\w|\s)*)([.!?])?\</;
let
[, firstWord, remainingSentence, punctuation] = htmlText.match(textRegex);


printLarge
(firstWord);
print(remainingSentence);
printOrDefault
(punctuation, '.');

With Rest operator

Worth noting, destructuring and rest operator can be used together.
let [first, second, third, ...honorableMentions] = [0, 1, 2, 3, 4, 5, 6, 7]; // see [1]
let
{president, vicePresident, ...otherImportantPeople} = {president: 0, vicePresident: 1, depStateSec: 2, depDefenseSec: 3, depTreasurySec: 4} // see [2]

Compatibility:
iOS 10.0-10.2
Works with ceslint, clang, and Closure [see below
[1] Rest operator in array destructuring is not supported by iOS.
[2] Rest operators in object destructuring is supported by iOS 11.1+ and closure compiler with `ECMASCRIPT8` flag.

Closure support

1. Rest operator in object destructuring.

As noted above, this requires the `ECMASCRIPT8` flag.

2. Typed arrays

The below snippet fails to throw a compiler error.

/** @type number */ let one;
[one] = [false];

Similarly, for default values during array deconstruction, the below does not throw an error.

/** @type string */ let zero;
/** @type string */ let xnull;
/** @type string */ let xfalse;
[zero = 0, xnull = 0, xfalse = 0] = [undefined, null, false];

But this is a broader issue with typed arrays in general, e.g. the below also fails to throw an error.

/** @type Array<number> */ let array;
array = [false];

Therefore, I don't think this is an argument against allowing destructuring, but just something worth mentioning.

Mike Frysinger

unread,
Nov 27, 2018, 4:15:54 PM11/27/18
to man...@google.com, chromi...@chromium.org
can you do one request per thread ?  gmail is garbage at threading which means the conversation becomes unmanageable.
-mike

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.

Mike Frysinger

unread,
Nov 27, 2018, 4:18:03 PM11/27/18
to man...@google.com, chromi...@chromium.org
i'm all for spread/rest usage!  IE is the only notable platform missing support, but that shouldn't matter to the Chromium project itself.
-mike

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.

man...@google.com

unread,
Nov 27, 2018, 4:25:31 PM11/27/18
to Chromium-dev
Yes, you're both correct, the last example (Defining Variadic functions, after) should be 

let sum = (...a) => a.reduce((b, c) => b + c);

let mySum 
= sum(a, b, c);

Mike Frysinger

unread,
Nov 28, 2018, 1:37:02 AM11/28/18
to Manuk Hovanesian, chromi...@chromium.org
hmm, we probably need to explicitly say that spread syntax for arrays/arguments is OK, but for objects it's still not permitted.  the former is in ES6, but the latter is new to ES2018.


On Mon, Nov 26, 2018 at 2:00 PM manukh via Chromium-dev <chromi...@chromium.org> wrote:
--

Dan Beam

unread,
Dec 3, 2018, 9:24:49 PM12/3/18
to Mike Frysinger, man...@google.com, Chromium-dev
On Tue, Nov 27, 2018 at 10:36 PM Mike Frysinger <vap...@chromium.org> wrote:
hmm, we probably need to explicitly say that spread syntax for arrays/arguments is OK, but for objects it's still not permitted.  the former is in ES6, but the latter is new to ES2018.


On Mon, Nov 26, 2018 at 2:00 PM manukh via Chromium-dev <chromi...@chromium.org> wrote:
Proposing to move spread and rest to the "allowed features" section of the es style guide.

I'm generally supportive as well!  \o/

Question though: do we have any type of static analysis tool that can detect trying to spread unspreadable types?  As in:

let a = 1;
alert(...a);

Or will we always be forced to find these at run time?

-- Dan
 

Dan Beam

unread,
Dec 3, 2018, 9:32:34 PM12/3/18
to Mike Frysinger, man...@google.com, Chromium-dev
On Mon, Dec 3, 2018 at 6:23 PM Dan Beam <db...@chromium.org> wrote:
On Tue, Nov 27, 2018 at 10:36 PM Mike Frysinger <vap...@chromium.org> wrote:
hmm, we probably need to explicitly say that spread syntax for arrays/arguments is OK, but for objects it's still not permitted.  the former is in ES6, but the latter is new to ES2018.


On Mon, Nov 26, 2018 at 2:00 PM manukh via Chromium-dev <chromi...@chromium.org> wrote:
Proposing to move spread and rest to the "allowed features" section of the es style guide.

I'm generally supportive as well!  \o/

Question though: do we have any type of static analysis tool that can detect trying to spread unspreadable types?  As in:

let a = 1;
alert(...a);

Or will we always be forced to find these at run time?

In my own testing, the answer seems to be: depends on if we have clear type info when using Closure compiler. https://imgur.com/a/f6mJy1u

-- Dan

dpapad

unread,
Jan 4, 2019, 2:47:58 PM1/4/19
to Chromium-dev, vap...@chromium.org, man...@google.com
@manukh: Can you summarize the status of this proposal based on the discussion above? What is left to do before approving the usage of spread and rest ES6 features?

Manuk Hovanesian

unread,
Jan 4, 2019, 3:07:21 PM1/4/19
to dpapad, Chromium-dev, vap...@chromium.org
@dpapad,
No one's expressed disagreement with the proposal. Mike pointed out
that object rest & spread properties are not in ES6. The proposal is
currently stage 4 and are expected in the next ES spec version. I
think our next steps would be to take the spread and rest parts from
your CL add a statement about obj rest & spread properties.

Giovanni Ortuño

unread,
Jan 30, 2019, 11:12:48 PM1/30/19
to man...@google.com, dpapad, Chromium-dev, vap...@chromium.org
fwiw: Using the spread operator to clone an object causes one of the tools to throw a 
a parsing error. Am I missing a flag? See this CL:  https://crrev.com/c/1447394

man...@google.com

unread,
Jan 31, 2019, 11:14:54 AM1/31/19
to Chromium-dev, man...@google.com, dpa...@chromium.org, vap...@chromium.org
The spread operator for objects is new to ecma 2018 [1]. Additionally, it may also not be supported by iOS 10 (for reference, the rest parameter during object destructuring isn't supported by iOS 10).
If you set the closure language_in to ECMASCRIPT_2018 [2], closure will accept the spread operator in objects; though, doing this will also make closure throw other errors and warnings.
For reference, there's been discussions about the similar rest parameter during object destructuring [3].

[1]

[2]

[3]
https://cs.chromium.org/chromium/src/styleguide/web/es.md?l=545-557&rcl=e031efefcef9c1482df55ecac3f485c37f240db9

Demetrios Papadopoulos

unread,
Jan 31, 2019, 1:09:12 PM1/31/19
to Manuk Hovanesian, Chromium-dev, Mike Frysinger
The error is thrown from polymer-bundler, not from Closure compiler. So it is possible that polymer-bundler is failing when that syntax is used. Pasting below

python ../../chrome/browser/resources/optimize_webui.py --host settings --input gen/chrome/browser/resources/settings/settings_resources.unpak --out_folder gen/chrome/browser/resources/settings --depfile gen/chrome/browser/resources/settings/build.d --html_in_files settings.html lazy_load.html --html_out_files vulcanized.html lazy_load.vulcanized.html --html_out_files_polymer2 vulcanized.p2.html lazy_load.vulcanized.p2.html --js_out_files crisper.js lazy_load.crisper.js --insert_in_head \<base\ href=\"chrome://settings\"\> Traceback (most recent call last): File "../../chrome/browser/resources/optimize_webui.py", line 266, in <module> main(sys.argv[1:]) File "../../chrome/browser/resources/optimize_webui.py", line 260, in main '\n'.join(manifest['_missing'])) Exception: polymer-bundler could not find files for the following URLs: autofill_page/autofill_section.js

This needs further investigation to come up with a minimal repro example.

Giovanni Ortuño

unread,
Jan 31, 2019, 4:44:08 PM1/31/19
to dpa...@chromium.org, Manuk Hovanesian, Chromium-dev, Mike Frysinger
It's also tripping the presubmit script:

/b/swarming/w/ir/cache/builder/chromium_presubmit/src/chrome/browser/resources/settings/autofill_page/autofill_section.js 173:62 error Parsing error: Unexpected token .. ✖ 1 problem (1 error, 0 warnings)

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.

Demetrios Papadopoulos

unread,
Jan 31, 2019, 4:51:55 PM1/31/19
to Giovanni Ortuño, Manuk Hovanesian, Chromium-dev, Mike Frysinger
On Thu, Jan 31, 2019 at 1:43 PM Giovanni Ortuño <ort...@chromium.org> wrote:
It's also tripping the presubmit script:

/b/swarming/w/ir/cache/builder/chromium_presubmit/src/chrome/browser/resources/settings/autofill_page/autofill_section.js 173:62 error Parsing error: Unexpected token .. ✖ 1 problem (1 error, 0 warnings)

There's probably two separate bugs here (since two separate tools are breaking). Could you file a bug for this?

Giovanni Ortuño

unread,
Jan 31, 2019, 9:00:11 PM1/31/19
to Demetrios Papadopoulos, Manuk Hovanesian, Chromium-dev, Mike Frysinger
On Fri, Feb 1, 2019 at 8:50 AM Demetrios Papadopoulos <dpa...@chromium.org> wrote:
On Thu, Jan 31, 2019 at 1:43 PM Giovanni Ortuño <ort...@chromium.org> wrote:
It's also tripping the presubmit script:

/b/swarming/w/ir/cache/builder/chromium_presubmit/src/chrome/browser/resources/settings/autofill_page/autofill_section.js 173:62 error Parsing error: Unexpected token .. ✖ 1 problem (1 error, 0 warnings)

There's probably two separate bugs here (since two separate tools are breaking). Could you file a bug for this?

 
 


On Fri, Feb 1, 2019 at 5:08 AM Demetrios Papadopoulos <dpa...@chromium.org> wrote:
The error is thrown from polymer-bundler, not from Closure compiler. So it is possible that polymer-bundler is failing when that syntax is used. Pasting below

python ../../chrome/browser/resources/optimize_webui.py --host settings --input gen/chrome/browser/resources/settings/settings_resources.unpak --out_folder gen/chrome/browser/resources/settings --depfile gen/chrome/browser/resources/settings/build.d --html_in_files settings.html lazy_load.html --html_out_files vulcanized.html lazy_load.vulcanized.html --html_out_files_polymer2 vulcanized.p2.html lazy_load.vulcanized.p2.html --js_out_files crisper.js lazy_load.crisper.js --insert_in_head \<base\ href=\"chrome://settings\"\> Traceback (most recent call last): File "../../chrome/browser/resources/optimize_webui.py", line 266, in <module> main(sys.argv[1:]) File "../../chrome/browser/resources/optimize_webui.py", line 260, in main '\n'.join(manifest['_missing'])) Exception: polymer-bundler could not find files for the following URLs: autofill_page/autofill_section.js

This needs further investigation to come up with a minimal repro example.

On Thu, Jan 31, 2019 at 8:14 AM <man...@google.com> wrote:
The spread operator for objects is new to ecma 2018 [1]. Additionally, it may also not be supported by iOS 10 (for reference, the rest parameter during object destructuring isn't supported by iOS 10).
If you set the closure language_in to ECMASCRIPT_2018 [2], closure will accept the spread operator in objects; though, doing this will also make closure throw other errors and warnings.
For reference, there's been discussions about the similar rest parameter during object destructuring [3].


Oh I see. Do we usually mark features that break our tools as banned? Either way, we should probably add ES2018 features to our list and put this in the TBD section.
Reply all
Reply to author
Forward
0 new messages