One of my big breakthroughs in understanding object oriented design in Ruby came when I learned about duck typing. Wikipedia provides a nice definiition of the concept:
duck typing is a style of typing in which an object’s methods and properties determine the valid semantics, rather than its inheritance from a particular class or implementation of an explicit interface.
This means that in Ruby it does not matter if an object is a specific type or class, only that it can respond to a given message. For example, in the stringify
method below, it does not matter if the argument is an integer or symbol or some other class, only that it can respond to the to_s
method.
def stringify(a)
a.to_s
end
stringify(1)
=> "1"
stringify(:hello)
=> "hello"
class NewClass
def to_s
"works for custom objects too!"
end
end
stringify(NewClass.new)
=> "works for custom objects too!"
Not having to care about a specific object’s class enables a lot of flexiblity for swaping out collaborator objects. To illustrate this, let’s take a look at an example:
File Storage with Duck Typing
My app generates reports, and I would like to save these reports. Initially, I just want to save the reports to my local disk.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Later, I decide that it would also be nice to have the ability to upload reports to S3. With duck typing, implementing this new feature is as simple as creating a new class for uploading to S3 which implements a store
method:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Start thinking about objects in terms of the messages they receive, and you will be rewarded with the flexibility that duck typing allows.