My Ruby 💌 newsletter 💌 is available here ! Feel free to subscribe ! 🚀

The super keyword

In this article we’re going to explore the following topics:

  • implicit arguments
  • super vs super()
  • super with blocks
  • super with the ancestors chain

implicit arguments

When a method with arguments is overridden by one of its children classes, then a call to super without any argument in the child method will automatically pass the arguments of the child method to the parent method.

Let’s have a look to the following example

class Parent
def say(message)
puts message
end
end
class Child < Parent
def say(message)
super
end
end
irb> Child.new.say('Hi!')
Hi!

Here the Child class inherit from the Parent class. The Child class overrides the Parent#say method.

Within the Child#say method we call super without any argument.

So, Ruby tries to find a method #say in the ancestors chain of the Child class and then passes the message argument to the founded method.

NB: feel free to have a look to my article if you’re unfamiliar with the Ancestors Chain mechanism in Ruby.

But, what if the Parent#say method doesn’t expect any argument ?

super vs super()

Let’s redefine the Parent#say method by removing the message argument

class Parent
def say
puts "I'm the parent"
end
end
class Child < Parent
def say(message)
super
end
end
irb> Child.new.say('Hi!')
ArgumentError (wrong number of arguments (given 1, expected 0))

An ArgumentError is raised because the Parent#say method doesn’t expect any argument but the call to super in the Child#say implicitly passes the message argument from the Child#say method to the Parent#say method.

To avoid this problem, we can explicitly indicate to super to don’t take any argument from the Child#say method.

To do so, we can add parentheses to the super keyword — super()

class Parent
def say
puts "I'm the parent"
end
end
class Child < Parent
def say(message)
super()
end
end
irb> Child.new.say('Hi!')
I'm the parent

So let’s try to pass a block to our Parent#say method.

super with blocks

Let’s redefine the Parent#say method by adding a yield keyword in it

class Parent
def say
yield
end
end
class Child < Parent
def say
super
end
end
irb> Child.new.say { puts 'Hi! Glad to know you Parent!' }
Hi! Glad to know you Parent!

The block passed to the Child.new.say method call is implicitly passed to the Parent#say method through the super keyword.

Then we use the yield keyword to catch the block and execute it in the Parent#say method.

NB: feel free to have a look to The yield keyword article if you’re unfamiliar with the yield keyword.

super with the ancestors chain

Let’s make the Parent class inherit from the GrandParent class which defines the #say method

class GrandParent
def say(message)
puts "GrandParent: #{message}"
end
end
class Parent < GrandParent
end
class Child < Parent
def say(message)
super
end
end
irb> Child.new.say('Hi!')
GrandParent: Hi!

Here we can see that the super keyword try to find the #say method in the Parent class.

The Parent class doesn’t define this method so super tries to find the #say method in the superclass of the Parent class (the GrandParent class).

The GrandParent class defines the #say method.

So, The 'Hi!' argument passed to the Child.new.say method call is implicitly passed to the GrandParent#say method through the super keyword.

Voilà!


Thank you for taking the time to read this post :-)

Feel free to 👏 and share this Medium post if it has been useful for you.

Here is a link to my last medium post: Method Arguments in Ruby: Part II.