Hello,
I would like to propose a shortcut for block arguments (the magic block
argument ;-)
I would like
[1, 2, 3].map { |x| x + 1 }
and
[1, 2, 3].map { @ + 1 }
to be equivalent.
This might have been proposed before, but I couldn't find a RCR or
something else through google (it is hard to search for).
I am not sure about the @ sign, other possibilities might be $ or $ plus
something or something completely different, it should just be short.
More details:
- @ would only be allowed in blocks without an explicit argument list
(blocks without goal posts)
- blocks that use it would have arity 1:
lambda { |x| x }.arity # => 1
lambda { @ }.arity # => 1
but:
lambda { }.arity # => -1 (or 0, see RCR 227)
- it should be "stackable":
[[1, 2, 3], [4, 5, 6]].map { @.reverse.map { -@ } }
would mean
[[1, 2, 3], [4, 5, 6]].map { |x| x.reverse.map { |y| -y } }
- I think it doesn't break any existing code
Open questions:
- should it be accessible in "enclosed" blocks? For example:
[1, 2, 3].map { |x| (0..5).collect { |y| x * y } }
versus
[1, 2, 3].map { (0..5).collect { |y| @ * y } }
I am really not sure if this should be allowed, there might be problems
with parsing and ambiguities.
- should it be assignable? For example:
[1, 2, 3].map { |x| x += 1; x }
versus
[1, 2, 3].map { @ += 1; @ }
I think that would be ok.
Some more examples:
Using it in blocks passed to new:
Font.new {
@.name = "Arial"
@.size = 12
@.color = :black
}
In lots of Array/Enumerable methods:
words.all? { @.length == 3 }
words.any? { @.length == 3 }
words.find_all { @.length == 3 }
words.partition { @.length == 3 }
words.each { puts @.upcase }
And many more...
I am aware that some people don't like such magic, because it might lead
to cryptic/unreadable code, but I think it is nice for all those short
blocks (like in the examples).
And nobody would be forced to use it, it would be completely optional,
just an alternative.
By the way, I got the idea while reading about Monad/MSH
(http://arstechnica.com/guides/other/msh.ars), they use $_ for this, but
that is taken in ruby (for similar magic). The author of this guide even
translates one MSH command to ruby for comparison:
msh> get-childitem | sort-object extension | select extension | where
{ $_.extension.length -eq 4 }
is
Dir["*"].map {|x| File.extname(x) }.sort.find_all {|x| x.length == 4 }
in ruby, with this proposal it could be written as
Dir["*"].map { File.extname(@) }.sort.find_all { @.length == 4 }
What do you think?
Dominik