Extracted from #7429, which has been closed due to the fact that some of the members of the community can’t stand the fact someone that is having a different point of view (see the irony).
So,
foo do |x|
x.foo
x.bar
end
and
foo do
&.foo
&.bar
end
Let’s continue arguing and insulting each other the discussion then.
I had extra subjective pros:
- A developer would not need to think of the argument naming anymore
- Ampersand is highlighted, which allows the brain to quickly extract the call name (compare
x.fooand&.fooin the example above, listen to how your brain reads it) - A developer would still be free to choose between explicit block argument and
&.whenever they want to - It would conform with the existing
foo &.barsyntax, as it expands tofoo { |x| x.bar }, which is essentially the same - It would not affect the
with yieldsyntax
Let’s skip the fact that I could have chosen Go or C instead of Crystal if it was not about subjective perception. And that Crystal would be just a one of meh languages if it was not expressive.
Oh wait, some community members are directly against expressiveness. They imply on the need for the code to be as much explicit as possible. But we have foo &.bar. And we have record. And tons of other macros. And also getter, setter and property. Why not defining def get_foo and def set_foo explicitly? getter is too implicit! Vote for removing the getter macro from the language!
My point is that expressiveness is the amount of code a developer needs to write to achieve the same result preserving the readability. foo &.bar equals to foo { |x| x.bar }, record equals to struct Foo .... We omit repeatable code using some rules.
foo do |x|
x.foo
x.bar
end
Is a perfect use-case for omitting the code with a simple rule – & = first block argument. It’s easy to remember, it’s easy to parse on the brain-side. Maybe even simpler than record macro.

