RFC: `&.` within a block

Personally I don’t see much of a point in having numbered arguments in general. It’s not only that they look dirty. They raise the question of 0-based vs. 1-based indexing, increasing mental overhead. If anything I feel like 0-based indexing is more intuitive, but I guess not everyone sees it that way. Additionally, you need to remember the types of each argument which you can no longer infer from descriptive names. The Ruby RFC for it makes some more excellent points under Why I don’t use _1.

As soon as you declare more than 1 argument, suddenly types and order start to become important. At this point I think you should be forced to name them, even if it’s only to help you catch errors early.

There is huge value in a special symbol for the first argument, because calling blocks with one argument is such a common use-case, and I think it is sort of acceptable.

To keep it simple, would anything speak directly against _? This even adds some whitespace and is commonly used for placeholders.

record Player, name : String, score : UInt8
PLAYERS = [Player.new("Joe", 50), Player.new("Zoe", 60)]

Printing all names:

PLAYERS.each { |player| puts player.name }

PLAYERS.each { puts _1.name }
PLAYERS.each { puts \1.name }
PLAYERS.each { puts it.name }   # weird grammar
PLAYERS.each { puts its.name }  # should this be allowed as well?
PLAYERS.each { puts _.name }

Commands remain equal (assuming the method exists):

PLAYERS.each(&.surrender)

Simple aggregation remains equal:

highscore = PLAYERS.map(&.score).max

But map & reduce is the one use case that I encounter all the time that’s just so much better with this feature:

percentages = PLAYERS.map(&.score).map { |player| player.fdiv highscore }
# or
percentages = PLAYERS.map { |player| player.score.fdiv highscore }

percentages = PLAYERS.map { _1.score.fdiv highscore }
percentages = PLAYERS.map { \1.score.fdiv highscore }
percentages = PLAYERS.map { it.score.fdiv highscore } # again weird grammar
percentages = PLAYERS.map { _.score.fdiv highscore }

There’s no benefit from anonymous argument identifiers when the argument is the receiver of a chained call. That’s already covered by short block syntax.
For the map examples, you could just use PLAYERS.map &.score.fdiv highscore.

1 Like