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.


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

Seeing as how instance variables have the @ sign in front of them, and global variables have the $ sign in front of them already in ruby, it is probably unnecessary to put an underscore character in front of the variable names. That being said, I don't think it is a bad practice necessarily. If it helps you to read or write your code in Ruby, then you should use it.

I have sometimes seen Ruby code where an argument for an instance method on a class has an underscore in front of it. Such as:

def my_method(_argument1)
  # do something
end

And I think that when you are dealing with a class that may have it's own attributes, like a model file in rails, for instance, this can be helpful so that you know you are dealing with a variable that has been passed into the method as opposed to one of the attributes that belongs to the class/model.


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