10

I'm learning Ruby right now, and I'm confused as to why I can refer to an instance variable without the @ sigil, which would make it a local variable too. Surely the following code shouldn't work as it does:

class Test
  attr_accessor :variable
  def something
    variable
  end
  def something2
    @variable
  end
  def something3
    self.variable
  end
end

y = Test.new
y.variable = 10
puts y.something  # => 10
puts y.something2 # => 10
puts y.something3 # => 10

I'd have expected y.something to return nil. Why do local variables and instance variables point to the same location? I'd have expected @variable and variable to have been two discrete variables.

1 Answer 1

19

In the code you posted, variable is not a local variable. It is a method call to the instance method named variable, which was defined by:

attr_accessor :variable

This is a shorthand for the following method definitions:

def variable
  @variable
end

def variable=(value)
  @variable = value
end

Note that Ruby does not require parentheses () for a method call, so distinguishing between a local variable and a method is not always easy.

Compare your code with:

class Test
  attr_accessor :foo

  def example1
    foo = nil  # 'foo' is now a local variable
    foo
  end

  def example2
    foo        # 'foo' is a method call
  end
end

x = Test.new
x.foo = 10
x.example1  # => nil
x.example2  # => 10
Sign up to request clarification or add additional context in comments.

5 Comments

That makes so much more sense!
Nitpick: it is perfectly possible to distinguish between a local variable reference and an argumentless receiverless message send without knowing which methods exist. In fact, it has to possible, because the distinction is made statically at parse time, while methods get defined dynamically at runtime. IOW: when the distinction is made, the methods don't even exist yet. Replace your foo = nil with if false; foo = 42 end to see exactly how it works.
You're right; always possible, but not always easy for a human. I've adjusted my answer to be more correct.
Technically, I believe your foo = nil line is calling the foo= method. If you change your example to use an attr_reader, it would be more correct, but then x.foo = 10 would break.
@bheeshmar: No, foo = nil will never call a method. You have to use self.foo = nil to accomplish that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.