functional programming and OO. I’ve decided to address some of these issues over the coming weeks, as much of this debate is raging in my workplace currently. But for now, I’d like to address a question raised some weeks ago by one of my co-workers.
Along with some fellow Erlangers, I was demonstrating Erlang and OTP to selected members of our 60 strong engineering group during a planning meeting in Dublin. One of the attendees asked a telling question: “what about when things change.” Reading between the lines, I could tell that my friend and colleague was really asking about the ease with which you can modify (and thereby maintain and potentially extend) Erlang code. His point of comparison was Java or, to be less specific, languages/platforms that support the Object Oriented paradigm.
The ways in which an object oriented language/platform facilitates change are many, but perhaps the best known of these is polymorphism. The ability to change behaviour at runtime by supplying an invocation target which shares a common, base interface, but overrides the target function with its own implementation: this “ability” is not unique to OO platforms at all. The mechanism used by languages such as C++, Java and .NET varies a little, but the terminology does not. In a langauge that uses manifest typing, such virtual resolution of an invocation target, relies on a mechnism known as dynamic binding (sometimes also called dynamic dispatch). Functional languages are not without support for changing their invocation targets at runtime, but in general, use a different
set of mechanics to do so. The strongly typed, non-strict, functional programming langauge Haskell, for example, has full support for polymorphic types and functions, but the mechanics of polymorphism are wildly different to those used by imperative languages.
Another set of langauges also support polymorphism, without the use of parameterized types and type constraints found in Haskell and minus the implementation and/or interface inheritance requirements of C++, Java and the .NET family of languages. These dynamically typed languages include Python,
Ruby, and Perl, to name but a few. Such langauges support the kind of ad-hoc polymorphism found in other imperative, Object Oriented langauges. It is both to this family of langauges, as well as the family of functional programming langauges, that Erlang belongs.
Erlang does support polymorphism, as do most other functional languages. Erlang is not strongly typed, it is dynamically typed; In this respect, Erlang is unlike the Algol familiy of langauges to which Java and C# belong. This difference is not as apparent as Erlang’s functional heritage, but can be just as conceptually tricky to understand if you have little or no background in dynamic languages.
The root of dispatch in dynamically typed langauges isn’t based on the ‘class’ of a reference, but rather on the target site’s responding to the message being passed; A concept sometimes called duck typing. Because Erlang’s type system is not rooted in the mechanics of classification and implementation inheritance, it is sometimes difficult to see that duck typing is there, just beneath the surface. Erlang’s lack of static typing means that this kind of late binding is ubiquitous. There are some esoteric examples such as message passing between processes (selective receive being a weak – and one sided – interface contract of sorts) and parameterised modules (which are good for building modules that act like functors). Besides these however, the simple case of stashing a module name in a variable will suffice to prove this point:
run(Thing, Mod) -> Mod:run(Thing).