ajeru1 still thinks we're being betrayed by types. I can't help thinking (s)he is mis-using typing to make a point. Particularly, the solution proposed in the first “we have been betrayed” article is just as inappropriate for these new problems as existing OO typing is. Certainly, if the thing deciding an object's state doesn't belong inside the object, then neither can the behaviour that results from that decision.
The Naming of Cats is a difficult matter,
It isn't just one of your holiday games;
You may think at first I'm as mad as a hatter
When I tell you, a cat must have THREE DIFFERENT NAMES.
—T S Eliot, The Naming of Cats
In Java at least, an object's type represents three different things:
- The messages that the object will respond to. This defines the object's interface.
- The code that the object will use to respond to these messages. This defines the object's implementation.2
- An attribute of the object, of type Class.
Sometimes, people get stuck on the third one, and give it far more importance than is really necessary. There is nothing magical about the identity of an object's class. It's just another attribute of the object. Its primary value is as a way of determining which messages we can send to an object, something that is done often enough that Java gives us the short-hand operator instanceof
instead of making us call Class.isAssignableFrom()
. However, the existance of this operator shouldn't make us feel that the class attribute as an attribute is any more or less important than any other.
As ajeru notes, when you use the class as a straight attribute, it's incredibly inflexible because an object's class is immutable. There are various patterns you can use to change the behaviour of an object at runtime, or even to provide an extensible interface, but there's no way to change the attribute-value of an object's class. Which is fine, because you are still free to add as many read/write attributes as you like to an object.
Some languages do allow you to change the type of an object at runtime, or in the case of Smalltalk's become:
, replace one object with another. This is still a terrible solution to the state-change problem, because the moment you have more than one set of states that need to be applied concurrently, you end up with a complete mess of classes.
Problems that arise from making things part of the type that shouldn't be tend to end up being “Doctor, it hurts when I do this!” problems. If the class is a bad place to store a certain bit of information about an object (i.e. whether a person is considered an adult or not), for whatever reason, then don't store it there! Your class heirarchy shouldn't correspond exactly to a real-world taxonomy; you shouldn't have every natural language is-a represented by a type in your program. That isn't the function of a class at all.
It's not the hammer's fault that you can't hammer in a screw.
1 memo to all bloggers: please put something on your weblog homepage making it clear what your name is, or at least what you would like to be referred to as. Usernames or page titles are just so impersonal.
2 For more on interface vs implementation, you might want to read my previous article, Inheritance Taxonomy