Summary
Jim Coplien now has a teaching job, but he's saying that it's about time we get rid of classes. Here's my take on why he may just be on to something.
Advertisement
James Coplien, the guy who got everyone talking about Idioms in C++, has now started blogging. He's got this extremely long piece on how to teach object orientation and he's got a pretty radical conclusion. He's saying its high time to get rid of classes!
No, he doesn't want to make his own teaching job obsolete. What he's talking about is about the concept of classes in Object Oriented Design (OOD). He writes about OOD from the perspective of teaching a course, however just like everything he's previously written, there's so much hidden gems that needs serious parsing to excavate.
He speaks about some conceptual difficulties with class based modeling:
But when we combine a hierarchy of related classes under a common construct that groups them together, we too often just use the concept of "class" again. The problem is that it's not a class any more: it's not a single structure that captures the structure of all the objects of all the classes being grouped together. Making this level of abstraction into a class discards the information that the resulting entity stands in for a larger number of classes in the subtending inheritance graph.
He talks about interfaces and why they are more about objects than classes:
The first is that roles are more about objects than they are about classes. A class is a total classification of objects. Rather than thinking of a role as a partical interface to some class, it might be better to think of it as a partial classification of a set of objects.
the fallacy of modeling the world using a single perspective:
Second, because they are not total classifications roles break down the tyrrany of hierarchy. That is a better match for the real world. When God created the world, she did not create it as a hierarchy of classes. She may not even have created it, as Kant might insist, from a universe of discrete, identifiable objects. Roles provide the freedom to define a software reality that can align with a myriad of important design perspectives that range from the marketing view to the structural view.
and the synergy between roles and use cases:
Third, because roles are closer to objects, they are closer to the structure of Use Cases than classes are. Objects are run-time animals, and the role interface to an object reflects a set of responsibilities related more by some function than by any structural consideration. Yet as partial classifications, roles can also bridge the gap to the structural world. This is perhaps the most powerful contribution of roles: as a locus for the intersection of structure and function.
Many readers however might think that he's just babbling along, however I've dug up some hard evidence that should lead to the death penalty for classes:
Exhibit A. Component Models.Component models aren't class based, they are object based. When you bring up a java bean in a palette and customize its properties you are essentially modifying an object instance. The way to add new functionality is to attach an event handler to the instance.
Exhibit B. Multiple Viewpoints. An illustrative explanation of this can be found in the OpenCyc documentation "Why use logic?". In fact, anybody who has worked with OODBMS will realize the difficulty in fixed hierarchies.
Exhibit C. Conceptual Impedance Mismatch. It's never clear what delineates a class and an object. All to often its conceptually more precise to represent a class as an object. In fact, Ralph Johnson's Adaptive Object Model architecural style points to modeling of objects in terms of objects.
Exhibit D. Dynamic models. Dynamic models are instance based, for example dynamic inheritance is implemented via delegation which is instance based. James Gosling, if only he could find a good solution, would have thrown out class inheritance all together. Also, AOP should be done at the object level and not at the class level as many are proposing. "Fluid AOP" takes the right approach of binding aspects at the instance level and not at the class level.
So, James Coplien appears to be on the right track when he says "This perspective combines a small number of fundamental concepts into a consistent, integrated picture of the fundamentals of object orientation".
Finally, one last question I've got to ask, if roles (i.e. Interfaces) are so important, then why aren't they also objects? Curiously, the only project I've heard about that treats interfaces as objects is PyProtocols.
It's fine to want to get rid of classes, but then we have to figure out what we are going to replace them with. Why replace them with anything?
Imagine a system where each object had its own methods and data. In class-based languages objects don't really have methods, they contain data but they delegate method calls to their class. So, in a way, classes are a way to reduce duplication. Instead of changing the text of a hundred duplicated methods on each of a hundred objects, you can change one method in one place and all of the objects will feel that change.
So, classes are good for something, and if you don't have them you have to invent something like them. The nice thing about prototype-based languages is that you can make your own mechanisms in many cases. I often wonder what Ruby would be like if it didn't have classes. It has the features to go nearly classless.
I really like the idea of protoype-based languages and I think there is some future in them. The best book I've seen on the topic is: Prototype-Based Programming: Concepts, Languages and Applications. Edited by James Noble et al. It is really a collection of papers but they cover many of the possible approaches in the class-less design space very well. Well worth a look.
If anyone is interested in prototypes they should get the book before it goes out of print. I can't imagine it is doing very well next to Al Franken and Ann Coulter.
Interesting piece. Regarding Coplien's arguments, I think his terminology is somewhat too closely aligned with existing OO language implementations. A class is a total classification of objects only in languages where class membership is an asserted property of the object itself. The assertion is made at the time of object creation by calling a constructor. And interfaces, at least as defined in Java, do not alleviate this "problem" because objects get their interfaces only via their class membership and are thus asserted as well. The class implements the interface, not the object. Thus in OO languages we use classes as templates for objects that further on stay connected to this template.
You have a completely different situation when you differentiate between asserted class membership and inferred class membership. For example you could define the class OverdrawnBankAccount as all instances of BankAccount that have a balance < 0. It would't make sense to assert the membership of any object to this class at the time of object creation. The membership can only be inferred by looking at the balance at some point in time.
I think it is also not useful to equate interface with role. A role is something that an individual (object) takes on at some time possibly without itself knowing about it (that is without a reference from the object to the role). It is not something that is an inherent part of the object itself from its creation to its destructrion.
Good conclusion! I thought classes are wrong somehow for a long time, too.
Nevertheless I'm not that sure anymore. I now think not classes as a "technical" thing are the problem. They just give us the possibility to encapsulate, group methode, do polymorphism and so on.
I think what is wrong is how we use them. Grouping methods can't be a bad thing, but doing OOA/D with them the way we do is wrong. Modelling the real world with all it's dynamic aspects (roles...) in a class hierarchy can't do it justice. Somebody (I forgot who) once called this an aristotical modell which hits the nail IMHO. You can't press the world in one hierarchy.
Therefore I think we can/should (?) continue using classes, but we should use them in a different way: Eg. of course you could introduce a class "Person" and derive an "Employee" from this class. But that is modell is plain wrong. Employee is a role which can be a class but it is not an "is a" relationship.
> I think what is wrong is how we use them. Grouping > methods > can't be a bad thing, but doing OOA/D with them the way > we do is wrong. Modelling the real world with all it's > dynamic aspects (roles...) in a class hierarchy can't do > it justice. Somebody (I forgot who) once called this an > aristotical modell which hits the nail IMHO. You can't > press the world in one hierarchy. > > Therefore I think we can/should (?) continue using > classes, > but we should use them in a different way: Eg. of course > you > could introduce a class "Person" and derive an "Employee" > from this class. But that is modell is plain wrong. > Employee is a role which can be a class but it is not an > "is a" relationship. > > What do you think?
I don't want to get off on a rant here, but..
I think that I'm, again, ready to throttle people who teach the idea that inheritance hierarchies map to generalization taxonomies and classes model the real world.
It's getting better because there are a lot good libraries out there as examples, but this idea that we are modeling the real world has caused an incredible amount of grief in the industry.
I suspect that it came about because an OO model can look like a "knowledge representation" or "conceptual" model. If you came from databases or AI when OO came along it looked like all of your skill and assumptions were transferrable.
In my experience, you can end up with designs that look very much like the role-based approaches by treating classes as pieces of software subject to cohesion and coupling concerns, and paying attention to the single-responsibility and Liskov substitution principles.
> I think that I'm, again, ready to throttle people who > teach the idea that inheritance hierarchies map to > generalization taxonomies and classes model the real > world. > > It's getting better because there are a lot good libraries > out there as examples, but this idea that we are modeling > the real world has caused an incredible amount of grief in > the industry. > > I suspect that it came about because an OO model can look > like a "knowledge representation" or "conceptual" model. > If you came from databases or AI when OO came along it > looked like all of your skill and assumptions were > transferrable. > > In my experience, you can end up with designs that look > very much like the role-based approaches by treating > classes as pieces of software subject to cohesion and > coupling concerns, and paying attention to the > single-responsibility and Liskov substitution principles.
That's exactly how I think about it! Nevertheless I think we are a small minority right now ;-( Even almost any OOA/D book I know preaches the "OO as a mapping of the real world" approach.
Coplien mentions Trygve Reenskaug's book Working with Objects. Reenskaug is a Smalltalk developer and his emphasis on Roles matches the idea of informal protocols pretty well.
The Problem(tm) with the current crop of statically typed pseudo-OO languages like C++ and Java is the unfortunate binding of Type to Protocol and the compile time enforcement of Type as Protocol in determining substitutability.
Because these concepts (which are actually orthogonal) are tightly bound, they are often confused by novices. This has done great damage to the collective consciousness of software developers and resulted in the just the problems Coplien is railing about. The unnatural implementation constraints leak into and warp the design process.
Frankly I'd say its time to get back to the basics of what OO is really about and purge the static typing practice from our tools. More and more evidence shows that typing errors in dynamic languages are easily caught in casual development with the rest showing up in the most elementary unit tests.
JavaScript is kind of a paradox in this respect. It has all these nifty and flexible features, but it is still a really pain to work with. For a while, I was using JScript a lot and I found that it just took an inordinate amount of work and time to create complete, robust solutions. It is still handy for web page stuff, but I don't use it for system scripting any more.
In almost every other language that supports object-oriented programming (Lisp, Smalltalk, Java, Python, Ruby, Perl, Objective C, and ECMAScript, to name a few) they are.
Also, it is a fairly wide-spread convention to use interfaces as objects in Python. Zope (http://www.zope.org) does it. Twisted (http://www.twistedmatrix.com) does it. PyProtocols enhances the convention somewhat as it attempts to unify all these approaches, and PEAK (http://peak.telecommunity.com/) builds upon it.
The reason that these approaches are not more popular is that the amount of indirection that aspect-oriented programming involves is fairly difficult to understand. Even experienced programmers without experience with an interface-based approach can get very confused.
When educating novice programmers, it can be helpful to present a vastly simplified view of the world, and a hierarchy is just that: vastly (over)simplified.
"[JS] has all these nifty and flexible features, but it is still a really pain to work with. [...] I don't use it for system scripting any more."
I have two problems with JS, and they both come down to the object hierarchy: first, the browser object hierarchy is pretty random and ad-hoc; and second, there's not a really extensive library for anything but browsers.
The latter is why I haven't tried using it for system scripting. Is that where you had problems, or is there something deeper I should be watching out for?