James Mitchell
James Mitchell

Reputation: 2467

Scope of instance variable on class methods

I'm trying to get the following code to work.

class Animal

end

class Tiger < Animal
    @hunger = 100

    def self.hunger
        @hunger 
    end

    def run
        puts "The Tiger runs"
        @hunger += 10
    end
end

class Statistics
    puts "This tigers hunger is: #{Tiger.hunger}" 
end

tiger = Tiger.new()
tiger.run

So the tiger has a variable called hunger which is by itself at the top of the Tiger class. I want to make it so this variable can be changed throughout the class methods. For example in run the hunger is set to hunger += 10, but when I run this code I get an undefined method '+' for nil:NilClass (NoMethodError). What do I do to make this program work so the variable can be changed and then displayed in the Statistics class?

Upvotes: 0

Views: 63

Answers (3)

ndnenkov
ndnenkov

Reputation: 36110

The problem is that you have completely mushed class and instance variables/methods together.

If you want to use instances (which you should):

class Animal; end

class Tiger < Animal
  attr_reader :hunger

  def initialize
    @hunger = 100
  end

  def run
    puts "The Tiger runs"
    @hunger += 10
  end
end

class Statistics
  def self.show(tiger)
    puts "This tigers hunger is: #{tiger.hunger}" 
  end
end

tiger = Tiger.new
tiger.run
Statistics.show(tiger)

If you want to use class methods/variables:

class Animal; end

class Tiger < Animal
  @hunger = 100

  def self.hunger
    @hunger
  end

  def self.run
    puts "The Tiger runs"
    @hunger += 10
  end
end

class Statistics
  def self.show
    puts "This tigers hunger is: #{Tiger.hunger}" 
  end
end

Tiger.run
Statistics.show

Note that @hunger is now a class instance variable of Tiger. The difference between class instance variables and class variables (ones defined with @@) is that the latter is shared by all descendants of the said class, while the former is only tied to the class where it was defined.

I do not agree with your descision about Statistic in either case though.

Upvotes: 2

user1943992
user1943992

Reputation: 222

Don't you need an initialize method in your Tiger class?

def initialize()
@hunger = 100
end

I am confused about your Statistics class. Shouldn't this be a method in the Tiger class? How does it know what Tiger to access? I would add that puts in a method taking your tiger as a parameter if you want to do that.

class Statistics
def tiger_stat(tiger_name)
puts "This tigers hunger is: #{tiger_name.hunger}" 
end
end

Edit* this is the code I would use:

class Animal
    def initialize(animal_type, hunger_start)
        @animal_type = animal_type
        @hunger = hunger_start
    end

    def hunger_print
        puts "This #{@animal_type}'s hunger is: #{@hunger}."
    end
end

class Tiger < Animal
    def initialize
        super("Tiger", 100)
    end

    def run
        puts "The Tiger runs"
        @hunger += 10
    end
end

This way you can call hunger_print on any animal without worrying about the type or making an extra class. You could do something like.

tiger = Tiger.new
tiger.run
tiger.hunger_print

Upvotes: 1

Tasos Stathopoulos
Tasos Stathopoulos

Reputation: 166

You can use class variable that is access from both instance and class methods.

class Animal
  @@hunger = 100

  def self.hunger
    @@hunger
  end

  def self.increase_hunger
    @@hunger +=1
  end

  def hunger
    @@hunger
  end

  def increase_hunger
    @@hunger += 1
  end
end

Animal.increase_hunger
puts Animal.hunger # => 101
animal = Animal.new
animal.increase_hunger
puts animal.hunger # => 102

Upvotes: 0

Related Questions