topnav
masthead

Series Info...#2: Simple Inheritance

by Richard Bartle
September 20, 2001

Why is inheritance important in MUDs?

Let’s say you have a brand – a piece of wood with pitch or something at one end that you can set fire to and use as a torch so as to see in places where there isn’t any natural light. As a coder, you can build the necessary functionality so that LIGHT BRAND causes the brand to burst into flames (emitting light) and DOUSE BRAND extinguishes the flame (handy if you’re going where a naked flame would cause an explosion). You can add a few more bells and whistles, and the result is a fully functioning brand.

Now suppose you wanted another 20 of them.

Well yes, you could simply cut and paste another 20, but then if you wanted to change the functionality of brands you’d have to alter all 20 definitions. What you really would like is to have a template for a generic "brand" and to be able to print 20 individual brands directly from it. Each of these reproductions would be a brand in its own right, but all its functionality would come from the single definition you gave for the template. In other words, each "brand" copy inherits from the "brand" template.

In programming parlance, the template is a class and each entity stamped out from it is a class instance (or just instance). Class instances are also known as objects. The usual way to visualize this is as a tree:

diagram

Because classes are mathematically equivalent to sets, they are often said to contain their members. This doesn’t mean that the members are inside in a physical sense – you can’t walk around carrying the BRAND concept then suddenly open it up and take one out (not unless you want to freak out your players). Rather, the objects are things you come across in the game world and the classes are their definitions. You might be able to kick a ball, but you can’t kick the notion of what a ball is.

Overriding Inheritance

Objects don’t have to accept everything that the class gives them: they can selectively override it. You could, for example, have a class FLOWER that provided the functionality for PICK FLOWER, SMELL FLOWER etc., and you could then create instances of it that had their own, particular description: "You see a rose growing off to one side" rather than "You see flower1 growing off to one side". This allows for programmers to pick and choose what functionality objects inherit. Anything that is individual to an object can be defined explicitly for that object; everything else is inherited implicitly from the object’s parent (i.e. the class of which it is an instance).

What I’ve described so far is single-level inheritance, in that each class can be used to stamp out one kind of object and one kind only. MUD1 had this form of inheritance. It works up to a point, and it’s certainly efficient, but it’s not without problems.

For example, let’s say you’ve created a class HERB that contains objects such as PARSLEY, SAGE and THYME. FLOWERs smell nice, HERBs taste nice. Maybe you also have a WEED class containing THISTLE and NETTLE. WEEDs smell bad, taste bad and hurt when you try to PICK them.

Now let’s invent a goat that wanders around eating any small plant it comes across.

Ah. You’d need to define separate functions to describe what happens when the goat came across FLOWERs, HERBs and WEEDs – even though it would be the same in all cases (the goat would eat the plant in question – goats aren’t as fussy as humans).

What you need is multi-level inheritance:

diagram

This looks more like the classical tree data structure, with classes as branch points and objects as leaves. The highest-level class (SMALLPLANT) defines some functionality; the lower-level classes that are children of it define more. These child classes are derived from their parent class in that they inherit their basic functionality from it, but they also have functionality of their own and may override some of the defaults offered by their parent (e.g. PICK SMALLPLANT is not the same for WEEDs as it is for FLOWERs and HERBs).

Inheritance Trees

In practice, inheritance trees can be of arbitrary size. Classes can have any number of children (although if they have 0 then they’re an object, not a class) and therefore any number of descendents. The length of branches (from the root class of the tree to a leaf/object) is unrestricted – they don’t have to be remotely similar. Inheritance is fast and efficient, because all components (nodes) of the tree except for the root have only one parent; to find the precise point at which some piece of functionality is defined is thus a simple case of a node’s asking "Is it defined for me? If so, yay! If not, I’ll pass the query up to my parent".

Many programming languages use inheritance trees. From the point of view of MUDs, by far and away the most important one that does is C++. It forms the basis of LPMUD, and virtually all the MUDs that descend from it.

It’s therefore something of a shame that this form of inheritance is a dog, too. In my next article, I’ll explain why...

Recent Discussions on Notes from the Dawn of Time:

jump new