Search code examples
rubyinstance-variablesclass-instance-variables

Why are my instance variables not existing across methods of the same class in ruby?


I am doing the ruby koans and I am on the DiceSet project. I've made the DiceSet class but my instance variables don't seem to persist with the instance like I thought they would. My code is

class DiceSet
   attr_reader :values
   @values = []
   puts @values.class
   def roll(number_of_rolls)
     (1..number_of_rolls).each do |roll|
       puts @values.class
       @values << (1..6).to_a.sample
     end
     return @values
   end
end

The koan then uses my DiceSet class with

dice = DiceSet.new
dice.roll(5)
puts dice.values.class
assert dice.values.is?(Array)

I put the puts commands in there to follow whats happening with the @values instance variable and only the first puts @values.class says its an Array class. All the others are returning NilClass. Am I using instance variables incorrectly or is there something else I am missing? Do instance variables get deallocated after a method call?

EDIT: My class works correctly now that I have put @values = [] in the roll method as suggested below. My only question now, is why the roll method thinks that @values is a NilClass instead of an array when I put @values = [] in an initialize method


Solution

  • In Ruby everything are objects. The Ruby interpreter assumes that all instance variables belong to the current object self. This is also true in a class definition. The role of self belongs to the class itself, so the instance variable @values belongs to the class. Don’t get confused! Instance variables of the class are different from instance variables of that class’s objects. Also you don't need specify return keyword explicitly Try this:

    class DiceSet
       attr_accessor :values       
    
       def roll(number_of_rolls)
         @values = []
         (1..number_of_rolls).each do |roll|
           @values << (1..6).to_a.sample
         end
         @values
       end
    end
    
    dice = DiceSet.new
    dice.roll(5)
    puts dice.values.class
    assert dice.values.is_a?(Array)