Table of Contents

This proposal has progressed to the Draft ECMAScript 6 Specification, which is available for review here: specification_drafts. Any new issues relating to them should be filed as bugs at http://bugs.ecmascript.org. The content on this page is for historic record only and may no longer reflect the current state of the feature described within.

Overview

Generator expressions were introduced in JavaScript 1.8. Generator expressions are a convenient, declarative form for creating generators with a syntax based on array comprehensions. Generator expressions also provide a convenient refactoring pattern, making it easy to switch between eager and on-demand generation of values in a sequence simply by changing the bracketing.

Because generator expressions desugar to an application of iterators, the surface syntax uses for-of rather than for-in.

Examples

Extracting pages on demand from an array of URL’s:

(xhrGet(url) for (url of getURLs()))

Filtering a sequence:

(x for (x of generateValues()) if (x.color === ‘blue’))

Lazy cartesian product

(xhrGet(row, column) for (row of rows()) for (column of columns()))

Syntax

PrimaryExpression ::= ...
                   |  "(" Expression ("for" "(" LHSExpression "of" Expression")")+ ("if" "(" Expression ")")? ")"

Translation

A generator expression:

( Expression0 for ( LHSExpression1 of Expression1 ) ... for ( LHSExpressionn ) if ( Expression )opt )

can be defined by expansion to the expression:

(function () {
    for (let LHSExpression1 of Expression1 ) {
        ...
        for (let LHSExpressionn of Expressionn ) {
            if ( Expression )opt
                yield (Expression0);
            }
        }
    }
})()

Notes

Background motivation for the syntactic sugar afforded by generator expressions:

  • Peter Norvig’s Sudoku solver based on constraint propagation, written in Python
  • My port of Peter’s solver to JS1.8

The critical uses of generator expressions, e.g., the actual parameter to all in:

    if (all(eliminate(values, s, d2) for (d2 of values[s]) if (d2 != d)))
        return values;

can only be desugared to generation function applications or an equivalent lazy iterator construct. They cannot be replaced with array comprehensions or any such eager construct without the solver taking exponential time and space creating eagerly populated arrays where it would have stopped early using lazy generator expressions, thanks to constraint propagation. Note how all is defined:

function all(seq) {
    for (let e in seq)
        if (!e)
            return false;
    return true;
}

so as to stop as soon as a value in the iterated sequence is falsy.

The JS1.8 version has some XXX comments and helper functions that show where methods such as the Array extras (Array.prototype.every instead of the custom all shown above, e.g.) are not iterator-friendly. This suggests the need for more generic methods that abstract over arrays and iterators.

Brendan Eich 2010/06/27 19:47

Another note: yield is verboten in a generator expression, to uphold TCP.

Brendan Eich 2011/03/24 18:12

 
harmony/generator_expressions.txt · Last modified: 2013/07/11 23:59 by rwaldron
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki