Monday, June 30, 2008

Implicit information via types / inheritance

There exists a broad class of objects in the real world called vehicles. A car is a type of vehicle. A Toyota Camry is a type of car. A 2006 Toyota Camry is a type of Toyota Camry.

These types of relationships would be easy to implement in classes, using subclassing. Class vehicle implements some really basic stuff. Class car implements some more specific stuff, and so on.

Or, you could say a car is a vehicle with the "type" attribute set to "car".


c = new vehicle;
c.type = "car";


This provides greater flexibility, but you forfeit some niceties.

For instance, the count_wheels method should return 4 for a car, and 18 for a semi. (In C++ terms, count_wheels would be a "pure virtual method" in the vehicle class, and overridden in subclasses.) If you make car be a subclass of vehicle, no conditional is needed when you call count_wheels ... the type system checks the type and calls the appropriate overridden method.


class car : vehicle { int count_wheels() { return 4; }; };
class semi : vehicle { int count_wheels() { return 18; }; };

c = new car;
s = new semi;

c.count_wheels(); // returns 4
s.count_wheels(); // returns 18


But if you make car be a vehicle with a member called "type" set to "car", you control the conditional (= greater flexibility).


class vehicle {
int type;
int count_wheels() { // conditional
if (type == "car" ) return 4;
if (type == "semi") return 18;
}
};


Of course, if you use the type system to hold the implicit info (am I a car or a semi?), then the conditional is evaluated at compile time ... so there *may* be a performance consideration, but beware of thinking this way.

So the moral is that anytime you use inheritance, you forfeit flexibility, but gain some "compiler-does-it-for-you" efficiencies. In fact, inheritance creates strong coupling between the parent class and the subclass, which is not usually a design goal! The only gain is less code (because the compiler does some stuff for you).

On a similar note, I've read some blogs where people claim that all inheritance should be replaced with composition, because composition doesn't require you to give up as much flexibility as does inheritance. So, for instance, a car is "composed of" a vehicle. The con here is you have to completely rewrite the interface for the car class. It doesn't come for free from the vehicle class like with inheritance.


inheritance -> shorter :), less flexible :( code