yield syntax (diverging from: How would shallow generators compose with lambda?)
brendan at mozilla.com
Sun May 17 21:27:52 PDT 2009
On May 17, 2009, at 6:39 PM, Neil Mix wrote:
> On May 17, 2009, at 7:01 PM, Brendan Eich wrote:
>> The mandatory parentheses could be avoided by breaking from
>> Python's precedent and making yield a canonical unary (that is,
>> high-)precedence operator like delete, !, etc. But then almost any
>> algebraic or logical expression computing the value to yield would
>> need parentheses, and people would make mistakes such as yield a +
>> b where they meant yield(a + b) -- as in Python -- but got yield(a)
>> + b.
> I'm going to make the argument that this is about where the
> parenthesis go -- not *if* -- but where.
Yes, this is the issue.
> - we could always allow parenthesis to be dropped when the yield is
> the entire expression of an expression statement or the right-hand
> side of an assignment.
Right-hand side of assignment is ok without parens in Python because
assignment is a statement.
In JS if you allow assignment expressions ending in unparenthesized
yields, then you can have unparenthesized yields in argument and
initialiser lists, comma expressions, and in the middle and final
operand positions in ternary (?:) expressions.
> - in my experience with JS 1.7 I almost always had to parenthesize
> the yield expression when it was in some other kind of expression.
> An in the cases where parenthesis weren't required, I parenthesized
> anyway to avoid ambiguity and maintain coding style consistency.
> (And because I got tired of predicting incorrectly whether or not
> parens would be required in a particular context.)
The only contexts we allow you not to parenthesize in JS1.7 are
assignment expressions and final argument in list. But see above --
the assignment expression loophole is big enough to allow
foo(a = yield b, c);
One argument, or two?
Comma is low enough precedence that users (with or without Python
exposure) don't view it as an operator.
> So I would argue that there are two syntactical forms of yield,
> yield E and (yield E), and that the rules regarding the requirement
> for parenthesis are hard to predict (from personal experience).
> Therefore, I argue that it would make sense to simplify a bit:
> - the yield E form may be used when it is the entire expression of
> an expression statement
> - all other times it must be parenthesized
Agreed; this closes the assignment expression loophole.
> Which is *kind of* a way of saying, if you're ignoring the send
> value, you don't have to parenthesize. But if you use the send
> value, you must parenthesize.
> And now that we've made clear the definition of parenthesized and
> non-parenthesized forms of yield, we can proceed to argue that
> yield(E) is a valid form of parenthesis, as much so as (yield E).
Nothing prevents you from writing yield(E) of course -- but you're
arguing that foo(a = yield(b), c) should be enough, no extra parens
required -- no foo(a = (yield(b)), c). Right?
> Pros for yield(E):
> - backward compatible
But for this to be true, we would need to use the direct-eval
detection hack I mentioned previously.
> - easier to read (to my eye)
> - it "feels" more correct to me in context of the when-using-send-
> value rule
These are subjective enough there's no point in arguing. I hear ya.
> Pros for (yield E):
> - consistent with python
> - doesn't present any is-it-a-function? ambiguities
These are more objective (no look & feel ;-). There is a borrowing
from Python. There isn't a function call going on.
More information about the es-discuss