Matt's Mind

Wednesday, August 18, 2004

Static vs Runtime Typing

In this post Bruce Eckel, who's written a lot of wisdom on software development, describes how he went from advocating C++-style static typing to Python-style dynamic "implicit" typing. What he means by this is the removal of things like Java interfaces and classes when describing an object. For example, a Python method to calculate a factorial takes an argument "x", but doesn't specify what x is: integer, floating point, BankAccount?
  def factorial(x):

if x == 0:
return 1
return x * factorial(x-1)
Bruce argues that static typing makes things harder for developers:
The extra verbiage that must be added in order to make the compiler happy doesn't really accomplish that much and has a severe impact on both productivity and code maintenance. We have to write unit tests anyway, so the illusion of safety comes at far too high a cost. Ned Batchelder put it another way: "Static typing prevents certain kinds of failures. Unfortunately, it also prevents certain kinds of successes."
The interesting thing here is that Bruce seems to be going further than many dynamic language advocates, who often say that dynamic programming is better because it lets you get small things done quicker without the syntactic boilerplate. He's claiming that since we're going to have 100% test coverage anyway, why pay the price of static typing in order to catch things like missing methods, etc? A number of responses to this come to mind from day-to-day development experiences.

Point 1: the testing requirement may be too onerous for a medium-size project, where 100% test coverage might be infeasible. For example, the 14KLOC GUI messaging application I'm developing would need a very large number of tests to cover all the code paths. Apart from the perennial problems involved in testing a GUI's and network communication, I simply don't wish to pay the price of 100% test coverage. I have tests for the core components, and test the rest by simply using the application day-to-day. Static typing ensures there are no trivial faults like typo's in method calls, the basic unit tests ensures there are no serious faults in the core components, and day-to-day usage exercises the rest.

Point 2: by not stating type info, you reduce the information available to readers of a program and to IDE's helping you develop the program. For example, say you come across some code that contains a "toolbar" object that seems to have an "add (item)" method. What sorts of objects can I add () and what behavioural contract do those objects need to satisfy? If there's type info like "Toolbar.add (ToolItem item)", then I (and an IDE) can immediately see what behaviour an item on the toolbar needs to provide and what classes provide it. I'd rate this as such important information that I'd argue that the lack of type information would have an impact on code maintenance, not the other way around (as Bruce claims in the article).

Point 3: dynamic typing excludes conventional optimization options. For my messaging application I can use a static compiler (Excelsior JET) that generates a highly optimized Windows .EXE from my Java code. A dynamic language does not currently have this option.

Point 4: when you need some some dynamic programming in Java, you can get it. Reflection, although it's messier than Python's elegant syntax, gives you the ability to ignore type when you need it. For example, a common GUI paradigm is the Command pattern: a command object packages the functionality of an application command (eg "Edit -> Cut") and is embedded into toolbars, main menu, context menu etc which invoke its execute () method when the user clicks the various items. A key issue with this pattern is that many commands, such as "Cut", are context-sensitive: the Cut command obviously needs to know what to cut.

This "object-to-operate-on" property of a command is very often bound to the selected item in a view such as a list or a tree, and it would be nice if we could have a simple way to just bind a command's property to the selected item in a view instead of writing endless tiny event handlers. So I have a class that listens to selection changes on any GUI viewer control and feeds the selected item(s) to a given property X of an object (usually a command), which is done by calling its setX () method. The type of the target object is irrelevant, as long as it has a setX () method. In fact this binding approach ends up being more flexible than the equivalent in Python because the binding object can find the type of X and automatically decide whether the currently selected item is compatible: if not it does not proceed with the binding and instead disables the command.


Post a Comment

<< Home