Ruby – Duck Typing

Duck Typing is a bit like an alternative concept to the inheritance concept. It basically let’s you create a standalone method, that resides outside a class. Another way to look at it is that duck typing is a bit like creating your very own “static method”.

Before we start explaining what “duck typing” is, let’s first take a look at an example of inheritance in action:

class Animal 
  def quack
    puts "unknown animal that makes a quack noise"
  end

  def feathers
    puts "this animal has something to do with feathers"
  end
  
  # Here we have taken the slightly unusual step of passing the object into the method. 
  # a better approach would be to not pass anything in, and just use the "self" keyword instead. 
  def in_the_forest(an_object)
    an_object.quack
    an_object.feathers
  end 
  
end


class Duck   < Animal
  def quack
    puts "Quaaaaaack!"
  end

  def feathers
    puts "The duck has white and gray feathers."
  end  

end
 

class Person   < Animal
  def quack
    puts "The person imitates a duck."
  end
  
  def feathers
    puts "The person takes a feather from the ground and shows it."
  end
end
 

 

donald = Duck.new
john = Person.new
mystery_animal = Animal.new

# If we used the "self" keyword earlier on then we wouldn't have needed to pass in the object itself in again. 
donald.in_the_forest(donald)
john.in_the_forest(john)
mystery_animal.in_the_forest(mystery_animal)

Here we have taken a slightly odd approach in the way we have defined the in_the_forest method. This will make better sense later on. Also notice that both the quack and feathers method has been over-ridden, and only in_the_forest method hasn't been overridden in the child classes.

This outputs:

PS C:\Temp\irb> ruby .\inhertance.rb
Quaaaaaack!
The duck has white and gray feathers.
The person imitates a duck.
The person takes a feather from the ground and shows it.
unknown animal that makes a quack noise
this animal has something to do with feathers
PS C:\Temp\irb>

Now let's say that we actually want to instantiate the Animal class. Also the quack and feathers classes will always be redefined in all of Animals child class, then we can in theory refactor the code to:

class Animal 
  
  def in_the_forest(an_object)
    an_object.quack
    an_object.feathers
  end 
  
end


class Duck   < Animal
  def quack
    puts "Quaaaaaack!"
  end

  def feathers
    puts "The duck has white and gray feathers."
  end  

end
 

class Person   < Animal
  def quack
    puts "The person imitates a duck."
  end
  
  def feathers
    puts "The person takes a feather from the ground and shows it."
  end
end
 


donald = Duck.new
john = Person.new

donald.in_the_forest(donald)
john.in_the_forest(john)

This outputs:

PS C:\Temp\irb> ruby .\inhertancet.rb
Quaaaaaack!
The duck has white and gray feathers.
The person imitates a duck.
The person takes a feather from the ground and shows it.
PS C:\Temp\irb>

At this poinnt, the (parent) Animal class only contains one method. Having a parent that only contains one method, can be thaught of as a bit overkill. It could be argued that it would be better to get rid of the Animal class altogether and have the in_the_forest method as a standalone method. This is possible like this:

def in_the_forest(an_object)
  an_object.quack
  an_object.feathers
end 


class Duck   
  def quack
    puts "Quaaaaaack!"
  end

  def feathers
    puts "The duck has white and gray feathers."
  end  

end
 

class Person 
  def quack
    puts "The person imitates a duck."
  end
  
  def feathers
    puts "The person takes a feather from the ground and shows it."
  end
end
 

donald = Duck.new
john = Person.new

in_the_forest(donald)
in_the_forest(john)

This outputs:

PS C:\Temp\irb> ruby .\inhertancet.rb
Quaaaaaack!
The duck has white and gray feathers.
The person imitates a duck.
The person takes a feather from the ground and shows it.
PS C:\Temp\irb>

Here, you can use the in_the_forest method for any objects whose corresponding class contains the quack and feathers method.

If we head originally wrote the in_the_forest method using the "self" syntax then this wouldn't have been possible and the in_the_forest method would have needed to be rewritten to the way it is written, i.e. requiring an object as in input parameter.

As mentioned there are few cases where you might need to use ducktyping.

The key benefit of duck typing is that it lets you avoid writing unnecessary classes just to hold generic methods.