Learn Ruby and rails from rails guru
Posts tagged instance variables
Quick Ruby Tutorials-3, class and instance methods
Apr 6th
This is a continuation of the following series of posts
Quick Ruby Tutorials-1
Quick Ruby Tutorials-2
In the last post our Dog class had the abilities to eat, sleep, bark, shit etc.
The class definition for Dog class looked like
attr_reader :weight, :height, :color
attr_accessor: name
def initialize(weight = 1,height = 0.5, color = "white")
puts "in initialize"
@weight, @height, @color = weight, height, color
end
def bark
puts "bhow bhow!!!"
end
def eat(food="bone")
puts "I am eating #{food}"
end
def sleep
puts "bbye, I am going to sleep"
end
def shit
puts "aah! now I am hungry again"
end
end
Let us extend it.
Besides other activities like sleeping, barking etc, our dog can now eat food.
On eating the food digestion should start. We make one more method for the same and call it in
the “eat” method.
def eat(food="bone")
puts "I am eating #{food}"
digest_food
end
def digest_food
puts "digesting food"
end
end
d = dog.new
d.eat
# I am eating bone
#digesting food
We could have written the code to digest food in the method “eat”, but we create a separate method called “digest” and call this method in “eat”. This is known as Single Responsibility Principle(SRP), ie each method should have only one responsibility. This helps to maintain the code.In future if the code changes, it is easier to change and test a small method which does only one thing. If we have a method which is big and performs many tasks at the same time then it is difficult to change and maintain the code.
Here we can directly call the digest_food method as shown.
This is not correct, digestion should only start after eating food. If we call digest_food directly then it can start even if the dog has not eaten the food.
Digesting food is an internal function of the dog which is triggered due to some other external event( here eating food).We should not be able to access digest_food method from outside the class.
For this we will make the digest_food method as private.
Private??
What are Private and Public Methods?
Private methods are ones which cannot be accessed/called from outside the class.
The methods which we were defining till now were public methods. By default all the methods of the class are public ie they can be accessed inside/outside the class. To make a method as private we need to add a keyword private as shown below.
private
def digest_food
end
def another_method
end
end
d = Dog.new
d.digest_food #error: private method digest food called
d.another_method #error: private method another_method called
As seen above, all the methods defined after the keyword private are private methods.
So our class definition looks like.
def eat(food="bone")
puts "I am eating #{food}"
digest_food
end
private
def digest_food
puts "digesting food"
end
end
d = dog.new
d.digest_method #error: private method another_method called
What are Class methods and Instance Methods?
Whatever methods we were defining till now were instance methods. Like bark, eat, digest_food etc.
We called these methods with respect to the instance/object like.
dog.bark
As these methods are related to an instance of the class they are called instance methods.
We cannot call instance method with respect to the class.
dog.weight #works
Dog.weight #error: NoMethod error
Class methods are ones which are called with respect to the class.
We have already come across a class method “new”. We don’t need to define “new” as Ruby gives this method for free with every class
.
We do Dog.new, we cannot do dog.new.
Class variables and instance variables
Instance variables are variables which are linked to the instance/object of the class
Instance variables as we have seen start with @ sign. There is a separate copy of the instance variable for each instance. They are accessible within a class in all the instance methods. They are not accessible outside a class. They are the ones responsible to store the data for an instance/object.
Class variables are once which store the data at class level.
Only one copy of the class variable is created for a class.
Class variables can be accessed in class as well as instance method.
There is a separate copy of instance variable for for every instance, but there is only one copy class variable.
Let us use a class variable to keep the count of number of dogs born.
@@population
end
#NameError: uninitialized class variable @@population in Dog
Above we defined a class variable population. Class variables are defined by adding a “@@”" before the variable name. But we need to initialize a class variable when it is being defined.
@@population = 0
end
We will increment the count of population after each dog is born. We can do this in the initialize method. We will also add a class method to access the value of the class variable.
@@population = 0
def initialize
@@population += 1
end
def self.population
return @@population
end
end
puts Dog.population # 0
d1 = Dog.new
puts Dog.population # 1
d1 = Dog.new
puts Dog.population # 1
d2 = Dog.new
puts Dog.population # 2
d3 = Dog.new
puts Dog.population # 3
Note how the class method is defined. A extra “self.” is added in front of the method name.
Let us try accessing the object_id(it is unique for every object) of the variable @@population in a class method and instance method.
@@population = 0
def initialize
@@population ++
end
def self.population
return @@population
end
def population
return @@population
end
def self.class_population_id
return @@population.object_id
end
def instance_population_id
return @@population.object_id
end
end
puts Dog.population # 0
d1 = Dog.new
d2 = Dog.new
d3 = Dog.new
d4 = Dog.new
puts Dog.population # 4
puts d1.instance_population_id # 233323
puts d2.instance_population_id # 233323
puts d3.instance_population_id # 233323
puts d4.instance_population_id # 233323
puts Dog.class_population_id #233323
Above we have done the following
- defined a class and instance method “population” to access the population count.
- defined a class and instance method “class_population_id” and “instance_population_id” to access the object_id of the class variable @@population.
The value of the population count from class and different instances is the same.
The object_id of class_variable @@population is also same from class and instance methods.
This implies that there is only one copy of the class variable.
More examples of a class method could be
- a find method to find the dogs with a particular name
- a count method which will return the total number of dogs
- an average age method which returns the average age of all the dogs which are alive.
Note the above all methods are performing some operation on a set of dogs, not on an individual dog, so they have to be defined as a class method.
We can use instance methods in place of class method, and call it with reference to a particular instance, but it is not the correct way.
def average_weight
puts "This should have been defined as a class method"
end
end
dog = Dog.new
dog.average_weight # This should have been defined as a class method
end
class Dog
def self.average_weight
puts "perfect"
end
end
Dog.average_weight #perfect
We can also use class methods in place of instance methods by passing the instance as a parameter to the method but again that is not the correct way.
def self.weight(dog)
puts "this should have been as instance method as it is related only to a particular dog."
end
end
dog = Dog.new
Dog.weight(dog) #this should have been as instance method as it is related only to a particular dog.
class Dog
def weight
puts "perfect"
end
end
dog = Dog.new
dog.weight #perfect
So In this post we have seen the following
Public And Private methods
Class methods and Instance methods
Class variable and instance variable.
More in the next post.
Share

