archives

« Bugzilla Issues Index

#2034 — Allow the spread/rest operator in any position of the destructuring or function parameters


The current spec says that the spread(or rest) operator should be the last operation in the destructuring assignment or function parameters.
The opportunity to set the spread operator to any position is an extremely useful.

While
```ecmascript6
let [a, ...c] = [1, 2]
```
is a simple
```javascript
var $__0 = [1, 2], a = $__0[0], c = [].slice.call($__0, 1);
```
the
```ecmascript6
let [...c, a] = [1, 2]
```
is a bit difficult
```javascript
var $__0 = [1, 2], a = $__0[$__0.length - 1], c = [].slice.call($__0, 0, $__0.length - 1);
```
and become more difficult (especially when developer must print it by the hand) with increasing the number of parameters.
For example:
```ecmascript6
let [a, b, ...c, d, f] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
```
goes to
```javascript
var $__0 = [1, 2, 3, 4, 5, 6, 7, 8, 9], $__1, a = $__0[0], b = $__0[1], c = (5 <= $__0.length ? [].slice.call($__0, 2, $__1 = $__0.length - 2) : ($__1 = 2, [])), d = $__0[$__1++], f = $__0[$__1++];
```

The same thing in function parameters.


I my opinion, there are no strong arguments to restrict the spread/rest operator position as a last one. The destructuring and function parameters should support the spread/rest in any position:

function test(p1, ...params, p2) { }
test(); //p1 == undefined, params = [], p2 == undefined
test(1); //p1 == 1, params = [], p2 == undefined
test(1, 2); //p1 == 1, params = [], p2 == 2
test(1, 2, 3); //p1 == 1, params = [2], p2 == 3
test(1, 2, 3, 4); //p1 == 1, params = [2, 3], p2 == 4
function test2(p1, ...params, p2, p3) { }
test2(1, 2, 3, 4); //p1 == 1, params = [2], p2 == 3, p3 == 4
test2(1, 2, 3); //p1 == 1, params = [], p2 == 2, p3 == 3

let [v1, ...vars, v2] = []; //v1 == undefined, vars = [], v2 == undefined
let [v1, ...vars, v2] = [1]; //v1 == 1, vars = [], v2 == undefined
let [v1, ...vars, v2] = [1, 2]; //v1 == 1, vars = [], v2 == 2
let [v1, ...vars, v2] = [1, 2, 3]; //v1 == 1, vars = [2], v2 == 3
let [v1, ...vars, v2] = [1, 2, 3, 4]; //v1 == 1, vars = [2, 3], v2 == 4

let [v1, ...vars, v2, v3]= [1, 2, 3, 4];//v1 == 1, vars = [2], v2 == 3, v3 == 4
let [v1, ...vars, v2, v3] = [1, 2, 3]; //v1 == 1, vars = [], v2 == 2, v3 == 3

CoffeScript has this feature http://coffeescript.org/#try:%5Ba%2C%20b%2C%20c...%2C%20d%2C%20f%5D%20%3D%20%5B1%2C%202%2C%203%2C%204%2C%205%2C%206%2C%207%2C%208%2C%209%5D as well.
Also similar syntax is allowed in Python 3:
```Python3
a, *b, c = [1, 2, 3, 4];
print(a, b, c);//1 [2, 3] 4
```


Example with a default parameters:
(rest/spread already has a default value - empty array)
```ecmascript6
function test3( p1 = 1, p2 = 2, ...spread, p3 = 3, p4 = 4 ) {
console.log(p1, p2, spread, p3, p4)
}
test3(); // p1 = 1, p2 = 2, spread = [], p3 = 3, p4 = 4
test3(9, 8, 7, 6); // p1 = 9, p2 = 8, spread = [], p3 = 7, p4 = 6
test3(9, 8, 7, 6, 5, 4);// p1 = 9, p2 = 8, spread = [7, 6], p3 = 5, p4 = 4
```

a CoffeeScript version:
http://coffeescript.org/#try:test3%20%3D%20(%20p1%20%3D%201%2C%20p2%20%3D%202%2C%20spread...%2C%20p3%20%3D%203%2C%20p4%20%3D%204%20)%20-%3E%0A%09console.log(p1%2C%20p2%2C%20spread%2C%20p3%2C%20p4)%0A%0Atest3()%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20p1%20%3D%201%2C%20p2%20%3D%202%2C%20spread%20%3D%20%5B%5D%2C%20p3%20%3D%203%2C%20p4%20%3D%204%0Atest3(9%2C%208%2C%207%2C%206)%3B%20%20%20%20%20%20%20%23%20p1%20%3D%209%2C%20p2%20%3D%208%2C%20spread%20%3D%20%5B%5D%2C%20p3%20%3D%207%2C%20p4%20%3D%206%0Atest3(9%2C%208%2C%207%2C%206%2C%205%2C%204)%3B%20%23%20p1%20%3D%209%2C%20p2%20%3D%208%2C%20spread%20%3D%20%5B7%2C%206%5D%2C%20p3%20%3D%205%2C%20p4%20%3D%204


This has already been discussed and the decision was not to include more general pattern matching such as this in ES6.

Reclassify issue as a Harmony feature request


I would love to see it in a spec. With this pattern you can save a lot of time and lines of code.
One of the common example is a working with a DOM tree:

```ecmascript6
let [firstOne, ...rest, lastOne] = document.findAll(".someClass");
firstOne.classList.add("first");
lastOne.classList.add("last");
```


(In reply to comment #3)
> I would love to see it in a spec. With this pattern you can save a lot of time
> and lines of code.
> One of the common example is a working with a DOM tree:
>
> ```ecmascript6
> let [firstOne, ...rest, lastOne] = document.findAll(".someClass");
> firstOne.classList.add("first");
> lastOne.classList.add("last");
> ```

I agree with Egor, it's quite logical.


I think, it good idea, and can be used everywhere. E.G.:

```ecmascript6
function download (...files, callback) {
var downloaded = 0;

for (let i of files) {
downloadSingle(files[i], function () {
downloaded++;
if (downloaded == files.length) callback();
});
}


}

download( 'file1.txt', 'file2.txt', function() {
alert('ready');
});
```

In such way "array_udiff" works in PHP & php.js:

```php
array array_uintersect ( array $array1 , array $array2 [, array $... ], callable $value_compare_func )
```

It can be usefull


+1. Its logical


changed priority to normal


Bulk closing all Harmony bugs. Proposals should be tracked on GitHub. The ES wiki is completely defunct at this point.