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.