Niel has a great answer for this, I just want to add something to it.
Counting Dogs :)
You need a class variable to do this..
class Dog
@@count = 0 # this is a class variable; all objects created by this class share it
def initialize
@@count += 1 # when we create a new Dog, we increment the count
end
def total
@@count
end
end
There is another way to do this with "instance variables of the Class object" but that's a bit of an advanced topic.
Accessing Instance Variables
In Ruby, variables are really just references to objects / instances.
> x = 1
=> 1
> x.class
=> Fixnum
> 1.instance_variables
=> []
x is a reference to the object '1', which is an instance of class Fixnum.
The '1' object is an instance of Fixnum which does not contain any instance variables.
It is not different in any way from a reference to a new "Dog" instance.
Similarly, you can say x = Dog.new
, then x is a reference to an instance of class Dog.
class Dog
attr_accessor :legs # this defines the 'legs' and 'legs=' methods!
end
x = Dog.new
x.instance_variables
=> [] # if you would assign legs=4 during "initialize", then it would show up here
x.legs = 4 # this is really a method call(!) to the 'legs' method
x.instance_variables # get created when they are first assigned a value
=> [:legs]
It does not matter if you pass such a reference to a method call, or to another class or just evaluate it by itself - Ruby knows it's an object reference, and looks inside the object and it's inheritance chain on how to resolve things.
Resolving Method Names
That was only the partial truth :) When interpreting x.legs
, Ruby checks if there is a method in the class-inheritance chain of the object, which responds to that name 'legs'.
It is not magically accessing the instance variable with the same name!
We can define a method 'legs' by doing "attr_reader :legs" or "attr_accessor :legs", or by defining the method ourselves.
class Dog
def legs
4 # most dogs have 4 legs, we don't need a variable for that
end
end
x.legs # this is a method call! it is not directly accessing a :legs instance variable!
=> 4
x.instance_variables
=> [] # there is no instance variable with name ":legs"
and if we try to implement it as a method and an instance variable, this happens: :)
class Dog
attr_accessor :legs # this creates "def legs" and "def legs=" methods behind the scenes
def legs # here we explicitly override the "def legs" method from the line above.
4
end
end
x = Dog.new
x.legs # that's the method call we implemented explicitly
=> 4
x.legs = 3 # we can still assign something to the instance_variable via legs=
=> 3
x.legs # the last definition of a method overrides previous definitions
# e.g. it overrides the automatically generated "legs" method
=> 4
attr_accessor :legs
is just a short hand notation for doing this:
class Dog
def legs
@legs
end
def legs=(value)
@legs = value
end
end
there is no magic way instance variable get automatically accessed. They are always accessed through a method, which can be overridden later.
I hope that makes sense to you