Let’s start by thinking about a very simple example. I’ve recently switched to using Ruby as my language of choice, after a decade as a Perl hacker. Ruby does a lot of things more nicely than Perl, including having proper object syntax, simple everything-is-an-object semantics, a sweet module/mixin scheme and very easy-to-use closures, so I’ve mostly been very happy with the switch. In so far as Ruby is a better Perl, I don’t see myself ever writing a new program in Perl again, except where commercial considerations demand it.
But there are some things that I miss from Perl, and one of them is the ability to say (via use strict) that all variables must be declared before they’re used. When this pragma is in effect (i.e. pretty much always in serious Perl programs), you can’t accidentally refer to the wrong variable — for example, if you use $colour when you meant $color (because you’re a Brit working on a program written in America), the Perl compiler will pull you up short and say:
Global symbol “$colour” requires explicit package name at x.pl line 4.Execution of x.pl aborted due to compilation errors.
In Ruby, there is no need to declare variables, and indeed no way to declare them even if you want to (i.e. nothing equivalent to Perl’s my $variableName). You just go ahead and use whatever variables you need, and they are yanked into existence, bowl-of-petunias-like, as needed.
Which means that Ruby programs suffer a lot from $color-vs-$colour bugs. Right?
Not so much, as it turns out.
Problems that are not really problems?
Ruby’s been my language of choice for about four months now — which I admit isn’t very long, but it’s long enough that statistics over that period are not completely meaningless. So far, I’m not aware that I’ve run into a $color-vs-$colour problem even once. Doesn’t mean it’s not happened, of course — maybe it did, the problem was obvious when I saw the program run wrongly, and I fixed it on autopilot without really registering it.
At any rate, if it’s happening at all, it’s not a big deal for me in practice. Which makes me think: is it ever? Could it be that variable-misspellings are a category of bug that we naturally tend to guard against rigorously but that we we don’t actually need to worry about?
If this is true, then it’s come as a surprise to me. When I was switching to Ruby, I sent emails to my Ruby-maven friends whining about the lack of variable declaration and foreseeing all kinds of doom arising from it. I’m as surprised as anyone that it’s not happened.
In the mean time, I have saved myself the trouble of typing my $variable (or, since it’s Ruby and we don’t need line-noise characters in variable names, my variable) some hundreds or maybe even thousands of times. Now, typing that is not a particularly heavy burden. If it takes, say, three seconds to type each time, and I’ve omitted six hundred of them in the last few months, that’s 1800 seconds which is half an hour. Long enough to watch an episode of Fawlty Towers, but not long enough to dramatically change my programing lifestyle.
Particularly heavy burdens
But now think about the difference between typing
public static void ArrayList<Integer> qsort(ArrayList<Integer> a)
In other words, explicitly stating your types. We do this for basically the same reason that we declare variables before use: to guard against our own mistakes, and to get them reported to us as quickly and clearly as possible. Now that is, unquestionably, a Good Thing. I am big fan of what I call the FEFO principle: that programs should Fail Early, Fail Often. When something goes wrong, I want to hear about it straight away: what can be worse that trying to debug a program that ignores an error condition until it pops up later, when all the evidence has gone?
But let’s also be honest that all that public static void main stuff does impose a real burden. A much heavier one than the occasional sprinking of my $variable. What we have here (and this shouldn’t really surprise anyone) is a case of getting a real benefit in return for a real cost. Well! Turns out that you can’t get something for nothing! Who’d have thought?
(Now of course you have your dynamic-typing fundamentalists, who will argue that having type errors diagnosed up front is valueless; and likewise, you have your static-typing fundamentalists, who will argue that all the scaffolding in languages like Java imposes no cost. Since both are clearly talking nonsense, and worse, are impervious to rational argument, let’s just treat them as we would treat that other wacky pair of opposed fundamentalists, “Doctor” Kent Hovind and Richard Dawkins, and ignore them.)
So the question is not “is static or dynamic typing better?” — advocates of both sides will be able to give cogent reasons in support of their position; and opponents of each side will be able to give cogent reasons why the position is wrong. Stage Zero in understanding the problem is simply to recognise that there really are legitimate reasons to adopt either position. The question is more along these lines: given that static typing imposes an overhead on programming, under what circumstances does that overhead pay for itself?
When does the cognitive tax imposed by static typing pay for itself?
And as soon as the question’s phrased in those terms, it gets a lot easier to think clearly about. Because we realise that it all comes down the question of what it costs to have a bug. If I’m writing an e-commerce web-site that sells books, a mistake may mean that I lose an order worth £20. If I write software that runs life-support systems in hospitals, a mistake may mean that someone dies. It seems obvious to me (although I admit that using the word “obvious” is always asking for trouble) that in the former case, it’s better for me to spend my time getting more work done — adding features and whatnot — and risk losing the odd sale to a bug that static typing might have found for me. It also seems obvious that in the latter case I should use every tool available to ensure that the code is correct, and that the cognitive overhead of static typing is a small price to pay. Somewhere in between those extremes lies the crossover point. But where? Those of you who work on banking software might have opinions on this: bugs can potentially have dramatic financial consequences but are unlikely to directly endanger life and limb.
Safety is expensive
Now here’s the thing: we all know from experience that as organisations grow, they invariably start to accumulate more and more rules, procedures, forms to fill in, and so on. One day, when a company has 200 employees, someone climbs a stepladder to change a lightbulb, falls off the ladder, breaks his collar bone and has to take two weeks paid leave. That costs the company, say, £3000, and someone high up thinks “This must Never Be Allowed To Happen Again!” So before you know it, there’s a set of Stepladder Safety Procedures that have to be followed, and no-one is allowed to use a stepladder at all until they’ve taken the half-day Stepladder Safety Course. Eventually every employee has taken the course (at a cost of 100 person-days, or £30,000) and as a result no-one falls off a stepladder again for a while. (We’re charitably assuming that the course is successful and that the overall rate of stepladder accidents really does decrease as a result of everyone having taken the course.)
Now of course in objective financial terms, this doesn’t pay off until we reach the point where, without the course, ten people would have fallen off their stepladders on office time. But in the meantime the company keeps growing and the hundreds of new employees are also taking this expensive and not-usually-useful course.
For similar reasons, mature companies will often have many, many other procedures that everyone has to follow. Because someone once nicked £50 worth of stationery and It Must Never Be Allowed To Happen Again, all 200 employees spend fifteen minutes every week filing Stationery Requisition Forms (at a total cost of £2000 per week); and so it goes. We all know someone who’s worked in one of these places where you can’t so much as sneeze without filling in a form in triplicate first. Some of you are unfortunate enough to work for such companies.
In some circumstances — some, I say! — all that tedious mucking about with static types is like the Stepladder Safety Course that costs ten times more than it saves.
On the other hand, there are circumstances where safety is important. Deeply important. Where additional layers of procedures, forms, validations and suchlike pay for themselves over and over again.
So here’s my thinking: the older and larger an organisation gets, the more it tends to lean on formal procedures, form-filling and suchlike to buy safety — even if it’s at a disproportionally high price. And because that’s the existing culture of such organisations, they are disproportionally likely to favour static typing, which fits into their standard SOP of investing extra effort up front to reduce the likelihood of accidents further down the line — however unlikely those accidents and however minor their consequences. And I think this explains the near-universal tendency for big organisations to favour what I am going to suddenly start calling Stepladder-Safety Programming.
If I’m right, it explains a lot. It explains why SSP-friendly languages like Java and C++ are so widely used (it’s because the relatively few organisations that use them are the large ones), but also why there’s always been such a strong guerilla movement that prefers dynamically typed languages such as Perl, Python and Ruby — and indeed the various dialects of Lisp, if you want to go back that far. It also explains why there is such a strong bifurcation between these two camps: static typing is often favoured in environments where anything else is almost literally unthinkable whereas dynamic languages are often found in startups where Get It Working Quickly is the absolute sine qua non, and SSP wouldn’t even be on the radar. That fact that static vs. dynamic typing is embedded in cultures rather than just programming languages makes it much harder for people to cross the line in either direction: it feels like a betrayal, not just a technical decision.
And this of course is complete nonsense.
At bottom, static vs. dynamic is a technical decision, and should be made on technical grounds. Cultural predispositions in one direction or the other are, simply, an impediment to clear thinking.
And finally …
The great technical impediment that prevents us from choosing to adopt either static or dynamic typing on a project-by-project basis based on a mature and disinterested judgement of whether the additional cost is merited in light of the project’s safety issues
Here is my big gripe: the choice of static or dynamic typing is so often dictated by the programming language. If you use Java, you are condemned to name your types for the rest of your days; if you use Ruby, you are condemned never to be able to talk about types — not even when you really want to, as for example when you want to describe the signature of a callback function.
That’s just stupid, isn’t it?
Surely it should be the programmer’s choice rather than the language’s?
There are a few bows in this direction in languages known to me. One of them we’ve already mentioned: Perl’s optional use strict pragma imposes a few static-typing-like limitations on programs. Most notably, it includes use strict ‘vars’, which requires each variable to be declared before use. That’s pretty weak sauce, but at least a step in the right direction, which is more than Ruby offers. Although the use of use strict is close to ubiquitous in the Perl world, there are exceptions: for example, I notice that the unit-test scaffolding script generated by h2xs does not use strict — presumably on the assumption that test-scripts are easy enough to get right that it’s nice to be allowed to write in the laxer style.
But, really, much much more is needed. There’s no obvious technical reason why Ruby and similar languages shouldn’t be able to talk about the types of objects when the programmer wishes, and non-ambiguous syntax is not difficult to invent. Conversely, would it be possible to relax Java and similar languages so that they don’t have to witter on about types all the time? That might be a more difficult challenge — I don’t know enough about Java compilers or the JVM to comment intelligently — but it seems to be at least a goal worth aspiring to.
Does anyone know of any existing languages where static typing is optional?
In conclusion …
In choosing what typing strategy to use in writing a given system (and therefore, given the current dumb state of the world, in choosing what language to use), we should give some thought to the costs involved in static typing and the risks involved in not using it — both the likelihood of error (which in my experience is often much smaller than we’ve got used to assuming) and the cost if and when such errors do occur. My guess is that a lot of habitual Java/C#/C++ programmers are in the habit of doing Stepladder Safety Programing for essentially cultural rather than technical reasons, and that a large class of programs can be written more quickly and effectively using dynamic typing while admitting little additional possibility of error.
We do need static typing for life-support systems, avionics and Mars missions.
(Although come to think of it, the dynamically typed language par excellence Lisp was indeed used on Mars missions, to very good effect. This was pointed out in a comment by Vijay Kiran on an earlier article: “Debugging a program running on a $100M piece of hardware that is 100 million miles away is an interesting experience. Having a read-eval-print loop running on the spacecraft proved invaluable in finding and fixing the problem.” I’m not sure what to make of that observation.)
 Having your program talk about types can also enable optimisations that aren’t otherwise possible, but those benefits are not as great as people sometimes seem to imply; and since we all know that time spent in CPU is rarely the limiting factor in the kinds of disk- and network-bound programs that most of us work on most of the time, let’s ignore that for now.