Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use of underscores with splats in Ruby

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)

like image 247
James Pond Avatar asked Jan 07 '23 10:01

James Pond


1 Answers

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:

  1. Explode an array into its individual items.
  2. Gather items into an array.

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.

like image 135
7stud Avatar answered Jan 19 '23 00:01

7stud