yield syntax (diverging from: How would shallow generators compose with lambda?)

Brendan Eich brendan at mozilla.com
Sun May 17 11:00:22 PDT 2009


This may be breaking a butterfly on a wheel, but I am game if it  
improves the state of the strawman proposals.

On May 15, 2009, at 7:16 PM, David-Sarah Hopwood wrote:

> My point was that the example of 'yield (foo)' (that is, yield as a
> prefix operator applied to the expression '(foo)') shows that the  
> prefix
> operator syntax cannot possibly be easier to specify than the function
> call syntax -- contrary to what you appeared to be arguing above.

Analogous to direct vs. indirect eval in ES5 (15.1.2.1.1), there is no  
purely syntactic specification for what Neil proposes. A runtime check  
is required. So I don't see why you are focusing only on syntax here.

All the costs count, but considering "who pays" can trump "how much";  
see the postscript below. I'm more concerned with usability than  
implementability, but the latter is not hard and there's no soundness  
issue.


> In fact I think it is much harder to do correctly.

See below, it's quite easy.


>> Yes, but it's not that complicated. SpiderMonkey and Rhino do it.  
>> Code
>> size burden is in the noise.
>
> Hmm. SpiderMonkey and Rhino use ad-hoc parsers. Show me an unambiguous
> grammar for the prefix yield operator, and then I'll concede the  
> point :-)

Python 2.5 has essentially the same issues, and it has a formal  
grammar (several, the one CPython uses and at least one other at  
antlr.org). From CPython's Grammar/Grammar EBNF:

$ grep yield Grammar
expr_stmt: testlist (augassign (yield_expr|testlist) |
                      ('=' (yield_expr|testlist))*)
flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt |  
yield_stmt
yield_stmt: yield_expr
atom: ('(' [yield_expr|testlist_gexp] ')' |
yield_expr: 'yield' [testlist]

What we are discussing is almost trivial in terms of usability, but  
the difference is big enough to care about, IMHO. Either you have to  
write, in Neil's approach:

yield (E)      (or just yield() to yield undefined)

or in the Pythonic approach:

(yield E)      (or just (yield))

with the parentheses in the Pythonic approach not required when the  
yield expression is either (a) the entire expression in an expression  
statement; (b) the right-hand side of an assignment.

Python differs from JS by having only assignment statements, not  
assignment expressions, which simplifies the problem a bit, as the  
grep output cited above shows.

In any case, yield E; as a statement is the most common kind of yield  
in real-world Python code, both because it came first and because  
sending values to generators is less commonly done than iterating  
generators.

So with either approach you have some "insignificant, silly  
parentheses" -- but with Neil's approach you have "lots" more because  
the expression-statement yield must have at least () after the keyord.

This tips the usability contest in favor of the Pythonic approach.

In no case are there ambiguities for a bottom up grammar. The right  
parenthesis avoids nasty automatic semicolon insertion problems that  
plagued the unbracketed low-precedence expression on the right of a  
high-precedence prefix in the case of expression-bodied functions, AKA  
"expression closures" (see https://mail.mozilla.org/pipermail/es-discuss/2008-October/007888.html) 
.

To confirm this, I patched WebKit's Bison grammar for JS to support  
yield //a la// JS1.7. I didn't hook up the semantic actions, just  
verified zero reduce-reduce conflicts. Patch attached below --  
comments welcome (including from you WebKit lurkers :-).

/be

P.S. Bean-counting productions in a bottom-up grammar is counting the  
wrong cost, given the few implementors and their greater skills,  
compared to the many users who need to be spared those painful and  
fruitless parentheses.

Bean-counting productions in a traditional bottom-up grammar is also  
silly given how many are required for ES1-3. From the patch, notice  
all the existing specialized NoIn/NoBF/NoNode variants in parser/ 
Grammar.y (NoBF = No Brace at Front, as far as I can tell).

Much of that production-forking could be avoided by using either  
parameterized LR parsing (www.cs.lth.se/Research/LDTA2004/d09_TheimannNeubauer.pdf) 
, or else top-down ("ad-hoc" or not :-P) parsing.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch
Type: application/octet-stream
Size: 8785 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20090517/eb8f4608/attachment-0001.obj>
-------------- next part --------------



More information about the es-discuss mailing list