Class Methods vs Instance Methods


A class method is a method that is defined on our class. The syntax for creating a class method involves using the word self.method_name_here. But what is self and what is it referring to?

class Cat

@@all = []

def initialize(name, breed, age)
@name = name
@breed = breed
@age = age
@@all << self
end

def self.all #This is the same as writing Cat.all
@@all
end

end

Here we have a class Cat that contains one class method, self.all, that returns our entire collection of cats that we have. As you may have noticed by the comment, self.all is the equivalent to writing Cat.all. If you were to throw yourself inside our class method using pry and called self you would get back our class Cat. So self in our method name refers back to the class. Why do we do this? As programmers we like to make our code as flexible/reusable as possible, using self will allow us to change the class name if needed but also to easily inherit other methods from other classes.

What is an instance method?

Well to start off, what is an instance? An instance is an object that we initialize within our class.

Cat1 = Cat.new("Catty", "Siamese", 7)

Here we are creating a new Cat object that we’ve assigned to the variable Cat1. Our instance methods are methods that can work on these objects, or instances. For example, if I wanted to make a method in our class that would allow for my cat to meow.

def meow
puts "meow"
end

Notice that there’s no self in our method name? Thats the tell that our method is only for our instance, Cat1. If I were to run this method on Cat1, self would be our cat object.

#<Cat:0x007ff4562024c8 @name="Catty", @breed="Siamese", @age=7> 
^ Our cat object, aka self

Refer back to when we created a new cat and set it to a variable, Cat1. We can now call our meow method on our instance.

Cat1.meow
meow
=> nil #our return value for using puts

But what if my collection of cats is actually a choir of cats that I’m extorting for money? Well we use our class methods to refer to our collection of data, so we’d have to build a class method that goes through each of our cats and calls the meow method on them.

# Lets pretend our cats collection is now full of cat objects 
# @@all = [#<Cat:0x007ff4562024c8 @name="Catty", @breed="Siamese", @age=7>, #<Cat:0x007ff456835098 @name="Birtha", @breed="Ragdoll", @age=2>, #<Cat:0x007ff4561eb8b8 @name="Igloo", @breed="Bengal", @age=5>]
def self.make_the_cats_meow
self.all.each do |each_cat_object|
puts "#{each_cat_object.meow}"
end
end

This class method is running our meow instance method on each of our instances, which should return 3 different meows. But if I can refer to our class variable @@all in an instance method, why wouldn’t I make an instance method to make all the cats meow? Good question. While it would somewhat work, it doesn’t exactly make the most sense. Why would you call on Cat1 to make all cats meow rather than my class Cat which is supposed to refer to all my data?

So, whats the golden rule of when we should create our methods?

Make class methods when wanting to refer to all your data that exists in the class. Make instance methods for when you want to run on one specific instance, or small piece of data.