Crowley Code! 
 (Take 12)

Turkey typing 2009/09/14

Mike Malone’s thrilling response to “The case against duck typing” [1] left me feeling a bit like I didn’t fully say what I set out to.  I do not intend to systematically pick holes in Mike’s arguments as that will be much more fun in person with beers.  In this installment I’m going to write out some code in an imaginary language called Copperhead to illustrate what I called declared typing before and decided to call turkey typing today.

A very simple example of balking at anything non-numeric.

def what_is_rent_in_san_francisco(float salary):
    return 47 * salary

In such simple cases, we can cause plain Python to Do The Right Thing by forcing the argument to be a float and catching ValueError, thus suppressing strings’ desire to quack.

def what_is_rent_in_san_francisco(salary):
    return 47 * float(salary)

It isn’t always so easy.  Duck typing raises exceptions when something fails to quack rather than when something is passed to a method in which it will fail to quack.  The distinction can be important.

def something_dangerous_then_a_loop(things):
    poke_a_tiger_with_a_stick()
    for thing in things:
        thing.stuff()

If you’re fortunate enough to survive the tiger-poke only to be greeted by a TypeError when things is not iterable, you’re going to be pretty bummed.  A duck typing language could push such call-time errors to the beginning of the method but I bet there’s a large amount of code in the wild that relies on this bugquirk.  A programmer could check types at the top of the method, implement database-like transactions or reorder her code but none of those options are particularly elegant.

def something_dangerous_then_a_loop(iterable things):
    poke_a_tiger_with_a_stick()
    for thing in things:
        thing.stuff()

Progress!  We won’t bother with the tiger unless we know the loop will be able to execute but this is still relying on duck typing for the stuff method of each thing.  Perhaps this is okay but perhaps we want to get even more specific.  I like the syntax of the C++ STL for this, so I’ll steal it.

def something_dangerous_then_a_loop(iterable<Thing> things):
    poke_a_tiger_with_a_stick()
    for thing in things:
        thing.stuff()

Now we know the iterable contains only Things and can safely call stuff on each one.  If Doodads and Widgets also implement the stuff method, one could block out Widgets by specifying the argument type as iterable<[Thing, Doodad]> (or just [Thing, Doodad] for a scalar argument).

It is not my intention to get caught up in syntax.  My hope is that I can demonstrate how useful turkey typing can be.  It isn’t a regression to static typing nor is it mutually exclusive from duck typing: note that I use the type iterable above which is not a type in any Python I’ve ever used.  iterable could itself be a duck type but, importantly, one checked at the top of the method and without nasty isinstance or hasattr smells.

Turkey typing is still dynamic typing, meaning values have types but symbols do not.  The type checking that happens at method call time is not an optimization but rather a shortcut.  Within method bodies, ducks still have to quack.

My motivation always comes back to API design (the real definition of API [2], not what Web 2.0 means by API).  Automatically generated documentation will be better if it’s generated from method signatures instead of Javadoc comments.  When documentation inevitably doesn’t exist or fails to measure up, the code tells you exactly what’s expected.  And when you barrel into code headfirst, the compiler can tell you what type it wants instead of just which method yor’re not providing.

  1. http://rcrowley.org/2009/09/12/the-case-against-duck-typing
  2. http://en.wikipedia.org/wiki/Application_programming_interface

Richard Crowley?  Kentuckian engineer who cooks and eats in between bicycling and beering.

I blog mostly about programming and databases.  Browse by month or tag.

To blame for...


© 2009 Richard Crowley.  Managed by Bashpress.