Tuesday, December 14, 2010

Too Lazy to "Type".

Loren Segal (@Islegal) in his blog (http://gnuu.org/2010/12/13/too-lazy-to-type/) makes the interesting point that most dynamic programs are, in fact, not particularly dynamic. Even duck-typed ruby programs would require very little change to make them static. He includes a Rack example showing this transformation.

class MyMiddleware
def call(app) ... end


class MyMiddleware
include Callable
def call(app) ... end

He asks, in the end: "how often do you write Ruby code that can really not have some kind of class based inheritance type system? For me, I can’t think of many cases. How often do you pass arbitrary types to methods without at least having a well-defined set of types that can be accepted by the method?"

He's quite correct that many (if not most) programs written in dynamic languages do not need to be dynamic. That with a very few simple changes we could add the hints that would make them static. And this would allow the compilers to optimize the programs in ways that are impossible for dynamic programs. However, there is a cost -- and the cost is not simply typing (and by that I mean keystrokes or LoC).

The cost is _dependencies_. The simple "include" in Segal's example above is a _coupling_. That coupling adds complexity to the design of the application. It might not seem that such a simple statement would be very confounding, but the problem is not one simple statement. The problem is that nearly all our classes would suddenly require instrumentation with appropriate includes or extends statements.
Even that might not seem all that bad, but the problem is that the requirements for interfaces change. We often want to add new methods to existing interfaces. When we do, we must add those methods to all classes that implement those interfaces, whether they need it or not. If some of our derivatives don't need those methods we might be tempted to split the interface into one that has the new methods, and one that does not; but that forces us to find all the classes that implement that interface and decide, in each case, which interface it should now derive from.

And of course interfaces depend on other interfaces which depend on other interfaces. And so the tangle grows. If you haven't been programming in a static language for awhile, it is easy to forget the complexities that these couplings lead to. But in the end, we like dynamic language not because we are too lazy to "Type". We like dynamic languages because we are tired of untangling couplings.

Robert C. Martin (Uncle Bob) | unclebob@cleancoder.com
Uncle Bob Consulting LLC. | @unclebobmartin
847.922.0563 | web: objectmentor.com


  1. I think I agree with your conclusion, but I'm not sure if the argument is sound.

    "The problem is that nearly all our classes would suddenly require instrumentation"

    Isn't this less of a problem in a language with open classes? You can reopen all the necessary classes and include the module. That would reduce the coupling, but at the expense of worse coherence?

    "We often want to add new methods to existing interfaces"

    Won't this be solved in the case of Ruby modules, as they are mixins and can provide a default implementation of methods?

  2. I like the approach Eclipse PDT (php extension) takes. You can write an annotation which can be used by the tool to hint you of the expected type and help navigate the source code but does not enforce you in any way to actually use the hinted type. For all other dynamic languages I would like to have something similar.
    I guess it's something you're writing about.
    PHP itself has a type hint system but once you use it in your code you are forced to pass the arguments in the declared way - IMHO this is a very bad feature.