Duck Typing in Ruby
Duck typing takes its name from the saying: 'if it walks like a duck and quacks like a duck, it's a duck.' In Ruby, this means code cares about what an object can do — which methods it responds to — rather than what class it belongs to. Instead of writing if object.is_a?(Duck) before calling object.quack, idiomatic Ruby simply calls object.quack and trusts that any object passed in will respond appropriately, or lets a NoMethodError surface naturally if it doesn't. This is a direct consequence of Ruby being dynamically typed: method calls are resolved at runtime based on the object's actual behavior.
Cricket analogy: A captain doesn't check a fielder's jersey number before throwing them the ball at short cover; if the player can catch, they get the catch, just as Ruby calls object.quack and trusts it responds rather than checking object.is_a?(Duck).
Why duck typing over type checking
Explicit type checks with is_a? or kind_of? couple your code to specific classes, making it brittle and hard to extend. Duck typing decouples code from concrete types, so any object that implements the expected interface can be used interchangeably — this is what allows File, StringIO, and custom loggers to all work anywhere Ruby expects something 'IO-like,' as long as they implement methods like read or write.
Cricket analogy: A selector who only picks players from a fixed list of 'opening batsmen' misses out on an all-rounder who could open just as well; duck typing lets any IO-like object like File or StringIO step into the same role, as long as it can 'bat.'
class PdfReport
def render
'PDF bytes...'
end
end
class CsvReport
def render
'col1,col2\nval1,val2'
end
end
# No shared superclass or interface declaration needed.
# Any object that responds to #render works here.
def publish(report)
puts report.render
end
publish(PdfReport.new)
publish(CsvReport.new)Checking capability, not class
When you genuinely need to verify an object supports an operation before calling it — for example, in a library that accepts many kinds of input — the duck-typed idiom is respond_to?, not is_a?. This still asks 'can you do this?' rather than 'what are you?', preserving the flexibility duck typing is meant to provide.
Cricket analogy: Before trusting a substitute fielder to take a high catch under pressure, a captain might ask 'can you catch?' rather than checking their registration category, just as respond_to? asks whether an object can act, not what it is.
def serialize(data)
if data.respond_to?(:to_h)
data.to_h
elsif data.respond_to?(:to_a)
data.to_a
else
data.to_s
end
endDuck typing is closely related to structural typing in statically typed languages like TypeScript or Go, where an object satisfies an interface simply by implementing its methods, with no explicit 'implements' declaration required. Ruby takes this idea further by resolving it entirely at runtime, with no compile-time interface check at all.
Because Ruby performs no compile-time checking, a typo like object.quak instead of object.quack won't be caught until that line actually executes — potentially in production. This is why comprehensive test coverage (e.g. via RSpec) matters more in duck-typed code than in statically typed languages.
- Duck typing means Ruby cares about what methods an object responds to, not its class.
- Prefer calling a method directly, or checking
respond_to?, over checkingis_a?/kind_of?. - Duck typing enables polymorphism without shared superclasses or explicit interfaces.
- It trades compile-time safety for flexibility, making thorough tests essential.
- Many core Ruby and Rails APIs (e.g. anything 'IO-like' or 'Enumerable-like') rely on duck typing.
- It parallels structural typing in languages like TypeScript and Go, but is fully dynamic in Ruby.
Practice what you learned
1. What does duck typing primarily evaluate about an object?
2. Which method is most idiomatic for checking whether an object can perform an operation in duck-typed code?
3. What happens if code calls a method an object does not implement, under duck typing?
4. Which statically-typed language concept is most analogous to Ruby's duck typing?
5. Why might excessive use of `is_a?` checks be considered un-idiomatic in Ruby?
Was this page helpful?
You May Also Like
method_missing and respond_to?
Explore Ruby's dynamic dispatch fallback: how method_missing intercepts unknown method calls, and why it must be paired with respond_to_missing? for correct, well-behaved objects.
Modules and Mixins
Discover how Ruby modules group related methods and constants, and how mixing them into classes with include, extend, and prepend enables flexible code reuse without multiple inheritance.
Comparable and Enumerable Modules
See how Ruby's Comparable and Enumerable modules let a class gain dozens of methods for free by implementing just one core method each: `<=>` or `each`.
Classes and Objects in Ruby
Learn how Ruby defines classes as blueprints for objects, covering the `class` keyword, `initialize`, instance methods, and how everything in Ruby is an object.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics