This was the tip of the week in the September 9, 2021 Ruby Weekly Newsletter.

We have likely all interacted with Ruby blocks which take parameters. Maybe we’ve seen something like this:

squared_numbers = (1...10).map { |num| num ** 2 }

From Ruby 2.7 onwards, we have an alternate syntax we can use to express this same statement. Instead of naming parameters (|num| above), Ruby allows us to use numbers prefixed with underscores to refer to the parameters. In the case above, since the block has one parameter, we can use _1 to refer to what was previously num:

squared_numbers = (1...10).map { _1 ** 2 }

If there are multiple parameters, we use numbers sequentially to refer to different parameters as they would have been ordered if they were named. For instance, iterating over a hash, we have both a key (city below) and value (population below) parameter. So this:

city_populations = { "Tokyo" => 37_435_191,
"Delhi" => 29_399_141, "Shanghai" => 26_317_104 }

city_populations.each { |city, population|
puts "Population of #{city} is #{population}" }

.. becomes this using numbered parameters:

city_populations.each { puts "Population of #{_1} is #{_2}" }

Use numbered parameters or named parameters

Numbered parameters only work if we don’t name the parameters. As soon as we give them a name, we can’t then also try access them by number:

squared_numbers = (1...10).map { |num| _1 ** 2 }

# SyntaxError (ordinary parameter is defined)

Style note

Before finishing this tip, it’s important to note that while in some cases numbered parameters are simpler, there are also some times numbered parameters can make code harder to read and understand than named parameters. I use numbered parameters for simple blocks, and named parameters as soon as any complicated logic appears in a block.

Be sure to agree with your team on when it’s stylistically appropriate to use numbered parameters or named parameters!