This blog is part of our Ruby 2.7 series.
At some point, all of us have used names like a, n, i etc for block parameters. Below are few examples where numbered parameters can come in handy.
1 2> (1..10).each { |n| p n * 3 } 3 4> { a: [1, 2, 3], b: [2, 4, 6], c: [3, 6, 9] }.each { |_k, v| p v } 5 6> [10, 100, 1000].each_with_index { |n, i| p n, i } 7
Ruby 2.7 introduces a new way to access block parameters. Ruby 2.7 onwards, if block parameters are obvious and we wish to not use absurd names like n or i etc, we can use numbered parameters which are available inside a block by default.
We can use **1_ for first parameter, **2_ for second parameter and so on.
Here's how Ruby 2.7 provides numbered parameters inside a block. Below shown are the examples from above, only this time using numbered parameters.
1 2> (1..10).each { p _1 * 3 } 3 4> { a: [1, 2, 3], b: [2, 4, 6], c: [3, 6, 9] }.each { p _2 } 5 6> [10, 100, 1000].each_with_index { p _1, _2 } 7
Like mentioned in News-2.7.0 docs, Ruby now raises a warning if we try to define local variable in the format _1. Local variable will have precedence over numbered parameter inside the block.
1 2> _1 = 0 3> => warning: `_1' is reserved for numbered parameter; consider another name 4 5> [10].each { p _1 } 6> => 0 7
Numbered parameters are not accessible inside the block if we define ordinary parameters. If we try to access _1 when ordinary parameters are defined, then ruby raises SyntaxError like shown below.
1 2> ["a", "b", "c"].each_with_index { |alphabet, index| p _1, _2} 3 4=> SyntaxError ((irb):1: ordinary parameter is defined) 5
This feature was suggested 9 years back and came back in discussion last year. After many suggestions community agreed to use _1 syntax.
Head to following links to read the discussion behind numbered parameters, Feature #4475 and Discussion #15723.
Here's relevant commit for this feature.