Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it good practice having local variables starting with underscore?

I'm just getting into Ruby and come from the Java and C/C++ environment.

While coding a first little project in Ruby, I somehow got used to let all local variables start with an underscore. I guess my main motivation for this was a better readability and distinction from method calls.

As in principle there are only three types of variables ($global, @instance and local), the vast majority of variables start with an underscore. I'm not really sure, whether this is good or bad. Besides, in a lot other languages, the underscore would be substituted to some other character.

Is there somehow a best practice concerning variable naming beside the usual CamelCase and/or underscore separated? What are the habits of the professional "rubyists"? Have I overlooked some general Ruby conventions, when I chose the leading underscore?


edit
Thanks to all answers and suggestions. It helped me a lot.


Short Summary of Answers and Comments below
(for the short-on-time visitor)

Leading underscores go with:

  • method arguments: def my_method(_my_arg)
  • block arguments: e.g. my_array.each { |_x| puts _x}

All other local variables without leading underscores, as programmers coming from e.g. JavaScript might get confused about intended behaviour of the variables.

For visual separation between variable names and method calls, forcing oneself to use "(" brackets ")" with all method calls might increase readability significantly.

like image 537
Torbjörn Avatar asked Jan 23 '12 18:01

Torbjörn


People also ask

Can variables start with _?

_ usually means something private or internal. In C++ standard libraries all implementation specific variables must start with _ .

Should I use underscores in variable names?

Variable names should not start with underscore ( _ ) or dollar sign ( $ ) characters, even though both are allowed. This is in contrast to other coding conventions that state that underscores should be used to prefix all instance variables. Variable names should be short yet meaningful.

Why should we avoid the use of the underscore to begin variable names with?

If you have many places where you are using _ as a convention then all of that will break. Using underscore in a variable like a_b is still valid. But using _ alone as variable name is no more valid.

Why are local variable names beginning with an underscore discouraged?

Explanation: Variable names should not start with a number. 5. Why are local variable names beginning with an underscore discouraged? Explanation: As Python has no concept of private variables, leading underscores are used to indicate variables that must not be accessed from outside the class.


3 Answers

Existing answers to this question are now a few years old, and conventions have changed. You should only ever use a leading underscore (_some_param), or a standalone underscore (_), to indicate that you don't care about the value. The rubocop style linting tool will carp about a "useless assignment" if you assign a variable but don't use it, but it will ignore variables with a leading underscore. This allows you to expressly indicate that you don't care about the value and don't intend to use it.

Here's a somewhat-contrived example use-case in an RSpec context:

describe 'login' do
  let(:user) { FactoryGirl.create(:user, login: 'bob') }
  it 'must be unique' do
    _user1 = user
    user2 = User.new login: 'bob'
    expect(user2.valid?).to be_false
  end
end

Here we're indicating that our user helper has a side-effect and returns something, but we don't care about it. You could also just skip the assignment entirely, but seeing a bare user on a line by itself looks odd and doesn't reveal the intention as clearly:

describe 'login' do
  let(:user) { FactoryGirl.create(:user, login: 'bob') }
  it 'must be unique' do
    user
    user2 = User.new login: 'bob'
    expect(user2.valid?).to be_false
  end
end

Other scenarios include ignoring values in iterators, or overriding a method where you want to keep the original method signature but don't care about some of the values:

def greet(name, _title)
  puts "Hi, #{name}!"
end
like image 50
Jim Stewart Avatar answered Oct 24 '22 19:10

Jim Stewart


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.

like image 20
bioneuralnet Avatar answered Oct 24 '22 21:10

bioneuralnet


In my experience, underscore-prefixed variables in Ruby are much like underscore-prefixed variables in JavaScript: a "don't touch" flag. More specifically, they are used when the implementer is doing something that really is not supposed to be understood as a part of the object, or shouldn't be thought of as the conceptual interface of the object.

This is more clear in the JavaScript world, where somebody is emulating "private" by prefixing a variable with an underscore. They are encoding that there's part of the object that's under the hood and can be ignored when looking at the object from the outside.

In Ruby, I've only really seen this with things like a cache or a singleton instance - the kind of thing that should be invisible to consumers of your object. Non-underscored variables are things that people using your object might be interested to know are there.

In any case, they seem fairly rare, and I would avoid them unless you want to send a signal to the next guy that's coming along that there's some extra magic or voodoo happening.

As far as making a distinction for method calls, if you're worried that there can be confusion between a method and a local variable, I would call the method on self to clarify. For instance:

def foo
    ...
end

def some_method
    foo # method
    bar # variable
end

If this seems unclear for whatever reason, you can clarify with

def some_method
    self.foo
    bar
end
like image 41
Matt Avatar answered Oct 24 '22 20:10

Matt