While exploring use cases for data-parallel concurrency in JavaScript using the 
ParallelArray API (see 
http://wiki.ecmascript.org/doku.php?id=strawman:data_parallelism) I found 
myself wanting better support for multiple results from a single parallel 
operation. More precisely, I wanted a neat way to do array-of-objects to 
object-of-arrays transformations.

The same problem exists with the Array API, probably to a lesser extent as one 
can always fall back to explicit iterators. So, for sake of simplicity, I will 
use ordinary Array objects here. Consider the following simple example:

function foo (x) {
  return {odd: (x%2), twice: 2*x};
}

[1,2,3,4].map(foo);

This will produce an array of objects that have two properties: 'odd' which 
encodes whether the corresponding source element was odd and 'twice' that gives 
twice the value of the source element. What I typically want, though, are two 
arrays containing the odd and twice values, respectively. For instance, I might 
want to use 'odd' in a consecutive filter operation on 'twice'. One way to 
achieve this is to write a little unzip helper:

Array.unzip = function unzip(a) {
  var r = {};
  for (var e in a) {
    for (var k in a[e]) {
      (r[k] || (r[k]=[]))[e] = a[e][k];
    }
  }
  return r;
}

which then allows me to conveniently specify the array-of-objects to 
object-of-arrays conversion like so:

result = [1,2,3,4].map(foo).unzip();

Throw in destructuring as per 
http://wiki.ecmascript.org/doku.php?id=harmony:destructuring, and you get a 
pretty workable

{odd, twice} = [1,2,3,4].map(foo).unzip();

Ideally, when implementing this, map should already materialize its result as 
two separate arrays if its result is only used by an application of unzip. A 
built in unzip with fixed, well known semantics would make this feasible 
without the need to analyze what a potential user defined unzip does. 

Improving on this some more, one could also extend destructuring to include the 
required array-of-objects to object-of-arrays transformation and thus directly 
allow the programmer to write

{odd, twice} = [1,2,3,4].map(foo);

The new semantics of destructuring would have an additional case that, whenever 
the rhs is an array like value but the lhs is an object pattern, the rhs is 
first transformed into an object of arrays before the pattern is applied. An 
implementation is of course free to perform the two steps at once, allowing for 
optimizations in cases where only parts of the elements are selected, as in

{odd} = [1,2,3,4].map(foo);

Extending destructuring this way does not impact other cases of destructuring. 
Consider the case where the programmer expected an object but got an array of 
values. The expression

{odd, twice} = [1,2,3,4];

would still yield odd and twice as undefined. If the lhs is an array pattern, 
the extended semantics do not apply at all.

To summarize, I propose two things. Either, rather conservatively, that an 
unzip primitive be added to Array/ParallelArray or that destructuring be 
extended such that if it encounters a lhs object pattern and a rhs evaluating 
to an array of objects that it be destructured into objects of arrays 
corresponding to variables specified in the lhs.

Stephan

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to