Mark Thomas

Deceptively random thoughts

Scala: Type safe duck typing

with 5 comments

If it walks like a duck and quacks like a duck, I would call it a duck.

Duck typing uses the set of methods and properties of an object, rather than its position in a type hierarchy to decide what you can do with it.

Scala’s structural typing feature provides something close to duck typing in a type safe way. A structural type is close to a .NET anonymous type; a type with a set of methods and properties but with no name. An example in Scala based on one of Wikipedia’s examples of duck typing:

class Duck {
  def quack = println("Quaaaaaack !")
  def feathers = println("The duck has white and gray feathers.")
}
 
class Person {
  def quack = println("The person imitates a duck.")
  def feathers = println("The person takes a feather from the ground and shows it.")
}
 
def inTheForest(duck: { def quack; def feathers }) = {
  duck.quack
  duck.feathers
}

The inTheForest function declares that it will accept any object that has a quack and feathers method, both of which take no parameters and return Unit (like void in Java/C#). When executed, the code works as expected:

scala> inTheForest(new Person)
The person imitates a duck.
The person takes a feather from the ground and shows it.

scala> inTheForest(new Duck)
Quaaaaaack !
The duck has white and gray feathers.

To demonstrate the type safety, lets try using a string:

scala> inTheForest("Duck")
:6: error: type mismatch;
 found   : java.lang.String("Duck")
 required: AnyRef{def quack: Unit; def feathers: Unit}
       inTheForest("Duck")
                   ^

When is this useful? Mostly in situations where you are consuming classes that follow common conventions but have no shared interface, in this case you can define the parts you are interested in by using the structural type as an implicit interface.

Finally, if you find that you are using a structural type a lot, it can define it in one place:

object UsefulTypes {
  type Duck = { def quack; def feathers }
}

inTheForest can then be declared as:

import UsefulTypes.Duck
 
def inTheForest(duck: Duck) = {
  duck.quack
  duck.feathers
}

Written by Mark Thomas

August 27th, 2008 at 6:40 pm