Making Ruby Quack—Why We Love Duck Typing

Share this article

One of the most lauded features of Ruby is its support for the technique known as duck typing. Despite the humorous name, duck typing enables Ruby developers to write succinct, clean, and readable code with very little effort—all the things that attracted us to Ruby in the first place.

“What would Duck Dodgers do?”

The basic premise of duck typing is simple. If an entity looks, walks, and quacks like a duck, for all intents and purposes it’s fair to assume that one is dealing with a member of the species anas platyrhynchos. In practical Ruby terms, this means that it’s possible to try calling any method on any object, regardless of its class. To demonstrate, here’s a simple scenario: you’re working with a system that tracks shipping manifests for each container on a ship. Data for each manifest is easily obtained through a RESTful web service:
# Fields:
# * package_count: number of packages in manifest (integer)
# * mass:          total mass of all packages, in kilograms (BigDecimal)
class ShippingManifest
  attr_accessor :package_count, :mass
end
Each ShippingManifest tracks the number of packages, as well as the combined mass for all the packages. Your task is to take a set of manifests (provided in an Array) and give a summation of the total mass and the total number of packages in the set.

“You say the Loch Ness Monster is living in your jacuzzi?”

The problem looks simple enough, right? We could probably bash it out in nine or ten lines of code:
def summarise_manifests
  # Grab the latest set of Manifests (returns an Array)
  manifest_set = ShippingManifest.all

  # Initialize our counters
  total_package_count = 0
  total_mass          = BigDecimal("0")

  manifest_set.each do |m|
    total_package_count += m.package_count
    total_mass += m.mass
  end

  return [total_package_count, total_mass]
end
Easy, but verbose. It’s possible to reduce this method to a single line of code:
def summarise_manifests
  ShippingManifest.all.sum
end
How? Duck typing!

“Skeleton key, eh? Where did you pick that up?”

Our one-line solution takes advantage of one of Ruby’s most powerful features: the Enumerable module. Enumerable provides an API to easily manipulate collections of objects—most commonly Array and Hash.
Specifically, we’re using a method defined in ActiveSupport: sum, which is available in every Rails project. As the name suggests, it’s used to calculate the sum of a set of objects. It does this by using inject, a function that uses a block to reduce a set of objects to a single value. In the case of sum, it does this by using the addition operator. This makes perfect sense when we’re talking about numbers: 1 + 1 = 2 is fundamental arithmetic. And it’s also easy to see how it can be used to concatenate strings together:
['foo', 'bar', 'baz'].sum # => 'foobarbaz'
But how does Ruby know how to add two instances of our ShippingManifest class? Easy. We tell it how.

“That’s only part of who I am. I’m actually quite complex.”

“Everything is an object” is one of Ruby’s core mantras. The implication of this is that (nearly) every operator is actually a method call on an instance of an object—which grants us the ability to define our own implementation for that operator. It means we can do this:
class ShippingManifest < ActiveResource::Base
  # Returns a new instance of ShippingManifest containing the
  # sum of both `mass` and `package_count`
  def +(other)
    self.dup.tap do |neu|
      neu.mass          = @mass + other.mass
      neu.package_count = @package_count + other.package_count
    end
  end
end
By adding a few simple lines of code, we’ve added functionality that has made the potential ShippingManifest much more usable by the wider Ruby library.

“And let me remind you again, folks, that you’re listening to Truth or—Aaaugh!”

Implementing custom behavior for the + operator only scratches the surface of what’s possible through duck typing. There are other operators that have custom behavior implemented: &
, *, -, <<. Even == can have custom behavior. Need to sort a set of records? Implement the comparison operator (<=>) in your classes and you’ll be able to take full advantage of the sorting methods provided in Enumerable. As always, some example code for this post is available on our GitHub account—feel free to fork it and experiment! For starters, try implementing behaviour for - and <=>, then experiment with the methods in Enumerable. If you have queries about any other aspect of Ruby, feel free to ask in the comments!

Frequently Asked Questions about Duck Typing in Ruby

What is the concept of Duck Typing in Ruby?

Duck Typing is a programming concept that is heavily used in Ruby. It is a style of dynamic typing where the methods and properties of an object determine the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface. The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows: “If it walks like a duck and it quacks like a duck, then it must be a duck.”

How does Duck Typing differ from Static Typing?

Duck Typing is a form of dynamic typing, which is different from static typing. In static typing, the type of a variable is checked at compile-time, whereas in dynamic typing, like Duck Typing, the type is checked at runtime. This means that in Duck Typing, you’re more concerned with what the object does, rather than what it is.

Why is Duck Typing preferred in Ruby?

Duck Typing is preferred in Ruby because it allows for more flexibility and less code. It allows you to call methods on objects without worrying about their class, as long as the method exists. This can make your code more abstract and flexible, and can also lead to less code, as you don’t need to check the type of the object before calling the method.

Can you provide an example of Duck Typing in Ruby?

Sure, here’s a simple example of Duck Typing in Ruby:

class Duck
def quack
'Quack!'
end
end

class Dog
def quack
'Woof!'
end
end

def make_it_quack(animal)
animal.quack
end

duck = Duck.new
dog = Dog.new

puts make_it_quack(duck) # Outputs: Quack!
puts make_it_quack(dog) # Outputs: Woof!

In this example, the make_it_quack method doesn’t care about the type of the object passed to it. It only cares that the object responds to the quack method.

What are the potential downsides of Duck Typing?

While Duck Typing provides flexibility, it can also lead to unexpected errors at runtime if an object doesn’t respond to a method that’s being called on it. This can make debugging more difficult, as these errors won’t be caught until the code is run.

How does Duck Typing relate to the principle of “strong typing”?

Duck Typing is a form of strong typing. In strong typing, an operation against an object is checked for compatibility with the type of the object, which is exactly what happens in Duck Typing. The difference is that this check happens at runtime, rather than at compile-time.

Is Duck Typing unique to Ruby?

No, Duck Typing is not unique to Ruby. It’s a concept that’s used in many dynamically typed languages, including Python and JavaScript. However, it’s particularly prevalent in Ruby due to the language’s focus on flexibility and expressiveness.

How does Duck Typing affect performance in Ruby?

Duck Typing can potentially affect performance, as type checking is done at runtime. However, in practice, the impact on performance is usually negligible, and the benefits of increased flexibility and less code often outweigh any potential performance drawbacks.

Can Duck Typing be used in conjunction with other typing methods in Ruby?

Yes, Duck Typing can be used in conjunction with other typing methods in Ruby. For example, you can use Duck Typing in combination with static typing if you’re using a tool like Sorbet, which adds static typing to Ruby.

How can I ensure that an object responds to a method in Duck Typing?

In Ruby, you can use the respond_to? method to check if an object responds to a particular method. This can help you avoid runtime errors when using Duck Typing. Here’s an example:

if object.respond_to?(:quack)
object.quack
end

In this example, the quack method will only be called on the object if the object responds to that method.

Dan CheailDan Cheail
View Author

Dan is a Melbourne-based Ruby and Web developer. He has contributed to Rails and other open-source projects, and is passionate about Ruby and the opportunities it provides.

ruby tricks
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week