If you're reading this post, you're probably familiar with Ruby classes; they're a fundamental part of designing object-oriented programs and are a very convenient and powerful way to store data and functionality for objects. Last week I covered some basics about classes and methods. This week I'm going to go more in-depth about class methods: how they differ from instance methods and when and how to use them.
Class Methods vs. Instance Methods
The difference looks very subtle in the actual code but is significantly different in execution. Take a look at the code below:
class newClass
def self.classMethod
puts "Class method"
end
def instanceMethod
puts "Instance method"
end
end
Did you spot the difference? Class methods are called on the class, or self. This means that this method can be used on all instances of this class.
The instance method, however, is called on an instance of that class, meaning it can't be called without a new or existing instance of that class. Take a look at the code below to see what happens:
class NewClass
def self.classMethod
puts "Class method"
end
def instanceMethod
puts "Instance method"
end
end
NewClass.classMethod #-> "Class method"
NewClass.instanceMethod #-> NoMethodError: undefined method 'instanceMethod' for NewClass:Class
NewClass.new.instanceMethod #-> "Instance method"
NewClass.new.classMethod #-> NoMethodError: undefined method 'classMethod' for #NewClass:0x1e820
We called a class method on our class, which worked perfectly. However, when we tried to call an instance method on the class, we weren't so lucky.
We saw similar results when defining a new instance of our class and calling methods on it. We were able to get the instance method to work but were unable to call the class method on it.
When to use class methods
As a very broad and general rule, class methods are used when you aren't dealing with anything specific to an instance. So if we use last week's basketball teams as an example, you could write a class method that defines the makeup of a starting lineup: point guard, shooting guard, small forward, forward and center. These are universal in every instance of the basketball team class, so we could define it at the class level.
class BasketballTeam
def self.positions
puts "Point guard, shooting guard, small forward, forward, center"
end
end
BasketballTeam.positions #-> Point guard, shooting guard, small forward, forward, center
When to use instance methods
Instance methods, then, are used when data varies from instance to instance. In the basketball example, this would be player names, numbers, etc.
class BasketballTeam
def self.positions
puts "Point guard, shooting guard, small forward, forward, center"
end
def initialize(pg, sg, sf, f, c)
@pg = pg
@sg = sg
@sf = sf
@f = f
@c = c
end
def point_guard
puts "#{@pg}"
end
def shooting_guard
puts "#{@sg}"
end
def small_forward
puts "#{@sf}"
end
def forward
puts "#{@f}"
end
def center
puts "#{@c}"
end
def starters
puts "Point Guard: #{point_guard}\n Shooting Guard: #{shooting_guard}\n Small Forward: #{small_forward}\n Forward: #{forward}\n Center: #{center}"
end
end
MSU = BasketballTeam.new("Keith Appling", "Gary Harris", "Denzel Valentine", "Branden Dawson", "Adreian Payne")
MSU.starters #->
Point Guard: Keith Appling
Shooting Guard: Gary Harris
Small Forward: Denzel Valentine
Forward: Branden Dawson
Center: Adreian Payne