| Subcribe via RSS

type(Duck)’ing: On Duck vs. Static Typing

May 30th, 2007 Posted in Programming, Python

Last night before bed - I sat down and read two articles that seemed to have grown some legs - the first being "Duck Typing Done Right" and the followup, "Answers to Duck Typing Done Right" (see the reddit comment thread). Ignoring the XML/DTD/Semantic web "solution" (see: Eby: XML is not the answer) offered for "doing it right" I got spun up on what "duck typing" really is, and what it really means for people (me) as (a) programmer(s). Invariably I didn't sleep so well.

What is duck typing? I hope most people reading this know what it is - but here is what I think it is, and why I think that a lot of people miss the point. Admittedly, this is slightly rant-ish.

To quote wikipedia on Duck Typing:

In computer science, duck typing is a principle of dynamic typing in which an object's interface and attributes determine valid semantics, rather than having the language enforce rules regarding inheritance or require type casting.This allows an object to be interchangeable with any other object so long as they both implement sufficiently compatible interfaces, regardless of whether the objects have a related inheritance hierarchy. Duck typing is a feature of programming languages such as Smalltalk, Python, Ruby, JavaScript, and ColdFusion.

Duck typing is the notion that if I create an object, and I give it the attributes of a Duck - let's say, a bill, a quack, a scent and feathers - then what I am giving you when I pass this object to you is a Duck (or at least supports the Duck interface(s)). This is also known as a "gentleman's agreement" - if I tell you I am giving you something that quacks, has feathers and a bill, then you can trust I'm giving you a damned Duck (or something equally compatible).

And there's the rub. People lie. Adults lie. Java/C/static typing people would lead you to believe that this type of flexibility is "bad" and that the "social contract" of typing should be enforced by an independent third party w.r.t: the Compiler/Interpreter.

My point is if it walks like a duck, smells like a duck, looks like a duck - but it's really a dog with no Duck interface, someone needs to acknowledge reciept of a PinkSlip(object) because they broke the contract - they knew that a duck was expected and they didn't have the politeness to wrap up their dog in a duck! who cares if it's a Dog in Duck's clothing if it can Dog.quack() when it needs to?

(note, I like this definition - "Duck typing is the system wherein you wish to pass something that requires a Duck object, and you only have a Dog, you have the decency to wrap it in a Duck suit.")

This is the beauty of Duck/Dynamic typing - I don't care if an "int" is really an integer as long as it acts like one. If you can fulfill the contract (the interface) that the method/function/etc you are about to call requires, i.e: the Dog() with Duck() interface, then by god, everything should be fine!

I see this kinda like a conversation:

Me: I want a Duck man.

You: Well, I have something that's got wings, a bill and that quacks

Me: I don't know... Does it have feathers?

You: Why yes, yes it does (def feathers(self): pass)

Me: Is it really a duck?

You: It's a Dog(Duck)

Me: Close enough for government work.

Note that his just so happens to align with my very libertarian world-view: What you do in your own free time is cool, as long as when you come over to my place you're civil according to my rules in my house.

The other side of the coin is the criticism that due to the lack of the interpreter nanny-state to protect against evil lying people from slinging things around, you can not "find bugs" until runtime. (by bugs, they mean syntax, type and other runtime errors).

The irony of this is that the same individual that is stating how Java/C++ is better in this regard is saying it while they're running xUnit Tests prior to a full build. And that bring me to my next point: A sufficiently large enough code base will enforce the contractual obligations of the objects labeled Duck() through unit tests. Testing is always the contractual enforcer of Code. If you say X does Y and it doesn't really do Y - then all the type checking-compiler-time magic in the world wouldn't save you.

I come from a QA background. I love testing. With python - I don't view a lack of a compile as a problem - I view unit testing and a dose of pylint/pychecker as the compiler. Not to mention - I can prove hundred of more assumptions in a unit test framework than I can in a compiler: I can't walk AST in my sleep, it's much easier for me to make a good, solid suite of unit-level tests (or hell - do it by hand!) to prove that my function/object/etc works/impersonates/runs as desired.

Not even compiler-jockies would suggest shipping something without comprehensive tests! So far, the only person I know who would suggest it also talks to cheese sandwiches.

In the age of the Agile Methodology - i.e. "Writing a Test before Code" - why do you need need someone/something else to contractually obligate you to a contract of type()? Why can't you - as a consenting adult, working with other consenting adults be responsible enough to agree to the contract and at least test it out.

Duck/Latent Typing buys you a lot of things - eval(), more interesting (better) polymorphism, among others, and of course static typing has it's benefits! In fact, I like static interfaces and types - see my previous horn tooting about Abstract Base Classes. I like/want the ability to force the contract/type when it's really important.

What I take umbrage too - and of course, this is outside of the scope of the original article(s) I linked to is the idea that a third party (the interpreter, a new language, my mom/wife/government) needs to tell me how to infer types, manage inputs, or build interfaces.

The best type of implementation is the light one. If people want more rules to enforce the contract - then give it to them (ergo: ABCs in Py3k). Otherwise, leave those of us willing to sit down and learn to write comprehensive tests to prove the contract is fulfilled alone. Duck typing is not a lesser creature to your fascist compiler-state. It's just different, and puts more responsibility on both the user and creator of an object and an application.

(maybe we should call it "contract typing", and if you really get hung up, get over it with isinstance().)

Edit to add for the Haskell people: Haskell is on the list of learning, but learning it is of a lesser impact on the paycheck than Java/Python hackery. But, people should also look into it (if you really like functional programming).

Hello, Reddit.

Also see my followup - Schrödinger’s Type (is a namespace a box?)

For more delicious discussion/links, check these out (not everyone agrees with me!):

Static Typing

14 Responses to “type(Duck)’ing: On Duck vs. Static Typing”

  1. gwenhwyfaer Says:

    @King: isn’t that rather like saying “I hereby declare that all blog posts talking about British universities should be ignored unless the poster at least mentions that he’s attended at least one of the following universities: Oxford, Cambridge, Durham, Kent or York”…?


  2. Henry Story Says:

    Thanks for mentioning my article “Duck Typing done right”.

    The original point of that article was, as you repeat above, that duck typing is implemented in many languages as just simple string comparison. So your
    dog.quack() example, is said to implement the Duck interface just because both contain the “quack” methods. The problem is that someone else can just as well have created a “quack” method on the dog which does something completely different (perhaps a QUick Answer to A Cat: Kill). The fact that two strings are the same does not indicate they mean the same thing. For this you would need namespaced methods at the least. Then you could distinguish between animal.sound.quack() and animal.action.quack() perhaps. This would give your program a lot more generality already: it would mesh better with wider libraries, and depend less on subtle contextual knowledge of the code base. You can then see how going with full fledged URIs gives you the largest scalability for exchanging and meshing information.


  3. jesse Says:

    @Henry: Obviously if you had Dog(Duck) and both had Quack() there would be no string comparison - it’s resolved simply by the fact that Dog inherited Duck’s methods, and then over wrote the original Quack.

    If Dog’s Quack() method does not in fact, Quack() then it is not a valid quack. Dog() by it’s very nature has violated the contract for anyone who needs a Duck() but gets a Dog()

    For example, in python - you have __getitem__(): If I created a class/object (class myob(object)) and over wrote __getitem__() to say, parse an XML stream and make the bios beep instead of simply returning a value from the local namespace - I am in violation of a very simple and basic contract within the language.

    Name spaced methods are exactly that within Python. pkg.module.file.method() is a clear enough name space. Proper python module structure means that given your example, we should have:

    animals.dog.sounds.quack()

    animals.dog.actions.quack()

    And so on. Which most python programs are smart enough to do - that’s the glorious nature of namespaces. If you have 14 Quack methods, they should each be contained within the proper namespace.

    Man I have to get a threaded comment system


  4. Haskell Says:

    I hereby declare


  5. King Says:

    I hereby declare that all blog posts talking about static typing should be ignored unless the poster at least mentions that he’s tried of at least one of the following languages: Haskell, ML, O’Caml, Clean, or Mercury.


  6. jesse Says:

    @HaskellPeople: Haskell is on the list - I tried to get started but I got distracted by other things involving paychecks.


  7. Jonathan Allen Says:

    The problem I see with duck typing is that it seems to be really, really easy to break compatibility.

    Lets say I add a Swim method to my Duck class. Then I change the move method to call Swim instead of Fly under certain circumstances.

    If I was using an IDuck interface, then I would get a compiler error on the Dog(Duck) class and know I needed to fix it.

    If I am just using Duck, I wouldn’t know there was a problem with Dog(Duck) until either the unit tests catch it or, more likely, it crashes up at runtime.


  8. Jake Says:

    I’ve been reading all of these Static/Duck arguments, and I’ve worked with both Rails and C++. I don’t mind working with either systems, but when I stop and think about duck typing it just seems imprecise. I don’t like relying on the name I happen to give a series of methods to define what it is.

    Especially when working w/ lots of people it seems like a good idea to be able to define interfaces strictly by setting up a Duck abstract class and having everybody that supports the duck interface inheriting from it rather than relying on people calling things the same thing. It seems like we’re taking a step back to have to manually write tests to check things that used to be done for us automatically.


  9. Joe Says:


  10. Henry Story Says:

    “If Dog’s Quack() method does not in fact, Quack() then it is not a valid quack. Dog() by it’s very nature has violated the contract for anyone who needs a Duck() but gets a Dog()”

    Well not really. As I see in most of these languages nobody uses full namespaced method comparison to identify the method. If they did then you would be right, for the reasons I pointed to in my orignal article: your namespaced method is close to being a URI for it.

    But in fact these languages don’t do this. they just look to see that there is a method that is named “Quack”. If there is it gets called as if it was clear that was it means was the sound. But why could a dog not have a “quack” method that meant to kill a cat? There would be no interface broken here. Just a clash of words, and we have those a lot in the english language. Things such as “bank” (the place you deposit your money at) and “bank” of a river… We disambiguate english because we take context into account, just as a programmer makes sure that when he gives objects to a method that will duck type on “quack” he makes sure never to give the method objects where “quack” means something else. Notice how this has trouble scaling though.

    Anyway, I would be glad to be shown to be wrong. I just looked up a book on Ruby, and that confirmed my thinking. Do you have a pointer to a piece of code that could resolve the issue?


  11. Paul Boddie Says:

    “The problem is that someone else can just as well have created a “quack” method on the dog which does something completely different (perhaps a QUick Answer to A Cat: Kill).”

    Yes, people might define perverse methods which have the same names as normal ones, and there is a possibility of method name “collisions”, but this kind of problem is addressed in many other fields within computing (as well as being a general disambiguation problem), and the solution doesn’t have to involve rigid interface hierarchies.


  12. nes Says:

    :> Ideally, IMO, two messages with the same name should have
    :> the same meaning but possibly different implementations.
    :> Of course, “meaning” is somewhat relative, but the notion
    :> that two messages with the same name should have the same
    :> “meaning” is very useful.

    :Like clothes.launder() vs money.launder(), or shape.draw() vs blood.draw(),
    :or matrix.norm() vs hi.norm() ? I’m afraid English thrives on puns,
    :and the same word routinely means radically different things across
    :application areas. Therefore, to insist that a word have “one true meaning”
    :in a programming language is insisting that the language cater to one true
    :application domain.

    http://groups.google.com/group/comp.lang.python/browse_thread/thread/c12d4b19d0f42f05/3acb79797dd3d3fd

    Most people are pretty good at guessing the semantic of words depending on the context used. Having to define the precise semantics of every word each time it gets used sounds pretty verbose to me. Of course this might potentially create some bug (and is source material for jokes by comedians). BTW, Java interfaces don’t even allow to implement methods of different domains with the same name for a class, so Java interfaces don’t even solve the problem. I wonder how Haskell handles that.


  13. jessenoller.com - Schrödinger’s Type (is a namespace a box?) Says:

    [...] “type(Duck)’ing: On Duck vs. Static Typing” post received some minor attention, but as with all things of an obsessive nature, I wanted to [...]


  14. jessenoller.com - Duck typing + Wikipedia. Says:

    [...] both - and after your done laughing, take a look at my previous articles (rants?) on the subject - typeducking-on-duck-vs-static-typing and [...]


Leave a Reply