Feature #11141
closednew syntax suggestion for abbreviate definition on block parameters in order
Description
One of the most commons things I do in Ruby are small block definitions:
x.each{|a| a}
One useful syntax introduced was the &:method
that allows calling a method on a block if only one param is expected. It's a shortcut for a.each{|x|x.method}
. I think it would be nice if Ruby had a syntax that allows me to not define the params that block would receive, but instead access them in order. For example:
x.each { $1 }
Let's suppose the block is waiting for two params, I normally do:
x.method {|a,b| a - b }
This syntax will allow us to use:
x.method{ $1 - $2 }
So:
x.each { p1.stg }
x.each {|p1| p1.stg}
x.each &:stg
would be the same.
Please consider $1
and $2
just as an example. I don't like the fact that they are global variables. It could be _1
or p1
, for example:
x.method{ p1 - p2 }
x.each{ p1 - p2 } == x.each {|p1, p2| p1 - p2 }
Or, as blocks already uses &:method
it could be &:1
. Or any other thing that you may consider more appropriated.
I think this syntax would be very nice for short block definitions, the downside is that it allows for bad practice on longer methods, but in the end, that's a decision that a programer should make.
Maybe this is not a valid reason, but I would like to point out that Regex is actually creating global vars as the results of match: $x vars. (for perl's historical reasons)
So why not introduce this into Ruby's syntax?
Personally I don't like either $1
nor p1
. They are just the first quick things that come to my mind.
Updated by matz (Yukihiro Matsumoto) over 9 years ago
- Status changed from Open to Rejected
We cannot use $1
etc. as they are already taken for Regexp
match.
Short hand notation for block parameter itself is a nice idea though.
Matz.
Updated by neohunter (Arnold Roa) over 9 years ago
Yukihiro Matsumoto wrote:
We cannot use
$1
etc. as they are already taken forRegexp
match.
Short hand notation for block parameter itself is a nice idea though.Matz.
Yes, I just use $1
as an example to explain the idea, by no means I think $1
would be a good choice as $
is for global variables and $1
..2
..3
are reserved for Regexp
. The idea I wanted to point here is the short-hand syntax.
@1
is a good idea, but @
is used for instance variables. So I'm not sure if is the ideal.
On method definition we can use *args
for multiple arguments, so what about *1
, *2
, *3
?
x.method{ *1 - *2 }
Updated by nobu (Nobuyoshi Nakada) over 9 years ago
Arnold Roa wrote:
On method definition we can use
*args
for multiple arguments, so what about*1
,*2
,*3
?x.method{ *1 - *2 }
It has obvious ambiguity.
How will you interpret foo(*1)
, a splat or the short-hand syntax?
Updated by austin (Austin Ziegler) over 9 years ago
It gets a bit more line-noisy, but why not a couple of sigils? Maybe:
x.method { @[1] - @[2] }
Austin Ziegler * halostatue@gmail.com * austin@halostatue.ca
http://www.halostatue.ca/ * http://twitter.com/halostatue
Updated by rbjl (Jan Lelis) over 9 years ago
Nobuyoshi Nakada wrote:
What about
@1
?
I liked this one at first glance, but it might confuse people, because you could think the scoping would be similar to @instance
variables.
Some brainstorming:
->{ puts $a, $b } # <- reasoning: $ does not mean global scope anyway
->{ puts 1st, 2nd } # <- interesting syntax trick
Updated by Hanmac (Hans Mackowiak) over 9 years ago
my problem i got with that new syntax is what does it do when i have blocks inside of blocks, specially with different arity count ...
like
{key1 => value1, key2 => value2}.each { |key, value|
[obj1, obj2, obj3].each { |obj|
}
}
when using that syntax:
{key1 => value1, key2 => value2}.each {
[obj1, obj2, obj3].each {
puts p1, p2 # what are the values of p1 and what specially are the values of p2 ?
}
}
Updated by rbjl (Jan Lelis) over 9 years ago
Hans Mackowiak wrote:
my problem i got with that new syntax is what does it do when i have blocks inside of blocks, specially with different arity count ...
I'd say, such a implicit block parameters should only be possible for the most inner block. Somehow accessing the arguments of an outer block probably does not make the code better readable. However, having simple (unnested) blocks with implicit variables can improve the readability, because it is more concise. Like, for example, it is already possible with gsub:
"Ruby".gsub(/(.)(.)/){ $1.downcase + $2.upcase } #=> "rUbY"
Updated by ko1 (Koichi Sasada) over 9 years ago
FYI:
Kazuki Tanaka-san proposed a library Kasen.
[ruby-list:50120] [ANN] Kasen(下線) v0.1.1
Github: https://github.com/gogotanaka/_
Rubygems: https://rubygems.org/gems/kasen
It introduces special method "_" (underscore, Kasen in Japanese) and enable us to write such code.
[1, 2, 3].map &(_ + 1).to_s
# means
[1, 2, 3].map { |n| (n + 1).to_s }
Matz said he favorites this idea.