The idea behind "Duck Typing", which has recently be made popular again by Ruby and other script languages, is to make the concept of types less restrictive.

Consider the following:

public interface ILifeCycle {
public void onStart();
public void onStop();
public void onPause();
// ...
public void runObject(ILifeCycle object) {
// ...

Faced with this kind of construct, some languages decide that the existence and even the name of the interface ILifeCycle is unimportant.  The only thing that really matters is the fact that runObject() needs the methods onStart() and onStop() to exist on the parameter, and that’s all.

In short, it boils down to:

public void runObject("any object that responds to the methods onStart and onStop" object) {
// ...

Late-binding languages are actually even less restrictive than that, since the verification that the object does respond to such methods is not made when the object is passed as a parameter to the method, but on the invocation of the said methods, which explains why parameters to methods are usually not typed

In a way that’s typical for dynamically typed language, the error will therefore only appear at runtime and only if such code gets run.

First of all, let’s get a frequently asked question out of the way:  if two interfaces have the same methods, are they semantically equivalent?  Isn’t there a risk to pass an object that is totally wrong for this method, yet will work because it responds to the right methods?

I don’t have a clear answer to that, but my experience is that such a thing is very unlikely.  This kind of argument is a bit similar to the fear we all felt in the beginning of Java when we realized that containers are not typed:  ClassCastExceptions end up being much more rare than we all thought.

Duck Typing is a big time saver when you write code, but is it worth it?  Don’t you pay this ease of development much later in the development cycle?  Isn’t there a risk that you might be shipping code that is broken?

The answer is obviously yes.

The proponents of Duck Typing are usually quick to point out that it should never happen if you write your tests correctly.  This is a fair point, but we all know how hard it is to guarantee that your tests cover 100% of the functional aspects of your application.

Another danger in the Duck Typing approach is that it makes it really hard to see what the contract is between callers and callees.

As you can see in the code above, you need to actually understand the entirety of the method to realize that the parameter passed to the method needs to respond to onStart() and onStop().  But the worst part is:  the code is lying to you!

The method is also relying on onPause(), except that this method is not used in this particular runObject().  But it is used in execute() in a different class.  How would you realize that runObject() and execute() work on objects of the same type?  With Duck Typing, it’s extremely hard to tell and it requires a detailed read of the code of these methods.

If you wanted to use runObject() from your own code, you would make the flawed assumption that all your object needs to do is respond to onStart() and onStop(), and chaos will ensue if/when the implementation is upgraded to invoke onPause() as well.  At least, with the typed approach, the contract is obvious and you are guaranteed that it can’t be changed from under you (the provider of this interface can’t add a method to ILifeCycle without breaking everything, so they will probably provide an ILifeCycle2 interface or something similar to guarantee backward

I am all in favor of anything that makes the development process more agile, but if I can ship code that contains errors when these errors could have been caught by the compiler before my code even gets a chance to run, I will seriously consider leveraging this support as much as I can.

Duck Typing is dangerous and should only be used for quick prototyping.  Once you switch to production coding, I strongly encourage everyone to make their code as statically typed as possible.

This is one of the great things in Ruby:   it is late-bound but still statically (strongly) typed.  Not only is the interface approach shown in the first code snippet above fully supported in Ruby, it is actually quite encouraged and it doesn’t make your code any less Ruby-ic.

Use Duck Typing for prototyping, but program to interfaces for anything else.