gordie
gordie

Reputation: 1955

How to declare a 'static' variable in a ruby class?

I know PHP & Javascript, but I'm just starting to learn Ruby.

This is currently working :

  class Animal
    attr_accessor :name, :mammal
    def initialize(name)
      @name = name
    end
  end

  class Fish < Animal
    def initialize(name)
      super(name)
      @mammal = false
    end
  end

  class Cow < Animal
    def initialize(name)
      super(name)
      @mammal = true
    end
  end

  animals = [
    Fish.new('Moppy'),
    Cow.new('Marguerite'),
  ]

  animals.each do |animal|
    puts "Is #{animal.name} a mammal ? #{animal.mammal}"
  end

See the @mammal var in the sub classes ?

They are 'static' variables which do not depend of the instance, but of the class itself (a cow will always be a mammal, while a fish won't)

I was wondering if I was declaring the @mammal var at the right place. Instinctively, I would rather have done this

  class Cow < Animal
    @mammal = true
    def initialize(name)
      super(name)
    end
  end

but then it does not work... Could someone tell me if how you should handle this with Ruby ?

Thanks !

Upvotes: 1

Views: 543

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110685

For each subclass, @mammal is the same for all instances and is not intended to change. It therefore should be a constant or the value returned by a class method. I initially chose the former, but have been convinced by @tadman in the comments that a class method would be preferable, in particular a method with a name ending with a question mark. If interested, see my original answer in the edit history.

class Animal
  attr_accessor :name
  def initialize(name)
    @name = name
  end
end

class Fish < Animal
  def initialize(name)
    super
  end
  def self.mammal?
    false
  end
end

class Cow < Animal
  def initialize(name)
    super
  end
  def self.mammal?
    true
  end
end

i = Fish.new('Moppy')
"#{i.name} is a mammal: #{i.class.mammal?}"
  #=> "Moppy is a mammal: false" 
i = Cow.new('Marguerite')
"#{i.name} is a mammal: #{i.class.mammal?}"
  #=> "Marguerite is a mammal: true" 

Upvotes: 0

Masklinn
Masklinn

Reputation: 42292

@var is an instance variable and @@var is a class variable (both private).

@var in class scope also works, but it's an instance variable on the class which is a bit different because (as all instance variables) it's going to be private to the class instance and thus not accessible to the class's instances, so you need to define a class-level accessor for it.

A big difference between class variables (@@) and class instance variables (@ in class scope) is that the first is shared throughout the inheritance tree while the second is private to one specific class. But given your structure Mammal being a class would make more sense than either.

See Ruby class instance variable vs. class variable for various examples.

Upvotes: 0

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

If you want a class-wide variable, define an instance variable on class level.

class Animal
    attr_accessor :name
    def initialize(name)
      @name = name
    end

    def self.mammal # class level
      @mammal
    end
  end

  class Fish < Animal
    @mammal = false # class level
  end

  class Cow < Animal
    @mammal = true # class level
  end

  [
    Fish.new('Moppy'),
    Cow.new('Marguerite'),
  ].each do |animal|
    puts "Is #{animal.name} a mammal ? #{animal.class.mammal}"
  end

Also, one might use so-called “class variables” @mammal, but they behave weirdly under some circumstances, so instance variable on the class level would fit your needs better.

Upvotes: 1

ReggieB
ReggieB

Reputation: 8212

The simplest solution is:

  class Fish < Animal
    def mammal
      false
    end
  end

  class Cow < Animal
    def mammal
      true
    end
  end

Personally I'd be tempted to do something like:

  class Animal
    attr_accessor :name

    def initialize(name)
      @name = name
    end

    def mammal
      false
    end
  end

  class Mammal < Animal
    def mammal
      true
    end
  end

  class Fish < Amimal
  end

  class Cow < Mammal
  end

Upvotes: 3

Related Questions