But does it quack like a duck?

code 15 comments suggest edit

From the topic of this and my last post, you would be excused if you think I have some weird fascination with ducks. In fact, I’m starting to question it myself.

Is it a duck? - CC BY-ND 2.0 from http://www.flickr.com/photos/77043400@N00/224131630/

I just find the topic of duck typing (and structural typing) to be interesting and I’m not known to miss an opportunity to beat a dead horse (or duck for that matter).

Often, when we talk about duck typing, code examples only ask if the object quacks. But shouldn’t it also ask if it quacks like a duck?

For example, here are some representative examples you might find if you Google the terms “duck typing”. The first example is Python.

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

Here’s an example in Ruby.

def func(arg)
  if arg.respond_to?(:quack)
    arg.quack
  end
end

Does this miss half the point of duck typing?

In other words, don’t check whether it IS-a duck: check whether it QUACKS-like-a duck, WALKS-like-a duck, etc, etc,…

Note that this doesn’t just suggest that we check whether the object quacks and stop there, as these examples do. It suggests we should go further and ask if it quacks like a duck.

Most discussions of duck typing tend to focus on whether the object has methods that match a given name. I haven’t seen examples that also check the argument list. But yet another important aspect of a method is its return type. As far as I know, that’s not something you can test in advance with Ruby or Python.

Suppose we have the following client code.

def func(arg)
  return unless arg.respond_to?(:quack)
  sound = arg.quack
  /quack quack/.match(sound)
end

And we have the following two classes.

class Duck
  def quack
    "quacketty quack quack"
  end
end

class Scientist
  def quack
    PseudoScience.new
  end
end

The Scientist certainly quacks, but it doesn’t quack like a duck.

func(Duck.new) // returns a MatchData object
func(Scientist.new) // returns nil (match failed)

I think that’s one reason why the example in my previous post actually tries and call the method to ensure that the argument indeed quacks like a duck.

My guess is that in practice, conflicts like this where a method has the same name, but different type, is rare enough that Ruby and Python developers don’t worry about it too much.

Also, with such dynamic languages, it’s possible to monkey patch an object to conform to the implicit contract if it doesn’t match it exactly. Say if you have a RobotDuck you got from another library you didn’t write and want to pass it in as a duck.

Thanks to GeekSam for reviewing my Ruby and Python idioms.

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

Comments

avatar

15 responses

  1. Avatar for Rasmus Schultz
    Rasmus Schultz January 6th, 2014

    You should have a look at interfaces in Go:

    http://golang.org/doc/effec...

    It's duck-typing, but (IMO) finally done right - other languages, as you pointed out, use something that should accurately be described as "duck-like behavior", but no actual "types", hence not really duck "typing" as such.

    As you explained, they're doing assertions along the lines of "does it quack?", where "real" duck-typing ought to be asking "is it a duck?".

    Go's type system does that.

  2. Avatar for marcusswope
    marcusswope January 6th, 2014

    "...another important aspect of a method is its return type. As far as I know, that's not something you can test in advance with Ruby or Python."

    Since in these languages a single method can return different types based different parameters or application states, there would never be a way to determine this without running the method and checking the type (or its "quackery") :)

  3. Avatar for Tyler Ramsey
    Tyler Ramsey January 6th, 2014

    Interesting timing, Eric Lippert recently questioned the definition of duck-typing in his blog. I found it interesting in that you mention what you feel is a proper way to perform duck-type assertions while Eric mentions that the very definition of duck-typing can be different from developer to developer (or language to language). Kind of neat to see two well informed perspectives intersect.

    http://ericlippert.com/2014...

  4. Avatar for haacked
    haacked January 6th, 2014

    Well this post and my last post http://haacked.com/archive/... were in response to his post. So it's not a coincidence. :)

  5. Avatar for Tyler Ramsey
    Tyler Ramsey January 6th, 2014

    Hah, well that's embarrassing. If only I were to actually read the posts in the order intended!

  6. Avatar for James Hart
    James Hart January 6th, 2014

    Of course, in JavaScript, whether it's a duck or not, regardless of whether it knows how to quack at all, you can try to make it quack like one anyway:

    Duck.prototype.quack.apply(dog);

  7. Avatar for John Atten
    John Atten January 7th, 2014

    Not that Wikipedia should be considered a canonical source for *anything*, but a key line in the Wikipedia article on Duck Typing is:

    "Duck typing is aided by habitually not testing for the type of arguments in method and function bodies, relying on documentation, clear code and testing to ensure correct use."

    Whether or not one buys into that particular philosophy or not is another matter. :-)

    The recent posts on this by Eric Lippert, yourself, and Glen Block (http://codebetter.com/glenn...
    came a good time for me, as I have been trying to come to terms with JavaScripts and Node.js. A day or two before Lippert's original post I had been looking at that very Wikipedia page.

  8. Avatar for martijnhoekstra
    martijnhoekstra January 7th, 2014

    Structural types in Scala do just this; the entire signature must match. If structural typing counts as duck typing I'll leave up to religious war^H^H^H^H polite debate from others.

  9. Avatar for Richard Gibson
    Richard Gibson January 7th, 2014

    Typescript has my absolute favourite implementation of structural typing. Look at this example, it covers the same example you gave and is compile-safe:

    function func(arg: { quack(): any })
    {
    var sound = arg.quack()
    alert((/quack quack/).test(sound).toString())
    }

    class Duck
    {
    quack()
    {
    return "quacketty quack quack"
    }
    }

    class Scientist
    {
    quack()
    {
    return new PseudoScience()
    }
    }

    class PseudoScience { }

    func(new Duck())

    Not only that, but you can enforce the return type too, as you requested by changing the signature of the main method from
    function func(arg: { quack(): any })
    to
    function func(arg: { quack(): string }).

    I think it's beautiful.

  10. Avatar for Ed Courtenay
    Ed Courtenay January 7th, 2014

    TypeScript gets it right; you can define an interface, and require that a method takes an instance of that interface as a parameter, but the instance passed in does not have to be explicitly derived from that interface - it only has to implement the 'shape' of the interface.

  11. Avatar for martijnhoekstra
    martijnhoekstra January 7th, 2014

    As a Wikipedian myself I find it fair to say that the Wikipedia article is quite bad - especially with the (possible) difference between late binding, structural typing and duck typing. I already cleaned up the F# section a little after Lipperts post. Help - especially in the form of sources that describe the difference - would be greatly appreciated. I have the feeling though that even in the litterature duck-typing and the contrast to late binding and structural typing is currently ill defined.

  12. Avatar for the_real_cuban
    the_real_cuban January 7th, 2014

    I am still surprised at not seeing complete mentions of semantics of the called method, only a vague reference to its signature, is that enough?
    What if you require certain assertions to hold on the returned value prior to calling the method, e.g, you require a "quack" that is guaranteed to return a 5-letter string? Is that part of the "like a duck" in your title?

  13. Avatar for Aaron Shumaker
    Aaron Shumaker January 31st, 2014

    How is this strict type of ducktyping different from the technique of checking for an interface? if(someThing is IDuckQuackable) { someThing.Quack() }
    This gives you the assurance that the Quack you are calling is semantically what you want. If interfaces are properly used(minimal, separation of concerns, i.e. no IDuck, but instead IBirdFlyable, IDuckQuackable, etc.) then you can do this kind of thing without the risks you describe and seemingly the same advantages.
    I ask more out of trying to understand what scenarios might lend themselves more to ducktyping than judicious use of interfaces?

  14. Avatar for dieuhien
    dieuhien February 27th, 2014
  15. Avatar for Bruno Facca
    Bruno Facca June 26th, 2016

    Great post! Thank you. I have linked it in the latest post at my Zen Ruby blog: http://www.zenruby.info/201...