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

by jesse

Last night before bed — I sat down and read two arti­cles that seemed to have grown some legs — the first being “Duck Typ­ing Done Right” and the fol­lowup, “Answers to Duck Typ­ing Done Right” (see the red­dit com­ment thread). Ignor­ing the XML/DTD/Semantic web “solu­tion” (see: Eby: XML is not the answer) offered for “doing it right” I got spun up on what “duck typ­ing” really is, and what it really means for peo­ple (me) as (a) programmer(s). Invari­ably I didn’t sleep so well.

What is duck typ­ing? I hope most peo­ple read­ing this know what it is — but here is what I think it is, and why I think that a lot of peo­ple miss the point. Admit­tedly, this is slightly rant-ish.

To quote wikipedia on Duck Typ­ing:

In com­puter sci­ence, duck typ­ing is a prin­ci­ple of dynamic typ­ing in which an object’s inter­face and attrib­utes deter­mine valid seman­tics, rather than hav­ing the lan­guage enforce rules regard­ing inher­i­tance or require type casting.This allows an object to be inter­change­able with any other object so long as they both imple­ment suf­fi­ciently com­pat­i­ble inter­faces, regard­less of whether the objects have a related inher­i­tance hier­ar­chy. Duck typ­ing is a fea­ture of pro­gram­ming lan­guages such as Smalltalk, Python, Ruby, JavaScript, and ColdFusion.

Duck typ­ing is the notion that if I cre­ate an object, and I give it the attrib­utes of a Duck — let’s say, a bill, a quack, a scent and feath­ers — then what I am giv­ing you when I pass this object to you is a Duck (or at least sup­ports the Duck interface(s)). This is also known as a “gentleman’s agree­ment” — if I tell you I am giv­ing you some­thing that quacks, has feath­ers and a bill, then you can trust I’m giv­ing you a damned Duck (or some­thing equally com­pat­i­ble).

And there’s the rub. Peo­ple lie. Adults lie. Java/C/static typ­ing peo­ple would lead you to believe that this type of flex­i­bil­ity is “bad” and that the “social con­tract” of typ­ing should be enforced by an inde­pen­dent 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 inter­face, some­one needs to acknowl­edge reciept of a PinkSlip(object) because they broke the con­tract — they knew that a duck was expected and they didn’t have the polite­ness to wrap up their dog in a duck! who cares if it’s a Dog in Duck’s cloth­ing if it can Dog.quack() when it needs to?

(note, I like this def­i­n­i­tion — “Duck typ­ing is the sys­tem wherein you wish to pass some­thing 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 typ­ing — I don’t care if an “int” is really an inte­ger as long as it acts like one. If you can ful­fill the con­tract (the inter­face) that the method/function/etc you are about to call requires, i.e: the Dog() with Duck() inter­face, then by god, every­thing should be fine!

I see this kinda like a conversation:

Me: I want a Duck man.

You: Well, I have some­thing 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 gov­ern­ment work.

Note that his just so hap­pens to align with my very lib­er­tar­ian 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 accord­ing to my rules in my house.

The other side of the coin is the crit­i­cism that due to the lack of the inter­preter nanny-state to pro­tect against evil lying peo­ple from sling­ing things around, you can not “find bugs” until run­time. (by bugs, they mean syn­tax, type and other run­time errors).

The irony of this is that the same indi­vid­ual that is stat­ing how Java/C++ is bet­ter in this regard is say­ing it while they’re run­ning xUnit Tests prior to a full build. And that bring me to my next point: A suf­fi­ciently large enough code base will enforce the con­trac­tual oblig­a­tions of the objects labeled Duck() through unit tests. Test­ing is always the con­trac­tual 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 back­ground. I love test­ing. With python — I don’t view a lack of a com­pile as a prob­lem — I view unit test­ing and a dose of pylint/pychecker as the com­piler. Not to men­tion — I can prove hun­dred of more assump­tions in a unit test frame­work than I can in a com­piler: I can’t walk AST in my sleep, it’s much eas­ier 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 sug­gest ship­ping some­thing with­out com­pre­hen­sive tests! So far, the only per­son I know who would sug­gest it also talks to cheese sandwiches.

In the age of the Agile Method­ol­ogy — i.e. “Writ­ing a Test before Code” — why do you need need someone/something else to con­trac­tu­ally oblig­ate you to a con­tract of type()? Why can’t you — as a con­sent­ing adult, work­ing with other con­sent­ing adults be respon­si­ble enough to agree to the con­tract and at least test it out.

Duck/Latent Typ­ing buys you a lot of things — eval(), more inter­est­ing (bet­ter) poly­mor­phism, among oth­ers, and of course sta­tic typ­ing has it’s ben­e­fits! In fact, I like sta­tic inter­faces and types — see my pre­vi­ous horn toot­ing about Abstract Base Classes. I like/want the abil­ity to force the contract/type when it’s really impor­tant.

What I take umbrage too — and of course, this is out­side of the scope of the orig­i­nal article(s) I linked to is the idea that a third party (the inter­preter, a new lan­guage, my mom/wife/government) needs to tell me how to infer types, man­age inputs, or build inter­faces.

The best type of imple­men­ta­tion is the light one. If peo­ple want more rules to enforce the con­tract — then give it to them (ergo: ABCs in Py3k). Oth­er­wise, leave those of us will­ing to sit down and learn to write com­pre­hen­sive tests to prove the con­tract is ful­filled alone. Duck typ­ing is not a lesser crea­ture to your fas­cist compiler-state. It’s just dif­fer­ent, and puts more respon­si­bil­ity on both the user and cre­ator of an object and an application.

(maybe we should call it “con­tract typ­ing”, and if you really get hung up, get over it with isinstance().)

Edit to add for the Haskell peo­ple: Haskell is on the list of learn­ing, but learn­ing it is of a lesser impact on the pay­check than Java/Python hack­ery. But, peo­ple should also look into it (if you really like func­tional pro­gram­ming).

Hello, Red­dit.

Also see my fol­lowup — Schrödinger’s Type (is a name­space a box?)

For more deli­cious discussion/links, check these out (not every­one agrees with me!):

Static Typing