Sponsored Link •
Some musings about my personal history with inheritance and interfaces, solicited by the release of the Go language this week.
I am an atypical programmer, since I spent most of my career doing science, not programming. When I first learned about Object Oriented Programming, a little bit more than seven years ago, I compared it with my experience in Mathematics and Physics. I was puzzled. In Mathematics you have objects (consider for instance the elements of a Lie group) but the objects themselves are not important: the important entities are the relations about the objects, their properties. When I write a + b in a mathematical expression I am not really interested in the objects: a and b may be numbers, or matrices, or functions, or even operators in a Hilbert space if I am doing Quantum Mechanics: in any case, the important thing is the addition operation. The + means that I am performing a commutative operation and therefore that the objects I am using are part of a commutative group and a set of well know properties are valid for them. Translated into programming jargon, that idea means exactly that the important things are the interfaces, i.e. the set of operations/methods which are available to the objects, not the objects themselves. Actually, the details about what the objects really are can be disregarded as implementation artifacts and I can write generic code which works for all objects satisfying a known interface, just as in Mathematics I can write a single proof valid for the entire class of entities satisfying a given set of properties.
This was my forma mentis when I begun studying object orientation. I was used to consider functions as the primary entities, and objects as inert material on top of which functions operate. Actually, it seemed backwards to me to attach functions to (classes of) objects. In traditional (Smalltalk-inspired) OOP instead this is exactly what happens. One focuses on objects: one writes window.create(), not create(window). One is induced to put the focus on the window which owns the .create method and not on the general operation of creation which is meaningful for all kinds of objects. Anyway, I kept studying and at the end I become acquainted with the OOP approach: I was no more disturbed by window.create() vs create(window). It is ironic that a year later I discovered Lisp and its object system (CLOS) where you indeed write create(window). It is understable that I immediately became a supporter of generic functions: I decided that I was right the first time after all ;) It is also clear why I am a supporter of functional programming. Nowadays, after years of experience writing an maintaining large code bases, I am even more convinced the really important things are not the objects (or classes) but the interfaces.
During my first six months of OOP programming I also had issues with another concept: inheritance. I remember that when I saw classes for the first time I said "look ma, objects are just the same as Pascal records and methods are just functions taking a record as first argument, they are not difficult at all!". It turns out I was wrong. Classes are very much different than Pascal records, the reason being inheritance. Inheritance makes classes quite nontrivial, and I had to write a paper on inheritance to understand its gory details (my first paper about programming, the infamous MRO paper). At that point however I only understood the tecnical details; but a year later I was hired as a programmer, I started working with Zope and then I understood what inheritance really was in the real word. From that time I started looking for alternative solutions to inheritance. I remember that once (something like 4 or 5 years ago) I implemented a toy object system in Scheme without inheritance, to see how it was like to program without it. From that experiment I concluded that one cannot really avoid single inheritance (I mean, you can, but then you have to implement some workaround which is more or less equivalent to it) whereas instead you can easily throw multiple inheritance out of the window. A couple of years ago I also became interested in the language SML which I really liked for various reasons, the most important being the lack on inheritance and the presence of interfaces.
It is at that moment that I decided to start a public campaign against inheritance and pro interfaces. Interfaces are the really important idea, not inheritance, but unfortunately many languages conflate the two concepts and make things confusing. Inheritance is a (often wrong) way of ensuring interface compliance, in the sense that a subclass satifies the same interface of its superclass, but in general two objects can have the same interface without having a common base class. After studying SML I became really convinced that there should be a formal way to specify that property in the language. I also decided to write a set of articles about the dangers of inheritance: I published on Artima four papers about mixins (1, 2, 3 and 4), a paper about generic functions and a paper about traits for people still emotionally attached to the Smalltalk OOP model and not wanting to switch to the CLOS model. I also planned to write a paper about interfaces, to explain how things should be done, but I never wrote it. The main reason is lack of time, since I was busy with The Adventures of a Pythonista in Schemeland and other things; there is also a secondary reason; I needed a language with interfaces done right to explain what I had in mind, and I was reluctant to use SML as that language. I mean, SML is very nice and it does interfaces really well, but it is definitively not a language for the large public. Python has interfaces (starting from Python 2.6) which are acceptable but not really what I had in mind.
Now finally there is Go. Go is a new language which was released this week by Google; it was designed by old-timers of the caliber of Rob Pike and Ken Thompson, so I decided to take it very seriously and to have a look at it. It turns out that Go lacks inheritance and it has something similar to the kind of interfaces I had in mind for all this time. I do not need to write my paper about interfaces vs inheritance anymore: just look at Go documentation! I am still playing with Go at the moment. As every language it has a few good things and a few bad things. I particularly like two blog posts by Mark Chu-Carroll (this and that). Of course everybody is writing about Go nowadays and you can find tons of comments about the language on the net. There is also an extremely activew newsgroup. Here I just wanted to point out the design choices about interfaces and inheritance. Such ideas are not new and it is a shame that no popular language has followed such particular route in the design space. I hope Go will become popular; if not, I hope such ideas will finally enter in a popular language, we are already 10 or 20 years too late :-(
|Michele Simionato started his career as a Theoretical Physicist, working in Italy, France and the U.S. He turned to programming in 2003; since then he has been working professionally as a Python developer and now he lives in Milan, Italy. Michele is well known in the Python community for his posts in the newsgroup(s), his articles and his Open Source libraries and recipes. His interests include object oriented programming, functional programming, and in general programming metodologies that enable us to manage the complexity of modern software developement.