Proposal: Generator returning a value should throw SyntaxError

Adam Ahmed aahmed at atlassian.com
Thu Sep 26 18:55:32 PDT 2013


Hi all,

Long-time lurker, first-time poster. Profuse apologies if this was
mentioned before and I failed to find it.

I've been using V8's generator implementation in Node 0.11.x recently, and
have come across what I believe is a footgun with generators currently.
That is - the ability to return a value, not just yield a value. I am
proposing that while `return;` is still allowed, `return value;` becomes a
syntax error within generators.

An alternative proposal is to implicitly treat `return value` within a
generator as `yield value; return;`, however this would create a difference
in the semantics between `return;` and `return undefined;` that currently
doesn't exist and I believe such a thing has been proposed before
unsuccessfully in http://esdiscuss.org/topic/void-as-a-value

There are a couple reasons I believe this should be a syntax error.

Firstly, for-of doesn't support it, thereby making it a bit halfway-there
to start with:

    function * upToThree() {
        yield 1;
        yield 2;
        return 3;
    }

    for(var num of upToThree()) {
        console.log(num); // 1, then 2. Never logs 3
    }

It also makes it impossible to return an empty iteration (or at least,
impossible to distinguish an empty iteration from an iterator that has a
single undefined value):

    function* empty() {
        return; // or is it
        // return undefined; ?
    }

Supporting that style also has knock-on effects for consuming generators
like takeUntil (which will execute a function on each value, and yield them
until it reaches one where the function returns true). Functions like this
will have to precompute the _next_ value to see if they should yield or
return the current value. For example:

    function * takeUntilThree(iterator) {
        var curr, next;
        next = iterator.next();
        while(!next.done) {
            curr = next;
            next = iterator.next();
            if (next === 3) { // only know which to do based on the _next_
value)
                return curr.value;
            } else {
                yield curr.value;
            }
        }
        return curr && curr.value; // Note: the undefined vs empty problem
is still not fixed.
    }

    var untilThree = takeUntilThree(upToThree());
    untilThree.next(); // { value : 1, done : false }
    untilThree.next(); // { value : 2, done : true }

For these reasons, I find the ability to return a value from a generator is
not useful (though I may have missed a use case).

Given that any generator with an occurrence of `return value;` can be
reimplemented cleanly as

    yield value;
    return;

I suspect we can remove the footgun by throwing early when an attempt to
return a value is encountered within a generator.

I must admit I'm not across how difficult this would be for implementers.
But I believe it will remove potential danger for developers without
harming any real usages.

Thanks for listening! Apologies for length!

Adam
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130927/3758d16c/attachment-0001.html>


More information about the es-discuss mailing list