Yesterday I wrote a bit about religious fervor vs hyper-skepticism regarding popular development fashions. One of those fashions is “dynamic languages” such as Ruby and Python. I have a way of looking at dynamic vs static languages that I find helpful that I haven’t seen written up elsewhere. So here it is for posterity, for what it’s worth.
Dynamic (loosely-typed, late-bound) languages are focused more on runtime objects and what they are capable of doing. Static (strongly-typed, early-bound) languages are more about compile-time classes and their identities. In other words, static languages are about what a class is; dynamic languages are more about what a class does.
You can think of it this way. Suppose I have the following classes:
- Class Foo with public method FooBar().
- Class Bar with public method FooBar().
- Class Boo with public method Hoo().
None of these classes have an inheritance relationship beyond the fact that they all derive from a common object class (like System.Object in .NET). Even this relationship may not exist in all languages, because not all languages expose a common ancestor class.
If I’m using a statically typed language like C#, and I issue code something like this:
Foo myInstance = new Foo(); myInstance.Foobar();
… I think of the compiler as something like Star Trek’s Mr. Spock. He arches his eyebrow and says, “myInstance is of type Foo. There is a public FooBar() method that is part of Foo’s signature, therefore, I will allow this call”.
On the other hand, making a similar call in a dynamic language, we typically have an interpreter or perhaps a p-code compiler that I envision as more of a Stallmanesque longhair, a bearded buy with sandals, who says, in effect, “No problem, dude!” and calls FooBar() on whatever instance you pass him. He doesn’t really care; he just assumes you know what you’re doing. In the above situation it works, because the Foo instance has a FooBar() method. If you tried the same thing on a Boo instance, the response is along the lines of “Bummer! I can’t find a FooBar() method. Sorry, man.”
I cut my OOP teeth on Visual FoxPro back in the early 90’s, which is an un-sexy but very dynamic language. When interfaces were added to the language to accommodate the needs of COM objects, I found them a rather alien concept. I didn’t see a use for them beyond what I assumed in my ignorance was the arcane demands of COM.
It wasn’t until I became heavily involved with C# back around 2001 that it dawned on me that interfaces are largely a kludge to accommodate the identity-oriented obsessiveness of static languages. VFP didn’t need interfaces, really. But C# desperately needs them because it’s the only way to call a collection of objects that are related by a common capability rather than a common definition. In other words, if two instances don’t share the same inheritance tree then an interface is your only hope for defining a common “partial type” that will allow you to look at them from the perspective of their functional commonalities. For example, an IFooBar interface would let you access both my Foo and Bar example classes from the same type, and call FooBar() on either.
From this point of view, interfaces are extra work to get a “for free” capability found in dynamic languages.
I realize that interfaces have some other uses, and some people take this to the extreme that you should never instantiate classes, only interfaces — in order to maintain loose coupling and allow easy implementation of pluggable / swappable implementations. I am a little dubious of this, as I think it’s using interfaces because they’re there and they’re cool rather than what they’re mainly for. Also, there are times when you can accomplish the same thing with abstract classes, and maybe do it better. But I digress.
I spent most of the 1990’s using dynamic and semi-dynamic languages, and have spent most of this century so far in the static world of C# (and occasionally, VB.NET). When I first made the transition, I found static typing somewhat annoying and confining, but I came to love the benefits, not the least of which are the almost spooky insight the development environment has into your code. I doubt that the level of Intellisense I enjoy working with every day is possible in a loosely-typed environment.
In other words, I think the trade-off has been well worth it. When I occasionally have to drop back to server-side VBScript to maintain someone’s legacy ASP code, I feel a bit lost and make more stupid mistakes because I’ve come to rely on the compiler to keep me out of trouble.
That said, all things being equal, I can’t really claim that I was more or less productive in either environment, at least not strictly because of what sort of typing they used. Dynamic languages do let you get more quickly into the flow, to convey intent rapidly without a lot of forethought about types and type declarations. This is both good and bad, and I suspect that it’s something of a wash overall, although specific projects may be better suited to one language type or the other.