Yukihiro Matsumoto wrote about new lambda syntaxes:
>f = ->(a) { ... }
[...]
>f = { : a,b=1|2 : ... }
>f = { : * : ... } # equivalent to f = lambda { ... }
Unfortunately :+space causes conflicts as well.
I'm probably not in the position to criticize, but I still feel like I have to or I will regret not having done it later.
Is it really in accordance to Ruby's design mentality to introduce new syntax just because parsing the most obvious one is too complex?
This is how I understand the issue. A new syntax is being considered because this will be hard to get working:
l = lambda { |x, y, z = (x | y)| ... }
And because block arguments don't look much (and aren't handled much like) method arguments.
If this is not only for the above two reasons, but also because you think that the above sample is hard to parse visually then please consider other choices that are more obvious than arrows pointing into random directions:
f = def(x, y, z = x | y) { ... } # also need to allow def x() { ... }
f = fun(x, y, z = x | y) { ... } # a new keyword
Personally, I think this complete situation is not as much as a problem as it might appear. -- Blocks are a special syntax in Ruby and we have all gotten used to it. It is okay for them to also have a special argument syntax. Having default arguments with the current one is not hard. We don't need both method call semantics and special block semantics both at the same time. We could get rid of Proc.new without losing anything but the danger of confusion.
Sure, the C#, Perl and ECMAScript way of doing this has advantages like being able to assign closures to variables with the same syntax as with method calls. It also allows multiple closures per method and storing them in hashes without a second syntax. Should we switch to it? Should this have been the way for Ruby to do it since the beginning?
As stated above I think switching might be more trouble than its worth. Sure, if you learn Ruby you will at one point try to do "x = { exit }", but after a small surprise you will have learnt to insert the "lambda".
Now to the more difficult part. Would it have been better if Ruby would have merged blocks and lambdas since the beginning? This is hard to answer. When I was learning Ruby I thought that it would be great to be able to supply multiple blocks to one method without needing a different syntax. Has this been a limitation? Nope, but that could be related to users of languages automatically working around issues before they encounter them.
So would there have been a downside to Ruby having unified blocks and lambdas since the beginning? Yes, I think that
10.upto(20, { |i| puts i })
is harder to type and read than
10.upto(20) { |i| puts i }
One can now argue that it does not matter for cases where there only is a block:
1.times { } is the same as 1.times({ }) anyway.
Or that we could allow trailing arguments that happen to be blocks to appear outside of the argument list:
Array.new(5) { |i| i * 2 } == Array.new(5, { |i| i * 2 })
# It is hard to come up with methods that take multiple blocks which
# isn't very surprising.
ary.context_each(
first: { |i| puts "First: #{i}" },
last: { |i| puts "Last: #{i}" },
) { |i| puts i }
# Or:
ary.context_each(
first: { |i| puts "First: #{i}" },
last: { |i| puts "Last: #{i}" },
middle: { |i| puts i }
)
I also think that you might be able to fix the arrow syntax by moving it. I think something like this is acceptable:
adder = (a, b) -> { a + b }
And perhaps:
printer = a -> { puts a }
And even more perhaps:
printer = a -> puts a
This is again very hard to parse. Perhaps even for humans. So:
adder = \(a, b) -> { a + b }
printer = \a -> { puts a }
Don't get me wrong here. It might be rare, but in this case I am not actually trying to talk you into changing the language. I think the best and least risky option is to just keep the current situation. I am usually for sacrificing backwards compatibility to gain more intuitiveness and simplicity, but in this case the problem is not big enough to solve it (yet?).