Saturday, May 12, 2007

Purest Idiocy

It appears that once again, various people are discovering that writing webapps in Ruby with Rails requires fewer keystrokes than writing similar things in Java with Struts and Springs.  While this is hardly a new realization (and is, one could mention, the entire justification for the existance of Rails), they then go on to conclude that the real culprit here is static typing.

I address this before when a different set of pundits came to the same conclusion (you know, roughly two years ago now), but this iteration's dynamic-typing proponents have come up with a couple of bold new ideas:

If you have pervasive testing, static typing == more typing. The static typing is nothing but a requirement to type extraneous code to satisfy a compiler that isn't telling you anything interesting anymore.

So, let's play the Hello, World game:

Ruby (dynamically typed): puts "Hello, World"

Haskell (statically typed): main = putStrLn "Hello, World"

Wow, look at all that extra typing.

The part that's particularly confusing to me, though, is the part where he concludes that if you already have pervasive testing, you don't need static type checking.  The goal of static typing is to describe (and thus constrain) the behavior of your code, and thus reduce the number of cases in which failure can occur (and thus the number of things that need to be, incompletely I might add, checked with test cases).

It's not a simple trade-off, though.  Consider a dynamically typed function:

(define (square x) (* x x))

compared to a statically typed:

square x = x * x

These both operate over the same domains, but in the case of the former, there's no static guarantee that the incoming values are within that domain.  (square "this") or (square :that) compile just a nicely as (square 2).  This means that to have complete testing coverage, you need to verify the behavior of square for all possible values in the language, not a constrained set.

Of course, things get more interesting once you get outside the world of printing hello world and squaring numbers.  Recently, I've had some fun discovering which parts of the .Net libraries are threadsafe.  While reading the documentation would have helped my quest, and testing did discover the non-threadsafe functions I'd missed (granted, four hours into batch runs), in Haskell I'd have been able to tell from the types whether or not the operations were threadsafe.  That's a stronger assertion than I've seen any testing library be able to make.