In picking Stepstone's Objective C as a key element in the NeXT development platform, Jobs and company made what had to be a tough choice. It's the kind of choice that will mean more as time goes on: It's what one writer calls a wye.
By wyes, novelist John Barth means those choice points in people's lives, roads taken or not, that lead to someplace very different from the alternate routes. The letter Y is used as a metaphor for significant choice points. That's what this column is about: the wyes of object-oriented programming. Some of these represent choices among products, some are just bullets on feature lists, and none is as widely discussed as it should be, at least if you believe Chuck Duff of The Whitewater Group.
I talked with Duff and Digitalk's Jim Anderson, developers, respectively, of Actor and Smalltalk/V, and both exponents of a "pure" approach to object-oriented programming. What follows is based on their experiences and perspectives out on their branches of the various OOP wyes. It is not an objective, balanced view of the choices a programmer faces, but rather a look at the choices two programmers made, and how they came to make them.
NeXT sidestepped the pure object-oriented approach exemplified by Smalltalk and Actor, and opted for a hybrid approach to object-oriented programming. There are compelling reasons for taking the branch NeXT took, as there are compelling reasons for following the purer path. (This use of the word "pure" is intended to be nonjudgmental and relative. Imagine quotes around the word wherever it appears.) But the paths do seem to be divergent, and the choice of whether to build on a pure object-oriented model or to employ object-oriented extensions to a familiar language model will take the chooser to radically different places. "Where Smalltalk and Actor came from is one world, and this is really an entirely different world," Duff says.
Although NeXT chose Objective C, it's another C-based object-oriented system --C++ --that is getting the bulk of the attention just now. And although Bjarne Stroustrup developed C++ from Simula, the same root from which all object-oriented languages grew, it is a fundamentally different approach from the Smalltalk model (as is Objective C). Stroustrup is explicit about his intentions in developing C++, and they include efficiency and compatibility with C. C++ is an extension of C, and as such permits programming style that is more procedural than object-oriented; it's this mixing of metaphors, more than any particular missing features, that seems to disturb the purists.
From the pure object-oriented programming branch, this approach of extending C in an object-oriented direction looks at best quaint and at worst wrong-headed. Anderson expresses what seems like genuine puzzlement at the NeXT decision, and Duff clearly sees C++ as a sell-out of the paradigm, popular only because of AT&T and its visibility in the public domain. "From my point of view," Duff says, "it really compromises a lot of the benefits of object-oriented programming."
Jim Anderson agrees. He sees one of the main benefits of object-oriented programming is that the solution is close to the problem. "You don't lose sight of your problem in the solution; in fact, you develop an increased understanding in the system you create." That benefit, he thinks, requires an unadulterated paradigm. Of Digitalk's customer base, he says, "We know that the nonprofessional programmer, the scientist, the doctor is a common customer. Programming isn't his job; he needs results quickly, and (appreciates) the solution being close to the problem, which I think Smalltalk gives you. But we're also getting a lot of programmers, because they're getting bloody noses with C or even with C++."
Duff and Anderson, of course, have axes to grind: They are selling products that lie on the other arm of the wye. But unlike most programmers, Duff has been down both branches. When he talks about C++, he's seeing it in the light of Neon. As he tells the story:
"My initial focus was on Forth. (When) I was at Kriya Systems, I was the author of Typing Tutor, and I had to write Typing Tutor for the Macintosh. Forth, as an extensible language, was not really working, in my view, because the extensibility was just too powerful. I was intrigued by the Smalltalk books, and that seemed to represent a situation in which you could channel the extensibility into a more pragmatic framework. If you extended the system (and I extended) the system, we could probably understand each other's extensions, because there was this consistent technology for doing it."
His researches into object-oriented programming and his background in Forth led to Neon: "Neon was an object-oriented extension to Forth, but it was a hybrid language in that you still had Forth around and you could still blow yourself out of the water any time you wanted to and completely corrupt the object metaphor. My focus in Neon was on making Smalltalk practical, because at that time there was no Smalltalk that was really useful on a personal computer; in fact I think Neon was the first object-oriented language that was commercially available for a personal computer."
Neon, however, failed to take the world by storm, and Duff himself had some second thoughts about the approach. After the Neon experience, he was convinced that a pure object-oriented model was better, if it could be achieved without compromising efficiency. In the hybrid approach, he saw too many ways for the base language to collide with the object model. It was appealing to envision a language in which even the basic syntactical constructs would be constructed according to the messaging paradigm. That appeal, and some frustration with Smalltalk as it existed then, led Duff to develop Actor.
Today, there are several pure object-oriented languages available on personal computers but surprisingly little direct comparison of these products with one another or with the hybrids. Although an advertisement for Interactive Software Engineering's pure object-oriented programming language Eiffel does a feature-list comparison with C++, you won't find many comparative reviews. (That ad also adds insult to injury by quoting Stroustrup repeatedly on object-oriented features that C++ lacks.) Duff thinks that the reason we don't see much direct comparison of the hybrid vs the pure implementations is that the two approaches are seen as incommensurable: "Right now, it's just sort of parallel evolutionary paths."
"C++ has an immense amount of support, but a lot of it is (from) C programmers, to (whom) it's just a better C. They don't have anything to compare it to." Some C vendors pitch C++ as precisely a better C, scarcely mentioning its object-oriented nature in their ads.
Duff wants to see the hard questions asked in print. "Eventually what's going to have to happen is that we're going to have to say, 'What is this technology about? What are the benefits that we're looking for? And what language features have to be there to provide those benefits?' We have to look behind the scenes, and that's not happening right now. We're going to have to take a hard look at what we want the technology to do for us, what compromises we're willing to make in the language to accomplish that."
The key to the object-oriented paradigm is inheritance. It's what delivers the benefits, and it's the essence of the choice to OOP or not to OOP, Duff believes. Anderson sees reusability as its greatest benefit: It buys the programmer reusability by factoring out the general, the abstractions, and letting general solutions be specialized.
It was precisely the quest for reusability that initially turned Anderson on to object-oriented programming. If Duff found his path only after following a Forth thread, Anderson's enlightenment came from watching the world's biggest software company fail and realizing that he knew where it had gone wrong.
Anderson was working for Computer Science Corp. when it got a contract with Basic 4 Corp. Basic 4 was selling a business minicomputer with a very good Business Basic and getting a lot of similar jobs: to do an accounting system for a bakery, to do an accounting system for a trucking company, and so on. Basic 4 had tried contracting the development out to individual consultants but wasn't happy with the result, when they hit upon the idea of contracting with CSC to do a general accounting system that could be tweaked for the particular applications.
CSC found itself unable to reuse the software in going from job to job. "It was just too much of a mess to snip out the pieces, the common stuff that could be used for all." As it was becoming clear that the project was not working out, Jim Anderson, working in another branch of CSC, was reading the 1981 Byte issue on Smalltalk and making connections.
"That was one of the things that I saw in Smalltalk: the reusability because of inheritance. Basic doesn't have much structure. What you need is to look at the similarities and the differences. The similarities are the abstractions, and the general things that apply to all, and the differences are the specializations in subclasses. Basic just doesn't give any help in that area."
CSC's problem in creating a generalized accounting system ultimately led Anderson and George Bosworth to start Digitalk and to develop a Smalltalk implementation for the PC and now for the Mac. "I haven't been able to go back and solve that problem, but I can certainly envision having multiple applications in Smalltalk: abstract accounts receivable, then Trucker's accounts receivable, and so on, all in there at once."
Duff points to the granularity of reusable code that inheritance provides. "You can isolate a smaller section of code that is more likely to be reusable as a unit than if it were five or ten times its size. As size increases, the likelihood of reusability goes down, because the more functionality there is, the more likely it is that it'll be inconsistent with future uses."
In fact, Duff finds that the object-oriented style seems naturally to lead programmers to break functionality down into small pieces. That's a value that rings true for Duff, an old Forth coder. One of Chuck Moore's rules of Forth programming is that no Forth word should be longer than two or three lines. "In a sense I've found the same thing to be true in Actor: that short methods and short classes and a larger number of smaller classes is usually a better situation because it gives you that granularity where you can pick and choose what you want to reuse."
But inheritance supplies a level of quality or reliability to the reusable code that, Duff argues, would not be there otherwise. "If I develop a library and I give it to you and you need it to work a little bit differently, you start to edit my code. There is a portion that we share, but it's no longer cleanly delineated from what I initially wrote. This means that we now have two separate maintenance problems. I can no longer simply give you a bugfix for you to blindly apply to your code, because you might have changed it. That problem is made much less severe by inheritance, because we can agree that you don't edit my code; you override pieces of it. Then I can give you updates and it's not going to compromise your system."
Inheritance is also what makes object-oriented programming hard for many programmers to adapt to. Novices seem to have less trouble, suggesting that it's an unlearning, rather than a learning problem. At Carlton University in Ottowa, they now use Smalltalk in the Introduction to Programming course in the computer science department. They've progressed: A few years ago it was being used only in a graduate AI course, and last year it was introduced in a second-year data structures class. But there is, as Anderson puts it, "definitely a weirdness factor."
"One of my problems in learning Smalltalk," he confesses, "was that I wanted to translate it into something familiar. I was constantly fighting the ideas. Nonprogrammers don't have to make this kind of translation all the time, so I think they accept it more quickly."
And the weirdness factor hits immediately, as you are approaching the problem, conceptualizing, analyzing, not thinking about code yet. Anderson again: "I can remember programming in Pascal, approaching a problem, and the first thought would be: 'OK, what kind of record structures do I need to define for this problem?' It's starting to go into Smalltalk and approach a new problem and the question is, 'OK, what kind of (preexisting) collections do I use for this problem?' You don't start by defining something new but by reusing something that exists."
Multiple inheritance means the possibility of belonging to two different classes at once, neither of which is a subclass of the other. It's a deviation from a strict tree-structured arrangement of classes, such as the Linnean classification of organisms. In the real world, objects belong to different classes. Some object-oriented systems have multiple inheritance, most don't.
Neither The Whitewater Group's Actor nor Duff's Smalltalk supports multiple inheritance, but both companies are looking into the technique. When a customer asks about multiple inheritance, the companies ask what the customer has in mind to do with it.
Duff says that the customers usually haven't thought about it very much. "It's a bullet on a features list," he says. "The people who have thought about it know it's fraught with pitfalls."
What are these pitfalls of multiple inheritance? Well, it's naive to think that you can combine an A and a B to come up with a meaningful AB. A and B typically will have similar but not quite identical properties that collide with each other. Consider the case of two multiply inherited classes with instance variables having the same name. Each may want to preserve its own copy of that instance variable, or they may want to share it. There are equally valid cases of each kind. When faced with these collisions, you have to decide what to do about them; specifically, you have to establish a collisions-resolving philosophy. Do you just employ an arbitrary rule? That really isn't good enough. Do you ask the programmer on a case-by-case basis to make the resolution? Do you develop a collision-resolving expert system? It's not a simple matter.
"It's things like this that have kept us from approaching multiple inheritance until just recently," Duff says. Anderson can think immediately of one instance in the design of his Smalltalk system when multiple inheritance would have come in handy. "It's nice to have a lot of things (that are not descendants of the stream class) that act like streams." He managed to get the effect of multiple inheritance without the structure, but "if we had had multiple inheritance we would have used it there." But would the costs in complexity that multiple inheritance brings with it have justified the convenience that would have been gained in this case? Anderson doubts it.
Duff says you have to weigh these costs in designing a language. "You have to say, 'Is the productivity benefit there? Are they spending more time in the multiple inheritance technology than they would have just getting around it with single inheritance?'" The Whitewater Group regularly teaches programmers how to simulate multiple inheritance in a single inheritance system. In a single inheritance environment, you can achieve multiple inheritance by adding the classes that you want to inherit from as components or instance variables and then using those components of the object as sort of experts to fill in that domain of behavior. Then you just pass through the protocol of those objects to the outside by introducing methods in the class. It works.
The approach suggests a broad design principle for object-oriented programming, and it applies particularly strongly to multiple inheritance. Duff says that his people have found that it's possible to overuse inheritance. "In general, it's better to err in the direction of encapsulating too much, in other words including something as an instance variable instead of inheriting from it, because it's very likely that you might inherit inappropriate behavior."
Inherit inappropriate behavior? Here's what he has in mind: "You want to create something that holds a collection of other things, let's say a picture class that holds a collection of graphical objects. One way to do that is to make it a descendant of one of the collection classes, like Array. A picture is an array, only it's a special kind of array. The problem is, you may want a picture that can have a dictionary instead of an array as its collection. Also, there are many things that are appropriate for arrays that are not appropriate for pictures. You end up having to circumvent a lot of inappropriate inherited behavior."
Multiple inheritance exacerbates the problem because with multiple inheritance you have not just one but many classes from which you need to filter out inappropriate behavior, in addition to resolving the redundancies. But Actor is likely to support multiple inheritance before long.
"The direction that I'm heading," Duff explains, "is decoupling inheritance of protocol --or methods --from inheritance of representation --or instance variables. One way to do that is to be able to group a piece of code into a thing that's like a class, except that it doesn't specify any representation. It's just a set of methods that, since they don't refer to instance variables, can be generically inherited. You can then say, in addition to the class that I inherit from, I also inherit these protocols that allow me to behave like an object of this virtual type --virtual (in that) you're not specifying anything about its representation. It simplifies a lot of these resolution problems. You don't have to worry about instance variables; you can just deal at the level of what functionality I inherit."
And it's really not accurate for me to say that Digitalk doesn't support multiple inheritance; it's there in the company's Smalltalk products. It's just not visible. "In ST/VB-286 and the Mac product," Anderson says, "we have actually implemented the mechanism for multiple inheritance, but we don't have a (supporting) user interface. We don't know how to present it to the user." The user interface is an area of active research at Digitalk, and Anderson feels that the company was really founded to make object-oriented programming accessible. Accessibility means a lucid user interface, he believes. If and when they figure out how to present the technique so that it doesn't complicate the programmer's life too much, they will no doubt implement multiple inheritance for real. If and when they do, the solution is likely to involve context, a concept that Digitalk programmers are currently exploring avidly.
From the point of view of putting valuable functionality in the programmer's hands, it's good that Digitalk and The Whitewater Group are moving toward multiple inheritance, because there are real benefits in having multiple inheritance: The real world has multiple inheritance, and if you want to simulate aspects of the real world, should you try to get along without this natural technique? On the other hand, the programmer has to decide if it is worth the hassle. It's really not a trivial choice for the language designer or for the programmer.
As Jim Anderson says, "It's definitely a controversial topic."
Copyright © 1989, Dr. Dobb's JournalPure vs Hybrid OOP
Inheritance vs Flat Programming
Multiple Inheritance vs Single Inheritance