Block lambda grammar: BlockArguments

Brendan Eich brendan at mozilla.org
Sat Jan 14 09:48:09 PST 2012


> Brendan Eich <mailto:brendan at mozilla.org>
> January 14, 2012 9:41 AM
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 13, 2012 9:09 PM
>>
>> If I read the grammar correctly, then you can do things such as (read 
>> "~~~>" as "desugars to"):
>>
>>      myfunc {|| } {|| } (arg3) (arg4)  ~~~>  myfunc({|| }, {|| }, 
>> arg3, arg4)
>>
>> The above is a function call with 4 arguments. My wish would be 
>> different: I would want to put lambdas after a function or method 
>> call and treat those lambdas as additional arguments:
>>
>>      myfunc(arg1, arg2) {|| } {|| }  ~~~>  myfunc(arg1, arg2, {|| }, 
>> {|| })
>>      myfunc {|| } {|| }  ~~~>  myfunc({|| }, {|| })
>
> The closing parenthesis after arg2 really ought to mean end of formal 
> parameter list. Anything else is too magical.

s/formal/actual/

/be
>>
>> Rationale: I would always make lambdas trailing arguments, similar to
>>      if (cond) {} {}
>> And I would rather achieve this effect without currying.
>
> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ?
>
> Your use-case is satisfied by returning a function (memoized, 
> singleton even), but the symmetry between (arg1, ... argN) and 
> space-separated BlockArguments should not be broken.
>
>> Following a block with a non-block doesn’t seem like a good idea.
>
> This was an explicit goal, in order to support use-cases including 
> setTimeout and promises APIs.
>>
>> Has the other approach been considered?
>
> Yes, see
>
> https://mail.mozilla.org/pipermail/es-discuss/2011-May/014675.html
>
> /be
>>
>> -- 
>> Dr. Axel Rauschmayer
>> axel at rauschma.de <mailto:axel at rauschma.de>
>>
>> home: rauschma.de <http://rauschma.de>
>> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
>> blog: 2ality.com <http://2ality.com>
>>
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 13, 2012 12:58 PM
>> Fixed: 
>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival&do=diff
>>
>> The LeftHandSideExpression productions and their kids (NewExpression 
>> and CallExpression) are funky and I keep misremembering how 
>> NewExpression is what bottoms out via MemberExpression -> 
>> PrimaryExpression at Identifier.
>>
>> /be
>>
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 12, 2012 11:43 PM
>>> Brendan Eich <mailto:brendan at mozilla.org>
>>> January 12, 2012 11:39 PM
>>>   v.map {|e| e*e}
>>
>> Er, not even that -- Arguments required in a CallExpression, so 
>> v().map or v.map() but not just v.map. Fixes coming tomorrow.
>>
>> /be
>>>
>>> or
>>>
>>>   get_map() {|e| e*e}
>>>
>>> or similar. I will fix.
>>>
>>> /be
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 12, 2012 11:16 PM
>>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival
>>>
>>> I’m trying to understand the syntax:
>>> BlockArguments :
>>> BlockLambda
>>> BlockArguments [no LineTerminator here] BlockLambda
>>> BlockArguments [no LineTerminator here] ( InitialValue )
>>>
>>> - Wouldn’t this allow the following? BlockLambda [no LineTerminator 
>>> here] BlockLambda
>>> - InitialValue means that paren-free can be combined with arguments 
>>> that aren’t blocks, right?
>>>
>>> myLoopFunc(initValue1)(initValue2) { | arg1, arg2 | ... }
>>>
>>> I think I would prefer the following (IIRC, more like Ruby):
>>>
>>> myLoopFunc(initValue1, initValue2) { | arg1, arg2 | ... }
>>>
>>>
>>>
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 12, 2012 11:39 PM
>>> Axel Rauschmayer <mailto:axel at rauschma.de>
>>> January 12, 2012 11:16 PM
>>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival
>>>
>>> I’m trying to understand the syntax:
>>> BlockArguments :
>>>      BlockLambda
>>>      BlockArguments [no LineTerminator here] BlockLambda
>>>      BlockArguments [no LineTerminator here] ( InitialValue )
>>>
>>> - Wouldn’t this allow the following? BlockLambda [no LineTerminator 
>>> here] BlockLambda
>>
>> Yes.
>>
>>> - InitialValue means that paren-free can be combined with arguments 
>>> that aren’t blocks, right?
>>
>> Yes.
>>>
>>> myLoopFunc(initValue1)(initValue2) { | arg1, arg2 | ... }
>>
>> No, the myLoopFunc(initValue1) is a CallExpression -- see
>> CallWithBlockArguments :
>>      CallExpression [no LineTerminator here] BlockArguments
>>   
>> The *return value* of that ordinary CallExpression is the callee of the paren-free call.
>>>
>>> I think I would prefer the following (IIRC, more like Ruby):
>>>
>>> myLoopFunc(initValue1, initValue2) { | arg1, arg2 | ... }
>>>
>>
>> That parses, as described above. The two-argument CallExpression must 
>> return a function that takes the block arguments.
>>
>> I see a problem in the grammar in the strawman, now that you mention 
>> it: no way to produce a simple identifier callee from CallExpression, 
>> so no
>>
>>   map {|e| e*e}
>>
>> only
>>
>>   v.map {|e| e*e}
>>
>> or
>>
>>   get_map() {|e| e*e}
>>
>> or similar. I will fix.
>>
>> /be
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 12, 2012 11:16 PM
>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival
>>
>> I’m trying to understand the syntax:
>> BlockArguments :
>> BlockLambda
>> BlockArguments [no LineTerminator here] BlockLambda
>> BlockArguments [no LineTerminator here] ( InitialValue )
>>
>> - Wouldn’t this allow the following? BlockLambda [no LineTerminator 
>> here] BlockLambda
>> - InitialValue means that paren-free can be combined with arguments 
>> that aren’t blocks, right?
>>
>> myLoopFunc(initValue1)(initValue2) { | arg1, arg2 | ... }
>>
>> I think I would prefer the following (IIRC, more like Ruby):
>>
>> myLoopFunc(initValue1, initValue2) { | arg1, arg2 | ... }
>>
>>
>>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> Axel Rauschmayer <mailto:axel at rauschma.de>
> January 13, 2012 9:09 PM
>
> If I read the grammar correctly, then you can do things such as (read 
> "~~~>" as "desugars to"):
>
>      myfunc {|| } {|| } (arg3) (arg4)  ~~~>  myfunc({|| }, {|| }, 
> arg3, arg4)
>
> The above is a function call with 4 arguments. My wish would be 
> different: I would want to put lambdas after a function or method call 
> and treat those lambdas as additional arguments:
>
>      myfunc(arg1, arg2) {|| } {|| }  ~~~>  myfunc(arg1, arg2, {|| }, 
> {|| })
>      myfunc {|| } {|| }  ~~~>  myfunc({|| }, {|| })
>
> Rationale: I would always make lambdas trailing arguments, similar to
>      if (cond) {} {}
> And I would rather achieve this effect without currying. Following a 
> block with a non-block doesn’t seem like a good idea.
>
> Has the other approach been considered?
>
> -- 
> Dr. Axel Rauschmayer
> axel at rauschma.de <mailto:axel at rauschma.de>
>
> home: rauschma.de <http://rauschma.de>
> twitter: twitter.com/rauschma <http://twitter.com/rauschma>
> blog: 2ality.com <http://2ality.com>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
> Brendan Eich <mailto:brendan at mozilla.org>
> January 13, 2012 12:58 PM
> Fixed: 
> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival&do=diff
>
> The LeftHandSideExpression productions and their kids (NewExpression 
> and CallExpression) are funky and I keep misremembering how 
> NewExpression is what bottoms out via MemberExpression -> 
> PrimaryExpression at Identifier.
>
> /be
>
> Brendan Eich <mailto:brendan at mozilla.org>
> January 12, 2012 11:43 PM
>> Brendan Eich <mailto:brendan at mozilla.org>
>> January 12, 2012 11:39 PM
>>   v.map {|e| e*e}
>
> Er, not even that -- Arguments required in a CallExpression, so 
> v().map or v.map() but not just v.map. Fixes coming tomorrow.
>
> /be
>>
>> or
>>
>>   get_map() {|e| e*e}
>>
>> or similar. I will fix.
>>
>> /be
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 12, 2012 11:16 PM
>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival
>>
>> I’m trying to understand the syntax:
>> BlockArguments :
>> BlockLambda
>> BlockArguments [no LineTerminator here] BlockLambda
>> BlockArguments [no LineTerminator here] ( InitialValue )
>>
>> - Wouldn’t this allow the following? BlockLambda [no LineTerminator 
>> here] BlockLambda
>> - InitialValue means that paren-free can be combined with arguments 
>> that aren’t blocks, right?
>>
>> myLoopFunc(initValue1)(initValue2) { | arg1, arg2 | ... }
>>
>> I think I would prefer the following (IIRC, more like Ruby):
>>
>> myLoopFunc(initValue1, initValue2) { | arg1, arg2 | ... }
>>
>>
>>
> Brendan Eich <mailto:brendan at mozilla.org>
> January 12, 2012 11:39 PM
>> Axel Rauschmayer <mailto:axel at rauschma.de>
>> January 12, 2012 11:16 PM
>> http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival
>>
>> I’m trying to understand the syntax:
>> BlockArguments :
>>      BlockLambda
>>      BlockArguments [no LineTerminator here] BlockLambda
>>      BlockArguments [no LineTerminator here] ( InitialValue )
>>
>> - Wouldn’t this allow the following? BlockLambda [no LineTerminator 
>> here] BlockLambda
>
> Yes.
>
>> - InitialValue means that paren-free can be combined with arguments 
>> that aren’t blocks, right?
>
> Yes.
>>
>> myLoopFunc(initValue1)(initValue2) { | arg1, arg2 | ... }
>
> No, the myLoopFunc(initValue1) is a CallExpression -- see
> CallWithBlockArguments :
>      CallExpression [no LineTerminator here] BlockArguments
>   
> The *return value* of that ordinary CallExpression is the callee of the paren-free call.
>>
>> I think I would prefer the following (IIRC, more like Ruby):
>>
>> myLoopFunc(initValue1, initValue2) { | arg1, arg2 | ... }
>>
>
> That parses, as described above. The two-argument CallExpression must 
> return a function that takes the block arguments.
>
> I see a problem in the grammar in the strawman, now that you mention 
> it: no way to produce a simple identifier callee from CallExpression, 
> so no
>
>   map {|e| e*e}
>
> only
>
>   v.map {|e| e*e}
>
> or
>
>   get_map() {|e| e*e}
>
> or similar. I will fix.
>
> /be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/e7377b23/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1290 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/e7377b23/attachment-0002.jpg>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: postbox-contact.jpg
Type: image/jpeg
Size: 1222 bytes
Desc: not available
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/e7377b23/attachment-0003.jpg>


More information about the es-discuss mailing list