Hi everyone,
Here's a revised lambda syntax tweak proposal. It's gotten feedback from
several, so I think it's time to present it more generally.
I don't think we should do this now; we should remain focused on bugs
for 0.3. I'm just interested in getting feedback.
Executive summary of the proposal:
1. Change the block lambda syntax from { |x| x + 3 } to |x| x + 3.
2. In general, remove the special case of "pulling the last argument out
and turning it into a block" from the language. However, it is still
supported, and in fact required, as part of the "for" construct and the
new "do" construct.
3. Change this:
for [ 1, 2, 3 ].map { |x|
...
}
To this:
for [ 1, 2, 3 ].map |x| {
...
}
4. Add a new form, `do`, in order to support block syntax for constructs
that aren't strictly loops. Also remove the mandatory || for
zero-argument lambda blocks. Thus instead of:
spawn { ||
...
}
We have:
do spawn {
...
}
Rationale:
* Removing the ability for the last argument of a function call to be
pulled out in the general case significantly decreases the complexity of
the language grammar. This feature simply becomes a mandatory part of
the "for" or "do" expressions.
* Removing the pipes around zero-argument functions in "do" or "for"
constructs improves readability. In particular "do spawn" reads naturally.
* Having the opening brace be at the end of the line increases
familiarity for programmers accustomed to the C language family.
* Removing the mandatory braces around lambdas decreases visual noise
for small lambda expressions. Consider the closing parentheses on this line:
log([ 1, 2, 3 ].map(|x| x + 1))
Versus the sequence '}))' on this line:
log([ 1, 2, 3 ].map({ |x| x + 1 }))
* Having only one way to get the block syntax iteration ("for" or "do")
provides an incentive for library authors to ensure that their blocks
follow the iteration protocol. At the same time, it minimizes surprises
when people try to put "break"/"continue"/"ret" in blocks intended for
iteration and discover it doesn't work. Now it always works for iterators.
* The "do" block allows "continue" for early returns, which is something
that cannot be done at the moment with block lambdas.
Here are the technical details:
Pseudo-BNF:
PrimaryExpr ::== ... | BlockLambda | ForExpr | DoExpr
BlockLambda ::== AbbreviatedArgs Expr
AbbreviatedArgs ::== '||' | '|' (ModeSigil Identifier)* '|'
ForExpr ::== 'for' (CallExpr | PrimaryExpr) AbbreviatedArgs? Block
DoExpr ::== 'do' (CallExpr | PrimaryExpr) AbbreviatedArgs? Block
If the "for" expression or "do" expression head is a primary expression
that is not a call expression, then it's treated as a call expression
with an empty argument list.
The block lambda in a "for" expression is treated as returning bool,
while the block lambda in a "do" expression is treated as returning
unit. As such, "break"/"continue"/"ret" all work in "for" loops, while
only "continue" works in "do" expressions (which effects an early return).
Thoughts?
Patrick
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev