Block lambda grammar: BlockArguments
Axel Rauschmayer <mailto:axel at rauschma.de> January 12, 2012 11:16 PM 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.
> 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/20120112/c36c9fe6/attachment-0001.html> -------------- 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/20120112/c36c9fe6/attachment-0001.jpg>
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.
> 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 | ... } > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120112/8845f4df/attachment.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/20120112/8845f4df/attachment.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/20120112/8845f4df/attachment-0001.jpg>
Fixed: 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.
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 | ... } >> >> >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > 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 | ... } > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120113/5f81f72a/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/20120113/5f81f72a/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/20120113/5f81f72a/attachment-0003.jpg>
Fixed: 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.
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?
> 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. 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 home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/6853d702/attachment.html>
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.
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
> 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. > > 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 | ... } > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/bc501988/attachment-0001.html> -------------- 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/bc501988/attachment-0002.jpg> -------------- 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/bc501988/attachment-0003.jpg>
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/
> 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>
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.
I think that’s how Ruby does it. I’m on the fence. It is indeed quite magical (and not the good kind of magical).
Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ?
BlockArguments : BlockLambda BlockArguments [no LineTerminator here] BlockLambda BlockArguments [no LineTerminator here] ( InitialValue )
I still don’t fully understand the ( InitialValue ) at the end – it’s a single value in parens that can come after several blocks. If Ruby-style magic isn’t an option then I would expect (and prefer) that there were only two calling “modes”:
- Traditional: myfunc(arg1, arg2, ...}
- Paren-free – lambdas only: myfunc {|| body1} {|| body2} ...
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.
With the above I meant: In paren-free mode, following a block with a non-block doesn’t seem like a good idea. With a normal paren call, I don’t see any problems.
>> 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. I think that’s how Ruby does it. I’m on the fence. It is indeed quite magical (and not the good kind of magical). > Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? BlockArguments : BlockLambda BlockArguments [no LineTerminator here] BlockLambda BlockArguments [no LineTerminator here] ( InitialValue ) I still don’t fully understand the ( InitialValue ) at the end – it’s a single value in parens that can come after several blocks. If Ruby-style magic isn’t an option then I would expect (and prefer) that there were only two calling “modes”: - Traditional: myfunc(arg1, arg2, ...} - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... >> 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. With the above I meant: In paren-free mode, following a block with a non-block doesn’t seem like a good idea. With a normal paren call, I don’t see any problems. -- Dr. Axel Rauschmayer axel at rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/8b6dc1cb/attachment.html>
Axel Rauschmayer <mailto:axel at rauschma.de> January 14, 2012 1:32 PM
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.
I think that’s how Ruby does it.
Indeed:
$ ruby def foo(a,b) yield a+b end foo(1,2) {|x| puts x} 3D
I’m on the fence. It is indeed quite magical (and not the good kind of magical).
It's way too magical in my view to retrofit to JS. Again, making "if" and "while" and so on into block-lambda calling functions seems a wild goose chase. These forms take statements, not just block-statements (and not block-lambdas to call). They're built into the language via the C-like syntax.
Imitating "if" etc. is fine. It's a motivation for the paren-free and semicolon-free CallWithBlockArguments statement form.
And such imitation is doable via the strawman grammar, simply by returning a function (currying a bit). Singletons or pairs can be used if there's no need to retain the "if condition":
function myIf(cond) { // The block-lambdas here are singletons (no upvars)... return cond ? {|t, e| t} : {|t, e| e}; }
myIf (x > y) {|| "greater"} {|| "not greater"}
Of course, one might want a dummy "else" ("myElse") in between the then and else blocks.
Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ?
BlockArguments : BlockLambda BlockArguments [no LineTerminator here] BlockLambda BlockArguments [no LineTerminator here] ( InitialValue )
I still don’t fully understand the ( InitialValue ) at the end – it’s a single value in parens that can come after several blocks. If Ruby-style magic isn’t an option then I would expect (and prefer) that there were only two calling “modes”:
- Traditional: myfunc(arg1, arg2, ...}
- Paren-free – lambdas only: myfunc {|| body1} {|| body2} ...
The objection (if you read the whole thread containing the message I cited, I think you'll find it) was that requiring only block-lambdas for the paren-free call form means expression arguments, even ones as simple as numeric literals, must be bracketed by {|| and }. Why not allow ( and ) instead?
One counter-argument is that this looks the argument list of a call expression whose callee is everything to the left. But paren-free call syntax supports newline termination, so I added the ... ( Initial Value ) production to satisfy setTimeout-like use cases without requiring {|| and | as brackets.
If this alternate production bites back in some way, or is simply under-used or too surprising, I'll yank it.
Indeed I could simplify CallWithBlockArguments to take only one BlockLambda argument but that seems unnecessarily restrictive. More comments welcome.
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.
With the above I meant: In paren-free mode, following a block with a non-block doesn’t seem like a good idea. With a normal paren call, I don’t see any problems.
The consequences might include
setTimeout {|arg| ...} {|| 1000} {|| x}
That is a bit harsh since 1000 (one second) is a literal and /* compute arg here */ is typically simply a pass-by-value reference to a variable in the scope of this setTimeout call, e.g. x in this example.
The strawman therefore supports
setTimeout {|arg| ...} (1000) (x)
for example.
Could we go further and support certain primary expressions, namely all of the PrimaryExpression right-hand sides except for object literal?
NonObjectLiteralPrimaryExpression : this Identifier Literal ArrayLiteral ( Expression )
?
Not a problem grammatically except for the added complexity, and the specific usability issues arising from that slight complexity:
- Leaving out object literal means one must parenthesize an object literal but not an array literal.
- Allowing K but not K+1, requiring instead (K+1), may blow back with users.
> Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 1:32 PM >>> 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. > > I think that’s how Ruby does it. Indeed: $ ruby def foo(a,b) yield a+b end foo(1,2) {|x| puts x} 3D > I’m on the fence. It is indeed quite magical (and not the good kind of > magical). It's way too magical in my view to retrofit to JS. Again, making "if" and "while" and so on into block-lambda calling functions seems a wild goose chase. These forms take *statements*, not just block-statements (and not block-lambdas to call). They're built into the language via the C-like syntax. Imitating "if" etc. is fine. It's a motivation for the paren-free and *semicolon-free* CallWithBlockArguments statement form. And such imitation is doable via the strawman grammar, simply by returning a function (currying a bit). Singletons or pairs can be used if there's no need to retain the "if condition": function myIf(cond) { // The block-lambdas here are singletons (no upvars)... return cond ? {|t, e| t} : {|t, e| e}; } myIf (x > y) {|| "greater"} {|| "not greater"} Of course, one might want a dummy "else" ("myElse") in between the then and else blocks. > >> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? > > BlockArguments : > BlockLambda > BlockArguments [no LineTerminator here] BlockLambda > BlockArguments [no LineTerminator here] ( InitialValue ) > > I still don’t fully understand the ( InitialValue ) at the end – it’s > a single value in parens that can come after several blocks. If > Ruby-style magic isn’t an option then I would expect (and prefer) that > there were only two calling “modes”: > > - Traditional: myfunc(arg1, arg2, ...} > - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... The objection (if you read the whole thread containing the message I cited, I think you'll find it) was that requiring *only* block-lambdas for the paren-free call form means expression arguments, even ones as simple as numeric literals, must be bracketed by {|| and }. Why not allow ( and ) instead? One counter-argument is that this looks the argument list of a call expression whose callee is everything to the left. But paren-free call syntax supports newline termination, so I added the ... ( Initial Value ) production to satisfy setTimeout-like use cases without requiring {|| and | as brackets. If this alternate production bites back in some way, or is simply under-used or too surprising, I'll yank it. Indeed I could simplify CallWithBlockArguments to take only one BlockLambda argument but that seems unnecessarily restrictive. More comments welcome. > >>> 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. > > With the above I meant: In paren-free mode, following a block with a > non-block doesn’t seem like a good idea. With a normal paren call, I > don’t see any problems. The consequences might include setTimeout {|arg| ...} {|| 1000} {|| x} That is a bit harsh since 1000 (one second) is a literal and /* compute arg here */ is typically simply a pass-by-value reference to a variable in the scope of this setTimeout call, e.g. x in this example. The strawman therefore supports setTimeout {|arg| ...} (1000) (x) for example. Could we go further and support certain primary expressions, namely all of the PrimaryExpression right-hand sides except for object literal? NonObjectLiteralPrimaryExpression : this Identifier Literal ArrayLiteral ( Expression ) ? Not a problem grammatically except for the added complexity, and the specific usability issues arising from that slight complexity: * Leaving out object literal means one must parenthesize an object literal but not an array literal. * Allowing K but not K+1, requiring instead (K+1), may blow back with users. /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> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > 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. >> >> 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 | ... } >> >> >> > 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 | ... } >> >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/78316fee/attachment-0001.html> -------------- 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/78316fee/attachment-0002.jpg> -------------- 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/78316fee/attachment-0003.jpg>
If Ruby-style magic isn’t an option then I would expect (and prefer) that there were only two calling “modes”:
- Traditional: myfunc(arg1, arg2, ...}
- Paren-free – lambdas only: myfunc {|| body1} {|| body2} ...
The objection (if you read the whole thread containing the message I cited, I think you'll find it) was that requiring only block-lambdas for the paren-free call form means expression arguments, even ones as simple as numeric literals, must be bracketed by {|| and }. Why not allow ( and ) instead?
(*) One counter-argument is that this looks the argument list of a call expression whose callee is everything to the left. But paren-free call syntax supports newline termination, so I added the ... ( Initial Value ) production to satisfy setTimeout-like use cases without requiring {|| and | as brackets.
If this alternate production bites back in some way, or is simply under-used or too surprising, I'll yank it.
Three arguments in favor of yanking:
-
Thanks to lambdas, setTimeout already looks very nice – even as a parenthesized function call.
-
Putting callable values last is more likely, the grammar rule introduces an odd asymmetry, by not allowing leading a leading ( InitialValue ) . I’m not saying that that would be a desirable feature (currying is fine here), just that trailing non-lambdas seem much rarer than leading non-lambdas.
-
The counter-argument (*) you mention above weighs heavily. Most people (certainly me) probably expect a function or method call when they see a parenthesized value.
The following seems like an elegant and easy to understand rule to me: “The parameters of a function or method call are either parenthesized or paren-free. In the latter case, all parameters must be lambdas.”
>> If Ruby-style magic isn’t an option then I would expect (and prefer) that there were only two calling “modes”: >> >> - Traditional: myfunc(arg1, arg2, ...} >> - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... > > The objection (if you read the whole thread containing the message I cited, I think you'll find it) was that requiring *only* block-lambdas for the paren-free call form means expression arguments, even ones as simple as numeric literals, must be bracketed by {|| and }. Why not allow ( and ) instead? > > (*) One counter-argument is that this looks the argument list of a call expression whose callee is everything to the left. But paren-free call syntax supports newline termination, so I added the ... ( Initial Value ) production to satisfy setTimeout-like use cases without requiring {|| and | as brackets. > > If this alternate production bites back in some way, or is simply under-used or too surprising, I'll yank it. Three arguments in favor of yanking: - Thanks to lambdas, setTimeout already looks very nice – even as a parenthesized function call. - Putting callable values last is more likely, the grammar rule introduces an odd asymmetry, by not allowing leading a leading ( InitialValue ) . I’m not saying that that would be a desirable feature (currying is fine here), just that trailing non-lambdas seem much rarer than leading non-lambdas. - The counter-argument (*) you mention above weighs heavily. Most people (certainly me) probably expect a function or method call when they see a parenthesized value. The following seems like an elegant and easy to understand rule to me: “The parameters of a function or method call are either parenthesized or paren-free. In the latter case, all parameters must be lambdas.” -- Dr. Axel Rauschmayer axel at rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120115/75ddc99c/attachment.html>
Axel Rauschmayer <mailto:axel at rauschma.de> January 14, 2012 4:58 PM
Three arguments in favor of yanking:
- Thanks to lambdas, setTimeout already looks very nice – even as a parenthesized function call.
Good -- and you make a good case here in terms of paren-counting:
setTimeout {|arg| ...} (1000) (x)
is worse by paren-count cost than:
setTimeout({|arg| ...}, 1000, x)
and with the style I expect where there's a space between the setTimeout and the {, worse in total character count even including the commas required in the second form.
Let B be the number of block-lambdas and I be the number of InitialValue expressions. In general we have B spaces (one before each block-lambda) and 2I parens and I spaces (one before each parenthesized InitialValue) or B+3I overhead with the paren-free syntax in the expected style, vs. 2 parens around the whole arg list + 2(B+I-1) ", " pairs between args, for 2(B+I). So the trade-off relation is
paren-free <=> parenthesized
B+3I <=> 2B+2I or
I <=> B
So if I < B, paren-free wins. If I >= B, parenthesized wins by I-B
chars. This ignores readability trade-off between ", " separation and " (" with ")" on the right of each InitialValue.
- Putting callable values last is more likely, the grammar rule introduces an odd asymmetry, by not allowing leading a leading ( InitialValue ) . I’m not saying that that would be a desirable feature (currying is fine here), just that trailing non-lambdas seem much rarer than leading non-lambdas.
Agreed.
- The counter-argument (*) you mention above weighs heavily. Most people (certainly me) probably expect a function or method call when they see a parenthesized value.
I think you are right.
The following seems like an elegant and easy to understand rule to me: “The parameters of a function or method call are either parenthesized or paren-free. In the latter case, all parameters must be lambdas.”
Given the overhead trade-off relation, I'm ditching the whole ( InitialValue ) alternative. Thanks for poking at this!
> Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 4:58 PM > > Three arguments in favor of yanking: > > - Thanks to lambdas, setTimeout already looks very nice – even as a > parenthesized function call. Good -- and you make a good case here in terms of paren-counting: setTimeout {|arg| ...} (1000) (x) is worse by paren-count cost than: setTimeout({|arg| ...}, 1000, x) and with the style I expect where there's a space between the setTimeout and the {, worse in total character count even including the commas required in the second form. Let B be the number of block-lambdas and I be the number of InitialValue expressions. In general we have B spaces (one before each block-lambda) and 2I parens and I spaces (one before each parenthesized InitialValue) or B+3I overhead with the paren-free syntax in the expected style, vs. 2 parens around the whole arg list + 2(B+I-1) ", " pairs between args, for 2(B+I). So the trade-off relation is paren-free <=> parenthesized B+3I <=> 2B+2I or I <=> B So if I < B, paren-free wins. If I >= B, parenthesized wins by I-B chars. This ignores readability trade-off between ", " separation and " (" with ")" on the right of each InitialValue. > - Putting callable values last is more likely, the grammar rule > introduces an odd asymmetry, by not allowing leading a leading ( > InitialValue ) . I’m not saying that that would be a desirable feature > (currying is fine here), just that trailing non-lambdas seem much > rarer than leading non-lambdas. Agreed. > > - The counter-argument (*) you mention above weighs heavily. Most > people (certainly me) probably expect a function or method call when > they see a parenthesized value. I think you are right. > > The following seems like an elegant and easy to understand rule to me: > “The parameters of a function or method call are either > parenthesized or paren-free. In the latter case, all parameters must > be lambdas.” Given the overhead trade-off relation, I'm ditching the whole ( InitialValue ) alternative. Thanks for poking at this! /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> > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > Brendan Eich <mailto:brendan at mozilla.org> > January 14, 2012 2:41 PM >> Axel Rauschmayer <mailto:axel at rauschma.de> >> January 14, 2012 1:32 PM >>>> 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. >> >> I think that’s how Ruby does it. > Indeed: > > $ ruby > def foo(a,b) > yield a+b > end > foo(1,2) {|x| puts x} > 3D > > >> I’m on the fence. It is indeed quite magical (and not the good kind >> of magical). > > It's way too magical in my view to retrofit to JS. Again, making "if" > and "while" and so on into block-lambda calling functions seems a wild > goose chase. These forms take *statements*, not just block-statements > (and not block-lambdas to call). They're built into the language via > the C-like syntax. > > Imitating "if" etc. is fine. It's a motivation for the paren-free and > *semicolon-free* CallWithBlockArguments statement form. > > And such imitation is doable via the strawman grammar, simply by > returning a function (currying a bit). Singletons or pairs can be used > if there's no need to retain the "if condition": > > function myIf(cond) { > // The block-lambdas here are singletons (no upvars)... > return cond ? {|t, e| t} : {|t, e| e}; > } > > myIf (x > y) {|| "greater"} {|| "not greater"} > > Of course, one might want a dummy "else" ("myElse") in between the > then and else blocks. >> >>> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? >> >> BlockArguments : >> BlockLambda >> BlockArguments [no LineTerminator here] BlockLambda >> BlockArguments [no LineTerminator here] ( InitialValue ) >> >> I still don’t fully understand the ( InitialValue ) at the end – it’s >> a single value in parens that can come after several blocks. If >> Ruby-style magic isn’t an option then I would expect (and prefer) >> that there were only two calling “modes”: >> >> - Traditional: myfunc(arg1, arg2, ...} >> - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... > > The objection (if you read the whole thread containing the message I > cited, I think you'll find it) was that requiring *only* block-lambdas > for the paren-free call form means expression arguments, even ones as > simple as numeric literals, must be bracketed by {|| and }. Why not > allow ( and ) instead? > > One counter-argument is that this looks the argument list of a call > expression whose callee is everything to the left. But paren-free call > syntax supports newline termination, so I added the ... ( Initial > Value ) production to satisfy setTimeout-like use cases without > requiring {|| and | as brackets. > > If this alternate production bites back in some way, or is simply > under-used or too surprising, I'll yank it. > > Indeed I could simplify CallWithBlockArguments to take only one > BlockLambda argument but that seems unnecessarily restrictive. More > comments welcome. >> >>>> 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. >> >> With the above I meant: In paren-free mode, following a block with a >> non-block doesn’t seem like a good idea. With a normal paren call, I >> don’t see any problems. > > The consequences might include > > setTimeout {|arg| ...} {|| 1000} {|| x} > > That is a bit harsh since 1000 (one second) is a literal and /* > compute arg here */ is typically simply a pass-by-value reference to a > variable in the scope of this setTimeout call, e.g. x in this example. > > The strawman therefore supports > > setTimeout {|arg| ...} (1000) (x) > > for example. > > Could we go further and support certain primary expressions, namely > all of the PrimaryExpression right-hand sides except for object literal? > > NonObjectLiteralPrimaryExpression : > this > Identifier > Literal > ArrayLiteral > ( Expression ) > > ? > > Not a problem grammatically except for the added complexity, and the > specific usability issues arising from that slight complexity: > > * Leaving out object literal means one must parenthesize an object > literal but not an array literal. > * Allowing K but not K+1, requiring instead (K+1), may blow back with > users. > > /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> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> 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. >>> >>> 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 | ... } >>> >>> >>> >> 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 | ... } >>> >>> >>> > Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 1:32 PM >>> 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. > > I think that’s how Ruby does it. I’m on the fence. It is indeed quite > magical (and not the good kind of magical). > >> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? > > BlockArguments : > BlockLambda > BlockArguments [no LineTerminator here] BlockLambda > BlockArguments [no LineTerminator here] ( InitialValue ) > > I still don’t fully understand the ( InitialValue ) at the end – it’s > a single value in parens that can come after several blocks. If > Ruby-style magic isn’t an option then I would expect (and prefer) that > there were only two calling “modes”: > > - Traditional: myfunc(arg1, arg2, ...} > - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... > >>> 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. > > With the above I meant: In paren-free mode, following a block with a > non-block doesn’t seem like a good idea. With a normal paren call, I > don’t see any problems. > > -- > 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 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. >> >> 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 | ... } >> >> >> > 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/1060f39e/attachment-0001.html> -------------- 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/1060f39e/attachment-0002.jpg> -------------- 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/1060f39e/attachment-0003.jpg>
Brendan Eich <mailto:brendan at mozilla.org> January 14, 2012 6:31 PM
Given the overhead trade-off relation, I'm ditching the whole ( InitialValue ) alternative. Thanks for poking at this!
Done: doku.php?id=strawman:block_lambda_revival&rev=1326440792&do=diff
> Brendan Eich <mailto:brendan at mozilla.org> > January 14, 2012 6:31 PM > > Given the overhead trade-off relation, I'm ditching the whole ( > InitialValue ) alternative. Thanks for poking at this! Done: http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival&rev=1326440792&do=diff /be -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/e50cab8c/attachment.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/e50cab8c/attachment.jpg>
Cool. I also have a feeling that every paren-free lambda after the first one should have some kind of preceding keyword or name, but I don’t know how one could make that happen. Brace-free object literals? (only half joking)
Cool. I also have a feeling that every paren-free lambda after the first one should have some kind of preceding keyword or name, but I don’t know how one could make that happen. Brace-free object literals? (only half joking) On Jan 15, 2012, at 3:42 , Brendan Eich wrote: >> Brendan Eich January 14, 2012 6:31 PM >> >> Given the overhead trade-off relation, I'm ditching the whole ( InitialValue ) alternative. Thanks for poking at this! > > Done: http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival&rev=1326440792&do=diff > > /be -- Dr. Axel Rauschmayer axel at rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120115/191cab69/attachment.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/20120115/191cab69/attachment.jpg>
Nothing is going to match Smalltalk on this. Keyword parameters are not even on the map because object literals suck the oxygen out of the room. And then you'll want to get rid of the || for empty block parameters.
I say pause with a simpler design and digest, ruminate, prototype, user-test.
Nothing is going to match Smalltalk on this. Keyword parameters are not even on the map because object literals suck the oxygen out of the room. And then you'll want to get rid of the || for empty block parameters. I say pause with a simpler design and digest, ruminate, prototype, user-test. /be > Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 9:35 PM > Cool. I also have a feeling that every paren-free lambda after the > first one should have some kind of preceding keyword or name, but I > don’t know how one could make that happen. Brace-free object literals? > (only half joking) > > On Jan 15, 2012, at 3:42 , Brendan Eich wrote: > > -- > 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 14, 2012 6:42 PM > > Done: > http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival&rev=1326440792&do=diff > > /be > Brendan Eich <mailto:brendan at mozilla.org> > January 14, 2012 6:31 PM >> Axel Rauschmayer <mailto:axel at rauschma.de> >> January 14, 2012 4:58 PM >> >> Three arguments in favor of yanking: >> >> - Thanks to lambdas, setTimeout already looks very nice – even as a >> parenthesized function call. > > Good -- and you make a good case here in terms of paren-counting: > > setTimeout {|arg| ...} (1000) (x) > > is worse by paren-count cost than: > > setTimeout({|arg| ...}, 1000, x) > > and with the style I expect where there's a space between the > setTimeout and the {, worse in total character count even including > the commas required in the second form. > > Let B be the number of block-lambdas and I be the number of > InitialValue expressions. In general we have B spaces (one before each > block-lambda) and 2I parens and I spaces (one before each > parenthesized InitialValue) or B+3I overhead with the paren-free > syntax in the expected style, vs. 2 parens around the whole arg list + > 2(B+I-1) ", " pairs between args, for 2(B+I). So the trade-off relation is > > paren-free <=> parenthesized > B+3I <=> 2B+2I or > I <=> B > > So if I < B, paren-free wins. If I >= B, parenthesized wins by I-B > chars. This ignores readability trade-off between ", " separation and > " (" with ")" on the right of each InitialValue. > >> - Putting callable values last is more likely, the grammar rule >> introduces an odd asymmetry, by not allowing leading a leading ( >> InitialValue ) . I’m not saying that that would be a desirable >> feature (currying is fine here), just that trailing non-lambdas seem >> much rarer than leading non-lambdas. > > Agreed. >> >> - The counter-argument (*) you mention above weighs heavily. Most >> people (certainly me) probably expect a function or method call when >> they see a parenthesized value. > > I think you are right. >> >> The following seems like an elegant and easy to understand rule to me: >> “The parameters of a function or method call are either >> parenthesized or paren-free. In the latter case, all parameters must >> be lambdas.” > > Given the overhead trade-off relation, I'm ditching the whole ( > InitialValue ) alternative. Thanks for poking at this! > > /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> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> Brendan Eich <mailto:brendan at mozilla.org> >> January 14, 2012 2:41 PM >>> Axel Rauschmayer <mailto:axel at rauschma.de> >>> January 14, 2012 1:32 PM >>>>> 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. >>> >>> I think that’s how Ruby does it. >> Indeed: >> >> $ ruby >> def foo(a,b) >> yield a+b >> end >> foo(1,2) {|x| puts x} >> 3D >> >> >>> I’m on the fence. It is indeed quite magical (and not the good kind >>> of magical). >> >> It's way too magical in my view to retrofit to JS. Again, making "if" >> and "while" and so on into block-lambda calling functions seems a >> wild goose chase. These forms take *statements*, not just >> block-statements (and not block-lambdas to call). They're built into >> the language via the C-like syntax. >> >> Imitating "if" etc. is fine. It's a motivation for the paren-free and >> *semicolon-free* CallWithBlockArguments statement form. >> >> And such imitation is doable via the strawman grammar, simply by >> returning a function (currying a bit). Singletons or pairs can be >> used if there's no need to retain the "if condition": >> >> function myIf(cond) { >> // The block-lambdas here are singletons (no upvars)... >> return cond ? {|t, e| t} : {|t, e| e}; >> } >> >> myIf (x > y) {|| "greater"} {|| "not greater"} >> >> Of course, one might want a dummy "else" ("myElse") in between the >> then and else blocks. >>> >>>> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? >>> >>> BlockArguments : >>> BlockLambda >>> BlockArguments [no LineTerminator here] BlockLambda >>> BlockArguments [no LineTerminator here] ( InitialValue ) >>> >>> I still don’t fully understand the ( InitialValue ) at the end – >>> it’s a single value in parens that can come after several blocks. If >>> Ruby-style magic isn’t an option then I would expect (and prefer) >>> that there were only two calling “modes”: >>> >>> - Traditional: myfunc(arg1, arg2, ...} >>> - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... >> >> The objection (if you read the whole thread containing the message I >> cited, I think you'll find it) was that requiring *only* >> block-lambdas for the paren-free call form means expression >> arguments, even ones as simple as numeric literals, must be bracketed >> by {|| and }. Why not allow ( and ) instead? >> >> One counter-argument is that this looks the argument list of a call >> expression whose callee is everything to the left. But paren-free >> call syntax supports newline termination, so I added the ... ( >> Initial Value ) production to satisfy setTimeout-like use cases >> without requiring {|| and | as brackets. >> >> If this alternate production bites back in some way, or is simply >> under-used or too surprising, I'll yank it. >> >> Indeed I could simplify CallWithBlockArguments to take only one >> BlockLambda argument but that seems unnecessarily restrictive. More >> comments welcome. >>> >>>>> 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. >>> >>> With the above I meant: In paren-free mode, following a block with a >>> non-block doesn’t seem like a good idea. With a normal paren call, I >>> don’t see any problems. >> >> The consequences might include >> >> setTimeout {|arg| ...} {|| 1000} {|| x} >> >> That is a bit harsh since 1000 (one second) is a literal and /* >> compute arg here */ is typically simply a pass-by-value reference to >> a variable in the scope of this setTimeout call, e.g. x in this example. >> >> The strawman therefore supports >> >> setTimeout {|arg| ...} (1000) (x) >> >> for example. >> >> Could we go further and support certain primary expressions, namely >> all of the PrimaryExpression right-hand sides except for object literal? >> >> NonObjectLiteralPrimaryExpression : >> this >> Identifier >> Literal >> ArrayLiteral >> ( Expression ) >> >> ? >> >> Not a problem grammatically except for the added complexity, and the >> specific usability issues arising from that slight complexity: >> >> * Leaving out object literal means one must parenthesize an object >> literal but not an array literal. >> * Allowing K but not K+1, requiring instead (K+1), may blow back with >> users. >> >> /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> >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> 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. >>>> >>>> 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 | ... } >>>> >>>> >>>> >>> 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 | ... } >>>> >>>> >>>> >> Axel Rauschmayer <mailto:axel at rauschma.de> >> January 14, 2012 1:32 PM >>>> 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. >> >> I think that’s how Ruby does it. I’m on the fence. It is indeed quite >> magical (and not the good kind of magical). >> >>> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? >> >> BlockArguments : >> BlockLambda >> BlockArguments [no LineTerminator here] BlockLambda >> BlockArguments [no LineTerminator here] ( InitialValue ) >> >> I still don’t fully understand the ( InitialValue ) at the end – it’s >> a single value in parens that can come after several blocks. If >> Ruby-style magic isn’t an option then I would expect (and prefer) >> that there were only two calling “modes”: >> >> - Traditional: myfunc(arg1, arg2, ...} >> - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... >> >>>> 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. >> >> With the above I meant: In paren-free mode, following a block with a >> non-block doesn’t seem like a good idea. With a normal paren call, I >> don’t see any problems. >> >> -- >> 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 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. >>> >>> 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 | ... } >>> >>> >>> >> 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 > Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 4:58 PM > > Three arguments in favor of yanking: > > - Thanks to lambdas, setTimeout already looks very nice – even as a > parenthesized function call. > > - Putting callable values last is more likely, the grammar rule > introduces an odd asymmetry, by not allowing leading a leading ( > InitialValue ) . I’m not saying that that would be a desirable feature > (currying is fine here), just that trailing non-lambdas seem much > rarer than leading non-lambdas. > > - The counter-argument (*) you mention above weighs heavily. Most > people (certainly me) probably expect a function or method call when > they see a parenthesized value. > > The following seems like an elegant and easy to understand rule to me: > “The parameters of a function or method call are either > parenthesized or paren-free. In the latter case, all parameters must > be lambdas.” > > -- > 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 14, 2012 2:41 PM >> Axel Rauschmayer <mailto:axel at rauschma.de> >> January 14, 2012 1:32 PM >>>> 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. >> >> I think that’s how Ruby does it. > Indeed: > > $ ruby > def foo(a,b) > yield a+b > end > foo(1,2) {|x| puts x} > 3D > > >> I’m on the fence. It is indeed quite magical (and not the good kind >> of magical). > > It's way too magical in my view to retrofit to JS. Again, making "if" > and "while" and so on into block-lambda calling functions seems a wild > goose chase. These forms take *statements*, not just block-statements > (and not block-lambdas to call). They're built into the language via > the C-like syntax. > > Imitating "if" etc. is fine. It's a motivation for the paren-free and > *semicolon-free* CallWithBlockArguments statement form. > > And such imitation is doable via the strawman grammar, simply by > returning a function (currying a bit). Singletons or pairs can be used > if there's no need to retain the "if condition": > > function myIf(cond) { > // The block-lambdas here are singletons (no upvars)... > return cond ? {|t, e| t} : {|t, e| e}; > } > > myIf (x > y) {|| "greater"} {|| "not greater"} > > Of course, one might want a dummy "else" ("myElse") in between the > then and else blocks. >> >>> Why should foo(arg1)(arg2) and foo(arg1){||arg2} differ? >> >> BlockArguments : >> BlockLambda >> BlockArguments [no LineTerminator here] BlockLambda >> BlockArguments [no LineTerminator here] ( InitialValue ) >> >> I still don’t fully understand the ( InitialValue ) at the end – it’s >> a single value in parens that can come after several blocks. If >> Ruby-style magic isn’t an option then I would expect (and prefer) >> that there were only two calling “modes”: >> >> - Traditional: myfunc(arg1, arg2, ...} >> - Paren-free – lambdas only: myfunc {|| body1} {|| body2} ... > > The objection (if you read the whole thread containing the message I > cited, I think you'll find it) was that requiring *only* block-lambdas > for the paren-free call form means expression arguments, even ones as > simple as numeric literals, must be bracketed by {|| and }. Why not > allow ( and ) instead? > > One counter-argument is that this looks the argument list of a call > expression whose callee is everything to the left. But paren-free call > syntax supports newline termination, so I added the ... ( Initial > Value ) production to satisfy setTimeout-like use cases without > requiring {|| and | as brackets. > > If this alternate production bites back in some way, or is simply > under-used or too surprising, I'll yank it. > > Indeed I could simplify CallWithBlockArguments to take only one > BlockLambda argument but that seems unnecessarily restrictive. More > comments welcome. >> >>>> 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. >> >> With the above I meant: In paren-free mode, following a block with a >> non-block doesn’t seem like a good idea. With a normal paren call, I >> don’t see any problems. > > The consequences might include > > setTimeout {|arg| ...} {|| 1000} {|| x} > > That is a bit harsh since 1000 (one second) is a literal and /* > compute arg here */ is typically simply a pass-by-value reference to a > variable in the scope of this setTimeout call, e.g. x in this example. > > The strawman therefore supports > > setTimeout {|arg| ...} (1000) (x) > > for example. > > Could we go further and support certain primary expressions, namely > all of the PrimaryExpression right-hand sides except for object literal? > > NonObjectLiteralPrimaryExpression : > this > Identifier > Literal > ArrayLiteral > ( Expression ) > > ? > > Not a problem grammatically except for the added complexity, and the > specific usability issues arising from that slight complexity: > > * Leaving out object literal means one must parenthesize an object > literal but not an array literal. > * Allowing K but not K+1, requiring instead (K+1), may blow back with > users. > > /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> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> 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. >>> >>> 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 | ... } >>> >>> >>> >> 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 | ... } >>> >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120114/bf99f269/attachment-0001.html> -------------- 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/bf99f269/attachment-0002.jpg> -------------- 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/bf99f269/attachment-0003.jpg>
-----Pôvodná správa---
-----Pôvodná správa----- From: Brendan Eich Sent: Sunday, January 15, 2012 7:55 AM To: Axel Rauschmayer Cc: es-discuss Subject: Re: Block lambda grammar: BlockArguments Nothing is going to match Smalltalk on this. Keyword parameters are not even on the map because object literals suck the oxygen out of the room. And then you'll want to get rid of the || for empty block parameters. === Sorry for this question, it is more a meta one. The paragraph above seems too dense for me to digest (and I thought my English is pretty good). Would it be possible to explain a little more? Like what is meant by "going to match" and what is "this" in "on this; and things like "not in the map", "o.l. suck the oxygen out of the room", and the last sentence, too. Thank you, Herby [ did you know you quoted cca 50 screens? 8-O I took the liberty of omitting them. ]
Herby Vojčík <mailto:herby at mailbox.sk> January 15, 2012 1:24 AM
"Nothing is going to match Smalltalk on this. Keyword parameters are not even on the map because object literals suck the oxygen out of the room. And then you'll want to get rid of the || for empty block parameters."
Sorry for this question, it is more a meta one. The paragraph above seems too dense for me to digest (and I thought my English is pretty good). Would it be possible to explain a little more? Like what is meant by "going to match"
"be as good as" Smalltalk.
and what is "this" in "on this;
"on keyword selector syntax".
and things like "not in the map"
No strawman or even idle chatter about adding keyword parameter passing to JS.
, "o.l. suck the oxygen out of the room", and the last sentence, too.
We have discussed here and in TC39 how {key: val} actual parameters in the language already (object literals) remove most of the justification and almost all motivation for adding key: val parameter syntax to call expressions.
Thank you, Herby
Hope this helps.
[ did you know you quoted cca 50 screens? 8-O I took the liberty of omitting them. ]
I'm using a new mail user agent and it does tend to overcite. Sorry, will try to fix.
> Herby Vojčík <mailto:herby at mailbox.sk> > January 15, 2012 1:24 AM > > "Nothing is going to match Smalltalk on this. Keyword parameters are > not even on the map because object literals suck the oxygen out of the > room. And then you'll want to get rid of the || for empty block > parameters." > === > > Sorry for this question, it is more a meta one. The paragraph above > seems too dense for me to digest (and I thought my English is pretty > good). Would it be possible to explain a little more? Like what is > meant by "going to match" "be as good as" Smalltalk. > and what is "this" in "on this; "on keyword selector syntax". > and things like "not in the map" No strawman or even idle chatter about adding keyword parameter passing to JS. > , "o.l. suck the oxygen out of the room", and the last sentence, too. We have discussed here and in TC39 how {key: val} actual parameters in the language already (object literals) remove most of the justification and almost all motivation for adding key: val parameter syntax to call expressions. > > Thank you, Herby Hope this helps. > > [ did you know you quoted cca 50 screens? 8-O I took the liberty of > omitting them. ] I'm using a new mail user agent and it does tend to overcite. Sorry, will try to fix. /be -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120115/213db08e/attachment.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: postbox-contact.jpg Type: image/jpeg Size: 1080 bytes Desc: not available URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120115/213db08e/attachment.jpg>
Thank you, it helped.
It is the fact that in ES up till now, {} block were always delimited by a keyword (if/else is probably the only case when two blocks were present). So it is not a bad idea to retain it.
The problem with this is, one can put arguments in normal parentheses as well as paren-free and keywords are only needed in paren-free scenario... nevertheless. I have an idea. What if this would be allowed:
function myIf(cond, ifBlock myElse elseBlock={||}) { ... }
that is, to allow to separate formal argument names with keywords, not only with commas (again, there can be some restriction like only first few ot last few can be separated this way, so it conforms the overall goals of the grammar).
Then, one could write (well, never mind now if it needs currying or not, it is not a topic now):
myIf(a>b) {|| doThisIfAWins() } myElse {|| doThisIfBWins() };
but also (since elseBlock has default value)
myIf(a>b) {|| doThisIfAWins() };
and of course, it still can write
myIf(a>b, {|| doThisIfAwins() }, {|| doThisIfBWins());
though it is a question if it would not be more consistent to do:
myIf(a>b, {|| doThisIfAwins() } myElse {|| doThisIfBWins());
Thank you, it helped. It is the fact that in ES up till now, {} block were always delimited by a keyword (if/else is probably the only case when two blocks were present). So it is not a bad idea to retain it. The problem with this is, one can put arguments in normal parentheses as well as paren-free and keywords are only needed in paren-free scenario... nevertheless. I have an idea. What if this would be allowed: function myIf(cond, ifBlock myElse elseBlock={||}) { ... } that is, to allow to separate formal argument names with keywords, not only with commas (again, there can be some restriction like only first few ot last few can be separated this way, so it conforms the overall goals of the grammar). Then, one could write (well, never mind now if it needs currying or not, it is not a topic now): myIf(a>b) {|| doThisIfAWins() } myElse {|| doThisIfBWins() }; but also (since elseBlock has default value) myIf(a>b) {|| doThisIfAWins() }; and of course, it still can write myIf(a>b, {|| doThisIfAwins() }, {|| doThisIfBWins()); though it is a question if it would not be more consistent to do: myIf(a>b, {|| doThisIfAwins() } myElse {|| doThisIfBWins()); Herby Brendan Eich wrote: >> >> Herby Vojčík <mailto:herby at mailbox.sk> >> January 15, 2012 1:24 AM >> >> "Nothing is going to match Smalltalk on this. Keyword parameters are >> not even on the map because object literals suck the oxygen out of the >> room. And then you'll want to get rid of the || for empty block >> parameters." >> === >> >> Sorry for this question, it is more a meta one. The paragraph above >> seems too dense for me to digest (and I thought my English is pretty >> good). Would it be possible to explain a little more? Like what is >> meant by "going to match" > > "be as good as" Smalltalk. > >> and what is "this" in "on this; > > "on keyword selector syntax". > >> and things like "not in the map" > > No strawman or even idle chatter about adding keyword parameter passing > to JS. > >> , "o.l. suck the oxygen out of the room", and the last sentence, too. > > We have discussed here and in TC39 how {key: val} actual parameters in > the language already (object literals) remove most of the justification > and almost all motivation for adding key: val parameter syntax to call > expressions. >> >> Thank you, Herby > > Hope this helps. >> >> [ did you know you quoted cca 50 screens? 8-O I took the liberty of >> omitting them. ] > > I'm using a new mail user agent and it does tend to overcite. Sorry, > will try to fix. > > /be
On Mon, Jan 16, 2012 at 2:14 PM, Herby Vojčík <herby at mailbox.sk> wrote:
Thank you, it helped.
It is the fact that in ES up till now, {} block were always delimited by a keyword (if/else is probably the only case when two blocks were present). So it is not a bad idea to retain it.
I believe it's perfectly valid to write blocks (for no particular reason) without any keyword. I.e.: function foo() { var x = 42; { var y = 10; print(x+y); } return x; }
Obviously it's useless, but it is valid. You could add a label to the block if you want to actually use it for something:
bar: { if (x == 10) { y = 10; break bar; } if (x == 20) { y = 0; break bar; } ... }
/L 'Bad examples are bad!'
On Mon, Jan 16, 2012 at 2:14 PM, Herby Vojčík <herby at mailbox.sk> wrote: > Thank you, it helped. > > It is the fact that in ES up till now, {} block were always delimited by a > keyword (if/else is probably the only case when two blocks were present). So > it is not a bad idea to retain it. I believe it's perfectly valid to write blocks (for no particular reason) without any keyword. I.e.: function foo() { var x = 42; { var y = 10; print(x+y); } return x; } Obviously it's useless, but it is valid. You could add a label to the block if you want to actually use it for something: bar: { if (x == 10) { y = 10; break bar; } if (x == 20) { y = 0; break bar; } ... } /L 'Bad examples are bad!'
Lasse Reichstein wrote:
On Mon, Jan 16, 2012 at 2:14 PM, Herby Vojčík<herby at mailbox.sk> wrote:
Thank you, it helped.
It is the fact that in ES up till now, {} block were always delimited by a
{} blocks which are parts of the same control structure. I did not talk about free blocks, but about bound blocks. Sorry if it was not clear.
keyword (if/else is probably the only case when two blocks were present). So it is not a bad idea to retain it.
I believe it's perfectly valid to write blocks (for no particular reason) without any keyword. I.e.: function foo() { var x = 42; { var y = 10; print(x+y); } return x; }
Obviously it's useless, but it is valid. ...
Lasse Reichstein wrote: > On Mon, Jan 16, 2012 at 2:14 PM, Herby Vojčík<herby at mailbox.sk> wrote: >> Thank you, it helped. >> >> It is the fact that in ES up till now, {} block were always delimited by a {} blocks which are parts of the same control structure. I did not talk about free blocks, but about bound blocks. Sorry if it was not clear. >> keyword (if/else is probably the only case when two blocks were present). So >> it is not a bad idea to retain it. > > I believe it's perfectly valid to write blocks (for no particular > reason) without any keyword. > I.e.: > function foo() { > var x = 42; > { > var y = 10; > print(x+y); > } > return x; > } > > Obviously it's useless, but it is valid. > ... > /L 'Bad examples are bad!' Herby
Lasse Reichstein <mailto:reichsteinatwork at gmail.com> January 16, 2012 5:54 AM
I believe it's perfectly valid to write blocks (for no particular reason) without any keyword. I.e.: function foo() { var x = 42; { var y = 10; print(x+y); } return x; }
Obviously it's useless, but it is valid.
It becomes useful with the introduction of 'let', 'const', and ES.next 'function' in block declarations.
You could add a label to the block if you want to actually use it for something:
bar: { if (x == 10) { y = 10; break bar; } if (x == 20) { y = 0; break bar; } ... }
/L 'Bad examples are bad!'
;-)
> Lasse Reichstein <mailto:reichsteinatwork at gmail.com> > January 16, 2012 5:54 AM > > I believe it's perfectly valid to write blocks (for no particular > reason) without any keyword. > I.e.: > function foo() { > var x = 42; > { > var y = 10; > print(x+y); > } > return x; > } > > Obviously it's useless, but it is valid. It becomes useful with the introduction of 'let', 'const', and ES.next 'function' in block declarations. > You could add a label to the block if you want to actually use it for > something: > > bar: { > if (x == 10) { y = 10; break bar; } > if (x == 20) { y = 0; break bar; } > ... > } > > /L 'Bad examples are bad!' ;-) /be > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > Brendan Eich <mailto:brendan at mozilla.org> > January 15, 2012 11:41 PM >> Herby Vojčík <mailto:herby at mailbox.sk> >> January 15, 2012 1:24 AM >> >> "Nothing is going to match Smalltalk on this. Keyword parameters are >> not even on the map because object literals suck the oxygen out of >> the room. And then you'll want to get rid of the || for empty block >> parameters." >> === >> >> Sorry for this question, it is more a meta one. The paragraph above >> seems too dense for me to digest (and I thought my English is pretty >> good). Would it be possible to explain a little more? Like what is >> meant by "going to match" > > "be as good as" Smalltalk. > >> and what is "this" in "on this; > > "on keyword selector syntax". > >> and things like "not in the map" > > No strawman or even idle chatter about adding keyword parameter > passing to JS. > >> , "o.l. suck the oxygen out of the room", and the last sentence, too. > > We have discussed here and in TC39 how {key: val} actual parameters in > the language already (object literals) remove most of the > justification and almost all motivation for adding key: val parameter > syntax to call expressions. >> >> Thank you, Herby > > Hope this helps. >> >> [ did you know you quoted cca 50 screens? 8-O I took the liberty of >> omitting them. ] > > I'm using a new mail user agent and it does tend to overcite. Sorry, > will try to fix. > > /be > Herby Vojčík <mailto:herby at mailbox.sk> > January 15, 2012 1:24 AM > > > -----Pôvodná správa----- From: Brendan Eich > Sent: Sunday, January 15, 2012 7:55 AM > To: Axel Rauschmayer > Cc: es-discuss > Subject: Re: Block lambda grammar: BlockArguments > > Nothing is going to match Smalltalk on this. Keyword parameters are > not even on the map because object literals suck the oxygen out of the > room. And then you'll want to get rid of the || for empty block > parameters. > === > > Sorry for this question, it is more a meta one. The paragraph above > seems too dense for me to digest (and I thought my English is pretty > good). Would it be possible to explain a little more? Like what is > meant by "going to match" and what is "this" in "on this; and things > like "not in the map", "o.l. suck the oxygen out of the room", and the > last sentence, too. > > Thank you, Herby > > [ did you know you quoted cca 50 screens? 8-O I took the liberty of > omitting them. ] > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > Brendan Eich <mailto:brendan at mozilla.org> > January 14, 2012 10:55 PM > Nothing is going to match Smalltalk on this. Keyword parameters are > not even on the map because object literals suck the oxygen out of the > room. And then you'll want to get rid of the || for empty block > parameters. > > I say pause with a simpler design and digest, ruminate, prototype, > user-test. > > /be > > Axel Rauschmayer <mailto:axel at rauschma.de> > January 14, 2012 9:35 PM > Cool. I also have a feeling that every paren-free lambda after the > first one should have some kind of preceding keyword or name, but I > don’t know how one could make that happen. Brace-free object literals? > (only half joking) > > On Jan 15, 2012, at 3:42 , Brendan Eich wrote: > > -- > 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120116/470fdd58/attachment-0001.html> -------------- next part -------------- A non-text attachment was scrubbed... Name: compose-unknown-contact.jpg Type: image/jpeg Size: 770 bytes Desc: not available URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120116/470fdd58/attachment-0004.jpg> -------------- 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/20120116/470fdd58/attachment-0005.jpg> -------------- next part -------------- A non-text attachment was scrubbed... Name: postbox-contact.jpg Type: image/jpeg Size: 1080 bytes Desc: not available URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120116/470fdd58/attachment-0006.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/20120116/470fdd58/attachment-0007.jpg>
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 | ... }