Skip to content
AgileLogics
5 min read

Polymorphism and Duck Typing

Prerequisites: Inheritance

Polymorphism means different objects can respond to the same method call in their own way. Code that calls the method doesn't need to know which kind of object it has.

In Ruby this goes further than inheritance, through duck typing: "If it walks like a duck and quacks like a duck, it's a duck." Ruby doesn't check an object's class before calling a method — only whether the object has that method.

Example

class EmailNotifier
  def deliver(message) = "Email: #{message}"
end

class SmsNotifier
  def deliver(message) = "SMS: #{message[0, 20]}"
end

class LogNotifier
  def deliver(message) = "Log: #{message}"
end

notifiers = [EmailNotifier.new, SmsNotifier.new, LogNotifier.new]

notifiers.each do |notifier|
  puts notifier.deliver("Your order has shipped today")
end

Expected output

Email: Your order has shipped today
SMS: Your order has shipp
Log: Your order has shipped today

The three classes share no parent class. They only share a method name, and that's enough. Adding a SlackNotifier later needs no change to the loop.

Checking capabilities, not classes

When you need to check, ask whether an object can do something rather than what class it is:

def print_all(items)
  items.each { |item| puts item }
end

print_all([1, 2])
print_all(1..2)

p [1, 2].respond_to?(:each)
p 42.respond_to?(:each)
1
2
1
2
true
false

print_all works with an array and a range — anything with each.

Common mistakes

  • Writing if obj.is_a?(EmailNotifier) ... elsif obj.is_a?(SmsNotifier) chains. Give each class the same method instead, and just call it.