Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby - instance methods: why can i use getter without self, but setter only with self

Tags:

ruby

I have been using Ruby for a while. Now i'm going to dig deeper and find all answers to questions that i have. I hope i will find answer to this one here. So here is my question in code below:

class Game

  attr_accessor :in_progress

  def initialize
    @in_progress = false
  end

  def start!

    # debug info                                                                         
    puts self.inspect                        # => #<Game:0x8f616f4 @in_progress=false>
    puts self.class.instance_methods(false)  # => [:in_progress, :in_progress=, :start!]
    puts self.instance_variables             # => [:@in_progress]
    puts self.respond_to?("in_progress=")    # => true

    puts in_progress      # => true - getter works without self
    # main quesion
    in_progress = true    # Why setter doesn't work without self?

    # self.in_progress = true   # this would work and set @in_progress to true becase setter called
    # @in_progress = true       # this would work as well because we set instance variable to true directly

  end

end

g = Game.new
g.start!
puts g.in_progress # => false - setter in start! method didn't work

What we have here:

  1. Class Game with getter and setter for @in_progress variable
  2. @in_progress is false by default
  3. We call start! method and try to change in_progress to true
  4. Getter for in_progress works well
  5. Setter works only with self. or with direct access to variable through @in_progress

I read about method lookup in Ruby (Go one step to the right into the receiver's class, and then up the ancestors chain, until you find the method.) But i really don't know why i have to use self.in_progress=true to get access to setter method. Especially when getter method works without self.

Thanks in advance!

like image 301
Sergey M Avatar asked Oct 27 '13 10:10

Sergey M


2 Answers

Because you are assigning value to local variable in_progress in a function, not the instance variable. The getter works because Ruby will query the local namespace of the start! function for in_progress, it will not find it and then it will query the instance namespace and it will find a method called in_progress and will call it.

There is no way Ruby interpreter can find out whether you want to assign the true value in a local in_progress or on the instance variable, so the rule is to assign it locally (to the current namespace in start!).

like image 197
Lachezar Avatar answered Nov 13 '22 07:11

Lachezar


When you do in_progress = true, you actually create a local variable inside your method and not accessing your setter.

When you do puts in_progress, Ruby checks for an in_progress local variable and when it cant find it, it goes for the getter of your class.

Try doing in_progress = 'hello' and then do puts in_progress. You will realize that Ruby is going to use the local variable in_progress.

like image 36
Steve Robinson Avatar answered Nov 13 '22 07:11

Steve Robinson