I've followed Why's (Poignant) Guide to Ruby, through couple of other guides, to Ruby style guide to see how Rubyists think. But this is the first time I see trailing underscores. What are these things? Are they useful and if so, when do we use them and how do we use them with splat operators?
(Ruby style guide link is anchored to the actual example)
A legal variable name is _
. And something like *_
is similar to *x
. The term a trailing underscore variable actually refers to the last variable name in a comma separated series of variables on the left side of an assignment statement, e.g.:
a, b, _ = [1, 2, 3, 4]
The splat operator has two uses:
Which of those happens depends on the context that the splat operator is used in.
Here are the examples that the Ruby style guide says are bad:
a, b, _ = *foo
The trailing underscore variable in that example is unnecessary because you can assign the first two elements of foo
to the variables a
and b
by writing:
a, b = *foo
The underscore variable is used to say, I don't care about this variable, and therefore it isn't necessary in that example if all you want to do is assign to a
and b
.
The example also might be considered bad style because the *
operator isn't needed either(credit: Cary Swoveland):
a, b = [1, 2, 3]
p a, b
--output:--
1
2
The *
can be used on the right hand side to good effect like this:
x, y, z = 10, [20, 30]
p x, y, z
--output:--
10
[20, 30]
nil
x, y, z = 10, *[20, 30]
p x, y, z
--output:--
10
20
30
So, just keep in mind that in the rest of the examples from the style guide the *
is superfluous on the right hand side.
The next bad example is:
a, _, _ = *foo
Here is a more concrete example:
a, _, _ = *[1, 2, 3, 4]
p a, _
puts "-" * 10
a, _ = *[1, 2, 3, 4]
p a, _
--output:--
1
3
----------
1
2
The following shows the way the assignment works in the first section of the example:
a, _, _
^ ^ ^
| | |
[1, 2, 3, 4]
In any case, if you get rid of the second underscore variable on the left, then a
will be assigned the same thing. What about getting rid of both underscore variables?
a = *[1, 2, 3, 4]
p a
--output:--
[1, 2, 3, 4]
Nope. So the first underscore variable on the left appears to be necessary. However, there is another syntax to get the same result without using a trailing underscore variable:
a, = *[1, 2, 3, 4]
p a
--output:--
1
Therefore, the third bad example:
a, *_ = *foo
can also be written as:
a, = *foo
and thereby avoid a trailing underscore variable.
Finally, the style guide offers this cryptic advice:
Trailing underscore variables are necessary when there is a splat variable defined on the left side of the assignment, and the splat variable is not an underscore.
I think that may be referring to something like this:
*a = *[1, 2, 3, 4]
p a
--output:--
[1, 2, 3, 4]
If you want a
to be assigned the first three elements of the array, then you have to write:
*a, _ = *[1, 2, 3, 4]
p a
--output:--
[1, 2, 3]
For whatever reason, the parser cannot handle:
*a, = *[1, 2, 3, 4]
--output:--
*a, = *[1, 2, 3, 4]
^
1.rb:6: syntax error, unexpected '\n', expecting :: or '[' or '.'
Here is one of the good examples:
*a, b, _ = *foo
The trailing underscore variable is necessary there, IF you want to assign the second to the last element of foo to b
.
The following good examples are a little perplexing:
a, _b = *[1, 2, 3, 4]
a, _b, = *[1, 2, 3, 4]
Let's try them out:
a, _b = *[1, 2, 3, 4]
p a, _b
puts "-" * 10
a, _b, = *[1, 2, 3, 4]
p a, _b
--output:--
1
2
----------
1
2
In ruby, a variable name such as _b
is no different than a variable named _
or b
. In functional languages, like Erlang, the variables _
and _B
and B
have different effects--but not in Ruby.
By the way, I wouldn't spend five minutes learning that style--it's too esoteric.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With