Home Play Pinja Bobbity flop

A blog about Ruby, Rails and other Tech. Mostly.

Back to blog

6th Jul 2004, 10:07pm
Ducktyping

The phrase "Ducktyping" comes from the simple idea that "If it walks like a duck, and it quacks like a duck, then let's call it a duck!". Possibly it was invented by the Pragmatic Programmers, I'm not sure. But it's a memorable way to state a very cool idea.

In programming in object oriented languages like ruby, it means that instead of asking your objects what type they are, why not just ask them what they can do?

Let's say you have a program that you pass an object to, from which your program is expecting to get some fish. In the old way of doing things, you might ask it "Object, are you a kind of Fishmonger?", and if so then call the "getFish" method. If it wasn't a Fishmonger, or a subclass thereof, then maybe you would say "Are you a Supermaket then?", and so on.

The trouble is, you get a long list of ifs and elses, and even then you don't cover all eventualities. Much better to ask the object "Do you have a getFish method?". This is what you really want to know.

This is all well and good in theory, but what prompted me to write about this is that I just came up against a very real case where duck typing would help.

The XML library that most people use in ruby is called REXML. And at the start it has some code like this:

if source.kind_of? String
  @source = Source.new(source)
elsif source.kind_of? IO
  @source = IOSource.new(source)
elsif source.kind_of? Source
  @source = source
elsif defined? StringIO and source.kind_of? StringIO
  @source = IOSource.new(source)
else
  raise "#{source.class} is not a valid input stream. It must be\n"+
        "either a String, IO, StringIO or Source."
end

Now, I wanted to read from a zlib GzipReader - this is something that behaves a lot like an IO object (which would usually be a stream from a pipe or a file), but it isn't actually a subclass of IO. You can read and getc and so on from a GzipReader just like an IO.

But passing the reader into REXML causes a "not a valid input stream" error. The author wasn't expecting a GzipReader! And possible he couldn't have covered all possibilities in this type of code.

You guessed, the solution is to not test to see if the object is an IO - the object should be tested to see if it responds to the read method (and/or readlines, or getc or whatever is needed). Then if you pass it something perfectly reasonable, but that happens to not be subclassed from something that was thought of when the program was written, then in all likelyhood it will just work anyway.

This is ducktyping in action.


Back to blog