Duck Typing
Fast recall
Quick revision
Core answer
notifier.deliver(message) can work with Email, SMS, or a test double as long as each honours that contract. This gives flexible composition, but missing methods fail at runtime, so clear behaviour contracts and focused tests matter.Whether you know duck typing = rely on behavior (methods), not class — 'if it quacks like a duck'.
Over-checking types with is_a? (use duck typing — call the method), or assuming a method exists without a clear contract.
Duck typing = rely on behavior, not class. def speak(x); x.sound works for anything with sound. Favor calling methods over is_a? checks.
Interview-ready guide
Interview answer
Duck typing is Ruby's behaviour-first form of polymorphism. A method does not require an object to belong to one declared class or interface. It simply sends the messages needed for the job. Any object that understands those messages and follows their meaning can be used.
Suppose send_alert(notifier, message) calls only notifier.deliver(message). An email notifier, an SMS notifier, and a fake used in a test can all take that place. They do not need a common parent class; each one only needs to honour the small deliver contract.
The caller below knows only about deliver. Changing the receiver changes the behaviour without adding a class check or changing send_alert. This keeps the caller small and also makes a test double easy to supply.
The trade-off is that Ruby checks compatibility when the code runs. A missing method raises NoMethodError, and a method with the right name can still return the wrong result. Keep duck-typed interfaces small and cover every implementation with the same contract tests. Use respond_to? when a capability is genuinely optional, not before every required call.
Duck Typing
Direct Answer
Duck typing means Ruby code depends on the messages an object can handle rather than requiring one declared class or interface. A method that calls notifier.deliver(message) can work with Email, SMS, or a test double as long as each honours that contract. This gives flexible composition, but missing methods fail at runtime, so clear behaviour contracts and focused tests matter.
Deep Dive & Architecture
The caller defines a protocol implicitly through the messages it sends. If a report exporter calls open, write, and close, any object with compatible implementations can participate. The protocol includes more than method names: argument forms, returned values, side effects, and failure behaviour must also line up.
This is late binding. Ruby selects the method from the runtime receiver, so unrelated classes can provide interchangeable behaviour. Test doubles are simple for the same reason: a fake object needs the small protocol exercised by the test, not the full production class hierarchy.
Flexibility moves some feedback from compile time to execution. A call may fail with NoMethodError, and a method with the right name can still have the wrong semantics. Shared examples or contract tests give every implementation the same behavioural checks. Static tooling or RBS signatures can add earlier feedback without changing Ruby's runtime dispatch.
respond_to? asks whether an object reports a method, including respond_to_missing? for dynamic APIs. It is appropriate when the branch truly supports optional behaviour—for example, call flush only on writers that offer it. For a required capability, calling the method and testing the contract usually makes the failure clearer than scattering defensive checks.
Code Example
class EmailNotifier
def deliver(message)
"email: #{message}"
end
end
class SmsNotifier
def deliver(message)
"sms: #{message}"
end
end
def send_alert(notifier, message)
notifier.deliver(message) # no class check
end
send_alert(EmailNotifier.new, 'build failed') # => 'email: build failed'
send_alert(SmsNotifier.new, 'build failed') # => 'sms: build failed'
Common Mistakes & Pitfalls
Over-checking types with is_a? (use duck typing — call the method), or assuming a method exists without a clear contract.
Check your understanding
Answer these without looking back at the article.
- When would you use Duck Typing in a real project?
- How would you compare Duck Typing with an alternative?
- What is a common mistake when using Duck Typing?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.