Duck Typing Is More Than Quackery

code 23 comments suggest edit

Eric Lippert writes one of my all time favorite tech blogs. Sadly, the purple font he was famous for is no longer, but the technical depth is still there.

In a recent post, he asks the question, “What is Duck Typing?” His post provides a thoughtful critique and deconstruction of the Wikipedia entry on the subject. Seriously, go read it, but please come back here afterwards!

For those of you too lazy to read it, I’ll try and summarize crudely. He starts off with his definitions of “typing”:

A compile-time type system provides three things: first, rules for defining types, like “array of pointers to integer”. Second, rules for logically deducing what type is associated with every expression, variable, method, property, and so on, in a program. And third, rules for determining what programs are legal or illegal based on the type of each entity. These types are used by the compiler to determine the legality of the program.

A run-time type system provides three similar things: first, again, rules for defining types. Second, every object and storage location in the system is associated with a type. And third, rules for what sorts of objects can be stored in what sorts of storage locations. These types are used by the runtime to determine how the program executes, including perhaps halting it in the event of a violation of the rules.

He continues with a description of structural typing that sounds like what he always thought “duck typing” referred to, but notes that his idea differs from the Wikipedia definition. As far as he can tell, the Wikipedia definition sounds like it’s just describing Late Binding.

But this is not even typing in the first place! We already have a name for this; this is late binding. “Binding” is the association of a particular method, property, variable, and so on, with a particular name2 in a particular context; if done by the compiler then it is “early binding”, and if it is done at runtime then it is “late binding”.3 Why would we even need to invent this misleadingly-named idea of “duck typing” in the first place??? If you mean “late binding” then just say “late binding”!

I agree that the Wikipedia definition is a bit unclear, but I think there’s more to it than simple late binding. Also, I think some of the confusion lies in the fact that duck typing isn’t so much a type system as it is a fuzzy approach to treating objects as if they are certain types (or close enough) based on their behavior rather than their declared type. This is a subtle distinction to late binding.

To back this up, I looked at the original Google Group post where the Alex Martelli first described this concept.

In other words, don’t check whether it IS-a duck: check whether it QUACKS-like-a duck, WALKS-like-a duck, etc, etc, depending on exactly what subset of duck-like behaviour you need to play your language-games with.

This was a response to a question that asked the question (I’m paraphrasing), how do you handle method overloading with a single parameter in a dynamic language? Specifically, the question was in reference to the Python language.

To illustrate, in a static typed language like C#, you might have the following three methods of a class (forgive me if the example seems contrived. I lack imagination.):


public class PetOwner {
  public void TakeCareOf(Duck duck) {...}
  public void TakeCareOf(Robot robot) {...}
  public void TakeCareOf(Car car) {...}
}

In C#, the method that gets called is resolved at compile time depending on the type of the argument passed to it.

var petOwner = new PetOwner();
petOwner.TakeCareOf(new Duck()); // calls first method.
petOwner.TakeCareOf(new Robot()); // calls second method.
petOwner.TakeCareOf(new Car()); // calls third method.

But in a dynamic language, such as Python, you can’t have three methods with the same name each with a single argument. Without a type declared for the method argument, there is no way to distinguish between the methods. Instead, you’d need a single method and do something else.

One approach is you could switch based on the runtime type of the argument passed in, but Alex points out that would be inappropriate in Python. I assume because it conflicts with Python’s dynamic nature. Keep in mind that I’m not a Python programmer so I’m basing this on my best attempt to interpret Alex’s words:

In other words, don’t check whether it IS-a duck: check whether it QUACKS-like-a duck, WALKS-like-a duck, etc, etc, depending on exactly what subset of duck-like behaviour you need to play your language-games with.

As I said before, I don’t know a lick of Python, so I’ll pseuducode what this might look like.

class PetOwner:
    def take_care_of(arg):
        if behaves_like_duck(arg):
            #Pout lips and quack quack
        elif behaves_like_robot(arg):
            #Domo arigato Mr. Roboto
        elif behaves_like_car(arg):
            #Vroom vroom vroom farfegnugen

So rather than check if the arg IS A duck, you check if it behaves like a duck. The question is, how do you do that?

Alex notes this could be tricky.

On the other hand, this can be a considerable amount of work, depending on how you go about it (actually, it need not be that bad if you “just go ahead and try”, of course catching the likely exceptions if the try does not succeed; but still, greater than 0).

One proposed approach is to simply treat it like a duck, and if it fails, start treating it like a fish. If that fails, try treating it like a dog.

I’d guess that code would look something like:

class PetOwner:
  def take_care_of(arg):
    try:
      arg.walk()
      arg.quack()
    except:
      try:
        arg.sense_danger_will_robinson()
        arg.dance_in_staccato_manner()
      except:
        arg.drive()
        arg.drift()

Note that this is not exactly the same as late binding as Eric proposes. Late binding is involved, but that’s not the full picture. It’s late binding combined with the branching based on the set of methods and properties that make up “duck typing.”

What’s interesting is that this was not the only possible solution that Alex proposed. In fact, he concludes it’s not the optimal approach.

Besides, “explicit is better than implicit”, goes one of Python’s mantras. Just let the client-code explicitly TELL you which kind of argument they are passing you (and doing so through a named argument is simple and readable), and your work drops to zero, while removing no useful functionality whatever from the client.

He goes on to state that this implicit duck typing approach to method overloading seems to have dubious benefit.

The “royal-road” alternative route to overloading would, I think, be the use of suitable named-arguments. A rockier road, perhaps preferable in some cases, but more work for dubious benefit, would be the try/except approach to see if an argument supplies the functionalities you require.

The Python approach would be to pass in a discriminator. Even so, the object passed in would have to fulfill the set of requirements for the selected branch of code indicated by the discriminator. With the discriminator, it does feel more like we’re just talking about late binding, but applied to a set of methods and properties, not just each one individually as you might do with late binding.

One observation I’ve heard is that “duck typing” sounds kind of like “duct taping.” Not sure if there’s anything to that, but if you forgive a bit of a stretch, I think there it may be an apt analogy.

On the Apollo 13 mission, the crew was faced with a situation where carbon dioxide levels were rising to dangerous levels in the Lunar Module. They had plenty of filters, but their square filters would not fit in the round barrels that housed the filters. In other words, their square filters were the wrong type (whether dynamic or static). Their solution was to use duct tape to cobble something together that would work. It wasn’t the solution intended by the original design, but as long as the final contraption acts like an air filter (duck typing), they would survive. And they did. Like I said, the analogy is a bit of as stretch, but I think it embodies the duck typing approach.

Perhaps a better term is typing by usage. With explicit typing, you explicitly declare an object to be one type or another (whether at compile time or run time). With typing by usage, if it just happens to meet the needs of the consumer, then hey! It’s a duck!

For static typed languages, I really like the idea of structural typing. It provides a nice combination of type safety and flexibility. Mark Rendle, in the comments to Eric’s blog post provides this observation:

Structural Typing may be thought of as a kind of compiler-enforced subset of Duck Typing.

In other words, it’s duck typing for static typed languages.

Also in the comments to Eric’s post, someone linked to my blog post about duck typing. At the time I wrote that, “structural typing” wasn’t in my vocabulary. If it had been, I could have been more precise in my post. For static languages, I find structural typing to be very compelling.

What do you think? Did I nail it? Or did I drop the ball and get something wrong or misrepresent an idea? Let me know in the comments.

UPDATE: Sam Livingston-Gray, also known as @geeksam notes another key difference between late binding that I completely missed:

@haacked method_missing illustrates the disconnect between binding and typing: an obj can choose how and whether to respond to a message

Recall that Eric defines “Late Binding” as:

“Binding” is the association of a particular method, property, variable, and so on, with a particular name in a particular context; if done by the compiler then it is “early binding”, and if it is done at runtime then it is “late binding”.

You could argue that method_missing is another form of late binding where the name is bound to method_missing because there is no other name to bind to. But conceptually, it feels very different to me. With binding, you usually think of the caller determining which method to call by name. And whether it’s bound early or late is no matter, it’s still the caller’s choice. With method_missing it’s the object in control of whethere it’s going to respond to the method call (message).

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

23 responses

  1. Avatar for codekaizen
    codekaizen January 4th, 2014

    I think that's Ruby's "convention over configuration" value, but point taken.

  2. Avatar for haacked
    haacked January 4th, 2014

    Ha! What a brain fart! I fixed it. Thanks!

  3. Avatar for haacked
    haacked January 4th, 2014

    I ended up removing that paragraph because I realized I made a mistaken assumption.

  4. Avatar for vince
    vince January 4th, 2014

    I'm not going to pretend I "know" what duck typing is, I thought I knew until I read Eric's post, but I think the example you gave in python where you have a try/catch block to determine "the type" is still late binding but determined in a structured way.

    To me duck typing means defining a type which will become an object at some point in the future which may or may not be the same object thereafter...the type does not matter, that's the whole point to me.

  5. Avatar for Joshua Smeaton
    Joshua Smeaton January 4th, 2014

    I think Eric assumed that duck typing meant that the argument passed to a function had to resemble a specific type. As pointed out though, that is structural typing. A relevant python function that uses duck typing might look like this:

    def func(arg):
    if hasattr(arg, 'quack'):
    arg.quack()
    elif hasattr(arg, 'woof'):
    arg.woof()

    The type of the argument is totally irrelevant to the receiving function. The attributes the argument has are only relevant in the body of the method where they are used.

    Of course, with such a basic example, someone is likely to suggest an inheritance tree with a common "talk" method. I've been hacking on django lately, and duck typing is used right throughout the project. For example, a column in a query may be represented as a string, or as an object capable of generating the appropriate string.

    def parse_column(col):
    if hasattr(col, 'as_sql'):
    return col.as_sql()
    return col

    And now any user defined column only needs to provide an as_sql() method, and it can play along with the rest of the framework.

    Minor nitpick: my python brain is hurting due to the misaligned blocks in your try-catch example. Other than that, you're remarkably close to actual python!

  6. Avatar for haacked
    haacked January 4th, 2014

    Thanks Joshua!

    > Minor nitpick: my python brain is hurting due to the misaligned blocks in your try-catch example. Other than that, you're remarkably close to actual python!

    Would you mind sending me a pull request?! Just click the "edit" button at the top of my post and make the changes in the editor.

  7. Avatar for hwiechers
    hwiechers January 4th, 2014

    Just wanted to say that implicit typing is not the same thing as duck typing. I hope people don't start using that term to refer to duck typing because it actually has a well understood meaning.

  8. Avatar for haacked
    haacked January 4th, 2014

    Ah, what is the well understood meaning of implicit typing?

  9. Avatar for haacked
    haacked January 4th, 2014

    I changed it to say "typing by usage". I can't think of a better word at the moment. Perhaps, "de-facto typing?"

  10. Avatar for Joshua Smeaton
    Joshua Smeaton January 4th, 2014

    Done. The indentation was correct, I just failed to realise that each try block was supposed to be nested. So I just made the few changes required to be actual python.

  11. Avatar for Glenn Block
    Glenn Block January 4th, 2014

    I thought a lot about this and came to the conclusion that there are two key criteria that define duck typing.

    1. There is a structural contract defined for a function which is either explicit or implict.

    2. The parameters being passed do nothing to comply with the contract other than having members present / or at least they can handle those members (i.e. method_missing)

    These criteria stand up for both traditional duck typing and the newer stuctural typing which takes things even further.

    I blogged a much longer version here :-) http://codebetter.com/glenn...

  12. Avatar for Glenn Block
    Glenn Block January 4th, 2014

    Hey Phil, what about dynamic? It's still valid C# :-)

  13. Avatar for Brad Westness
    Brad Westness January 5th, 2014

    Another way to do a similar thing in C# would be to accept an Object parameter rather than a Duck parameter in your method signature, and then use reflection to check if it has a .Quack() method.

    You can basically accomplish the same thing with interfaces, but I can see where some library author might prefer the stylistic choice of being able to say "just implement a .Quack() method" rather than "all objects must implement IQuackable."

    Personally I like the interface approach better because I prefer compile-time exceptions to run-time exceptions, but in dynamic languages the duck-typing method is sometimes your only viable option.

  14. Avatar for Glenn Block
    Glenn Block January 5th, 2014

    When people talk about Duck Typing it's used in the context of the language making it easy. Using reflection is possible but it is not as intuitive / easy and requires more heavy lifting, it works around the language through runtime calls. Wheras in a dynamic language or using dynamic in C#, it just works and the code is very simple i.e.

    public void DoSomething(dynamic instance) {
    instance.DoIt();
    }

    is a lot more natural then

    public DoSomething(object instance) {
    instance.GetType().GetMethod("DoIt", BindingFlags.Instance | BindingFlags.Public).Invoke(instance);
    }

    don't you think?

    The one thing about interfaces is it forces the object that is being passed to the method to explicitly implement the interface. That's the main significant difference imo between that and Duck Typing. In Duck Typing member presence alone is enough.
    That is except in Go which actually allows an object to implement an interface simply by having the members on that interface present.

  15. Avatar for Brad Westness
    Brad Westness January 6th, 2014

    Well, yeah using dynamic is a little cleaner, but achieves effectively the same thing from the vantage point of anyone calling your .DoSomething() method. I guess mainly I was thinking that the reflection approach would enable you to check if the method exists without resorting to nested exception trapping, which would get ugly fast if you have more than one or two types to check for.

    I'd personally still stick with the interface approach when using C# as doing the duck typing thing feels like it's going against the entire point of using a statically typed language, but it's nice to know there are ways to achieve it if you have the mind to.

  16. Avatar for Glenn Block
    Glenn Block January 6th, 2014

    Brad

    I agree the reflection approach works! My point was only that it is not using the language to do it / as easy, it's working around the language using APIs.

    I agree with your second statement which is in general in a static language like C# I would choose to use interfaces.

    It's nice in Go though that you can have your cake and eat it too. :-)

  17. Avatar for Travis Illig
    Travis Illig January 6th, 2014

    I think the trouble with "duck typing" is that it's not "typing" in the conventional sense, but "late binding combined with message passing" and just referred to as "duck typing." It feels more like a convenience term than technically correct by computer science standards.

    Eric has a great point about the "typing" part of "duck typing" effectively being late binding. I buy that if typing even really plays a part in this scenario.

    However, I think the real "meat" of the thing is in that update at the end: "duck typing" smells to me like another name for "message passing," possibly combined with a little late binding. I don't think "method_missing" really has anything to do with the type system so much as how objects choose to respond to messages for which they don't already have responses prepared - just like "doesNotUnderstand" and "respondsTo" in Smalltalk.

    Finally, minor typo: "Apollo" is misspelled in the reference to "Apollo 13."

  18. Avatar for Li Chen
    Li Chen January 12th, 2014

    I tried to come out with an implementation of duck-typing in c#. It is based on proxy rather than reflection. Blog at: http://weblogs.asp.net/lich... and code at: http://skylinq.codeplex.com/. See if it makes sense.

  19. Avatar for dieuhien
    dieuhien February 27th, 2014
  20. Avatar for Jamie da Silva
    Jamie da Silva March 13th, 2014

    I wanted to come as close to this as possible for C#. Here's the doc for duck casting using my new ProxyFoo library - http://proxyfoo.com/docs/du...

    This is my first open-source project so feedback is very welcome.

  21. Avatar for mike
    mike June 3rd, 2014

    That is the Rails philosophy, not Ruby's.

    Rails is not Ruby.

  22. Avatar for mike
    mike June 3rd, 2014

    If you are explicitly checking types in a duck type language you are completely misunderstanding the point.

    Checking types in a duck typed language is a newbie error.
    In Ruby:

    class PetOwner
    def take_care_of pet
    pet.walk
    end
    end

    That is all that is needed. If the pet can't walk, as you noted method missing can rescue it, but the design is wrong. Removing that method and putting it in a module and than including it if the Owner has a pet that requires to be walked.

    module WalkablePet
    def take_pet_for_walk
    @walkable_pet.walk
    end
    end

    module CarMaintianable
    def take_care_of_car
    @car.maintain
    end
    end

    class Owner
    def initialize walkable_pet=nil, car=nil
    @walkable_pet=walkable_pet
    @car=car
    finalize
    end
    private
    def finalize
    extend WalkablePet unless @pet.nil?
    extend CarMaintianable unless @car.nil?
    end
    end

    owner = Owner.new WalkingPet.new,Car.new
    owner.take_pet_for_walk
    owner.take_care_of_car

    The only thing missing is to add method_missing to print out if the owner doesn't have a car or pet if one or both or those mixins don't exist for that object and of course adding setters to allow for the owner to get a pet or car.

    Duck typed and maintainable within the contrived example. There are much cleaner duck typed solutions that can more easily and cleanly handle adding new things that an Owner can own.

    Duck typing is an informal term but, depending on the language can have a precise meaning. Ruby is a good example of this. Ruby is dynamically and strongly typed. A Ruby object can never be coerced to a different type, including up or down the inheritance chain. In other words, objects can not be cast to any type. You can’t coerce a Fixnum to be one of its parents(like Integer), and you can’t coerce it to be a float. However, what an object can respond to can be added at any time.

    In Ruby, the actual type doesn’t matter, it is what can it do that matters. If an object responds to a method, it gets called, otherwise, method_missing gets invoked, and if that method is not overridden to deal with it an exception is raised.

    A good Duck typed language erases the need for a lot of standard patterns you see in the more rigid languages. The book Eloquent Ruby has an outstanding chapter that covers what Duck typing is, what it buys you, and what pitfalls to look out for. If you are a C# or Java fan, it might piss you off because it shows how duck typing makes dozens of lines of code, boilerplate or not, disappear.

    You two are over complicating something very simple. Your usage of C# is probably where you and the OP went wrong. If you want to learn about Duck Typing, use an actual language that has first class support for it. If you are checking types in Ruby, you are writing verbose, pointless code. If you see method calls to is_a? or class, 99.9% of the time, the author doesn’t understand Ruby in the slightest and is likely trying to make it work like Java.

    Just like if you really want to learn what object oriented programming is you don’t reach for C++, Java, Python, PHP or C# because they all miss the point, to varying degrees(but they are still all wrong). You use Smalltalk or Ruby because they actually grok and implement OO correctly.

  23. Avatar for gfgfgg
    gfgfgg June 23rd, 2014

    dfdfdfdfdfdf