Thursday, March 16, 2006

Here's an interesting discussion. The State of the Scripting Universe

Just to note what I always tell my Programming Language class. Alan Kay (inventor of Smalltalk) wrote that "higher level" is synonymous with "later binding". In other words, the more things that are bound later, the higher level the language is.

My take on it is this. The more things that are bound at run-time, rather than compile-time, the more context aware the language is. The more it is able to take note of and adapt to its environment. Look at how Ruby on Rails uses metaclass hacking to dynamically update its classes as the description of the tables in the database changes.

Earlier, static binding, of variables to types, of function calls to blocks of code, of classes to particular data-structures, means that the code you write is context independent, a one dimensional list of instructions. Later, dynamic binding, of variables to types, of message selectors to blocks of code, or classes to data-structures, means that more of your code becomes more abstract, generic, fluid, meta-recipies which say "in this context do this, but in that context do that, and in t'other context do t'other thing"

It's not simply the extra finger-typing involved in static binding that's a problem. The compiler checks and restricts the behavior of programs to a well defined and (hopefully) understood set of behaviours. But this necessarily involves preventing more meta-level, generic, context-aware programming. Programmers working with static binding have to predict the future more accurately because they can't expect the code to adapt to it when it arrives.

Java's an interesting case. A lot is made of the kinds of adaptability that are available at (or close to) runtime; of how its polymorphism allows new behaviors to be slotted into old code. But it's less noted how all this dynamism is too ordinary to mention in the context of dynamic languages.

The more you think about patterns and good practice and underlying principles in Java, the more obvious it becomes that they exist to maintain a modicum of dynamism against the dead-hand of static binding in the compiler. Favour composition over inheritance? Only because you can't change the inheritance hierarchy at run-time, but you can slot in another Strategy object. (Assuming you got your dependency injection right.) Design to interfaces? Because you don't want to be anchored to particular class names in your code.

Well, in most dynamic languages, you can change the inheritance hierarchy at run-time (and add another mixin). Arguments aren't burdened with type restrictions, so you can be sure that you'll be able to pass anything you need to to a function, however unpredictable it was to the original authors.

All those expensive pattern-language books? All that training and time spent on good design? All to overcome the static bindings between variable and type, class and superclass, which the compiler set in concrete.

No comments: