Ruby Variable Name with Double Underscores

Ruby variable name with double underscores

An initial underscore or double underscore basically indicates
"special/avoid overwrite" --meaning it's meant to reduce the
likelihood that someone else might define a method/attribute of the
same name. The most common occurrence is __send__.

From Ruby Forum

What is @__instance__ in Ruby?

The underscore is a legal character in an identifier. It has no meaning whatsoever.

(There is one exception: local variables that start with an underscore will not generate a warning if they are unused.)

In other words: the meaning of @__instance__ is exactly the same as the meaning of @foobar: there is no meaning.

Ruby naming convention / double underscore / useful stuff

This is a complete list for Ruby 2.1:

  • __callee__ (Kernel)
  • __dir__ (Kernel)
  • __method__ (Kernel)
  • __id__ (BasicObject)
  • __send__ (BasicObject)
  • __ENCODING__ (keyword)
  • __LINE__ (keyword)
  • __FILE__ (keyword)

From delegate:

  • __getobj__ (Delegator)
  • __setobj__ (Delegator)
  • __getobj__ (SimpleDelegator)
  • __setobj__ (SimpleDelegator)

From drb:

  • __drbref
  • __drburi

From irb:

  • __evaluate__
  • __exit__

From tk:

  • All the methods start with a double underscore

Is it good practice having local variables starting with underscore?

Nothing wrong with your idea. But if I was having trouble distinguishing local vars from method calls, I would probably just force myself to always use ()'s on methods. (My team at work has discussed making this part of our coding standards).

a = thing # var
b = thing() # method

The possible advantage to this is readability to others. Someone may wonder at your leading _'s, but using ()'s on all method calls should be clear to everyone.

Use of underscores with splats in Ruby

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.

What does an underscore between two variable mean?

Ruby's double-quoted string literals and symbol literals allow interpolation via #{...}. It works like a placeholder. The result of an expression given within the parentheses is converted to a string and inserted at the given position:

"1 + 2 = #{1 + 2}"
#=> "1 + 2 = 3"

Back to your question:

What does an underscore between two variables mean?

Within a string, an underscore is a literal underscore, i.e. _.

Your code creates a hash with dynamically created symbol key and string value:

type = 'foo'
data = { 'blah' => 'bar', 'blahblah' => 'baz' }

{ "#{type}_#{data['blah']}": "#{data['blahblah']}" }
#=> {:foo_bar=>"baz"}

There was a minor typo in your code: the : must not have a trailing space.

Furthermore, interpolation is not needed if the string contains nothing else. If data['blahblah'] is a string, you can just write:

{ "#{type}_#{data['blah']}": data['blahblah'] }

And otherwise:

{ "#{type}_#{data['blah']}": data['blahblah'].to_s }


Related Topics



Leave a reply



Submit