ACCU Home page ACCU Conference Page
Search Contact us ACCU at Flickr ACCU at GitHib ACCU at Facebook ACCU at Linked-in ACCU at Twitter Skip Navigation

pinMicro-Derivation & Related Ideas

Overload Journal #32 - Jun 1999 + Programming Topics   Author: the Harpist

I have been very busy these last few weeks and have not had time to think about what I might write for Overload. I know what pressure there is on editors and how much they rely on the regular contributors coming up with something for each issue. Of course, as Francis frequently comments, there would not be so much pressure if there was a steady flow of material from elsewhere. Fiction magazines normally have large slush piles on which they can draw for the fillers they need to complete an issue. That gives new writers a chance as well as guaranteeing the readers a regular mix of old and new talent.

I had just about decided, reluctantly, to give this issue a miss when Francis asked me to look at some ideas he was playing with. What follows leans heavily on his ideas and is entirely speculative. In other words I have not had time to test even a line of code let alone explore how the ideas might work in detail. I hope, that you, the reader will explore some of these ideas and feed back your experiences, both good and bad.

Micro-Derivation

This is a term that I have coined to refer to using derivation to add some small extra to a class while leaving the class functionally as it was before. I think this is best illustrated by a simple example.

Have you ever wanted to have a simple array of objects only to discover the class owner has decided not to support a default constructor? Well if you never have, you have been lucky. Look at the following:

class HisObject {
  < no default constructor available>
};

int main(){
  HisObject objects[10];
  // other code
}

Of course your compiler refuses to compile this. In this circumstance you can just about manage by providing explicit initialisation such as:

HisObject objects[10] = {
  HisObject(<suitable data>),
  HisObject(<suitable data>),
  HisObject(<suitable data>), 
  // etc. for 10 instances
};

However that would be intolerable if you had a large array and in some circumstances (array member of a class) it is impossible.

Maybe you are wondering why I do not use an STL type container instead. There are several reasons why I might choose an old style array. For example I might need the efficiency that these guarantee. I might also have difficulty if the HisObject class lacks strict copy semantics. In this case it might have had copying inhibited (I will visit that shortly) or it might actually have had some semantic aspect of copying perverted (see auto_ptr). Either of these two cases means that STL containers are dangerous.

So instead I use micro-derivation:

class MyObject : public HisObject {
public:
  MyObject();
};

The first reaction from experienced programmers is that the original class designer probably had a good reason for not providing a default constructor. I entirely agree. However a good reason in general might not be relevant in the context of my program. The only feature I am adding is the ability to create default instances. Naturally I must ensure that such can be used effectively.

Some questions that will spring to mind is to ask 'Why public derivation? Why not either private derivation or layering?' My answer is that I want MyObject instances to be exactly what HisObject instances are with the solitary exception that they can be created by default. I am completely happy for MyObject instances to substitute for HisObject ones.

There is one tiny irritant, everything will work as I expect once the object has been created, but HisObject must have some constructors and these are not inherited. That means that I must add 'forwarding' constructors in addition to my default constructor. For example, suppose that HisObject has a constructor HisObject (int), now I must add:

MyObject(int i):HisObject(i){};

to my class interface. It would have been nice if I could have written:

using HisObject;

to mean that I wanted MyObject to have constructors that did no more than call equivalent HisObject constructors. As it is I have to implement this by hand. Perhaps a good idea as it should make me think about what I am doing.

The idea of deriving to add just one feature is quite powerful. We can take a pure object class (no public copy semantics) and convert it into a value class as long as we can code a copy process. [Note from Francis: indeed and this is the subject of a forthcoming column of mine in EXE Magazine].

I am going to leave this at this stage and invite readers to come up with other instances where micro-derivation is useful. Note that I apply the term precisely to the case where you wish to add one (or possible more) features to a class which otherwise must behave exactly as it did before. Adding some form of constructor is the most likely extra.

Related Ideas

I suppose that you might call the next idea micro-layering. I first came across the idea when Francis was discussing ways of providing user defined types that behaved like built-in ones. In a sense enums do this for integer types. For example:

enum Int {
  min_value=INT_MIN,
  max_value=INT_MAX
};

creates a type that has almost all the functionality of an int. Unfortunately it lacks any implicit inward conversions. Int values will convert to int ones implicitly but to go the other way you must make the conversion explicit with a cast. So try this instead:

class Int {
  int value_m;
public:
  Int(int v=0): value_m(v) {}
  operator int () {return value_m;}
};

I have deliberately not qualified the constructor as explicit because I want me Int type to behave as like the built-in type as possible. Once I have a UDT with int functionality I can derive from it, add constraints (for example declare a private operator*() and operator/() etc.

I wonder what weaknesses there maybe in this idea. Certainly I can think of several advantages. For example define:

class Double {
  double value_m;
public:
  Double(int v=0): value_m(v) {}
  operator double () {return value_m;}
};

There is no implicit conversion between Double and Int because that would require two user-defined conversions (one conversion operator and one constructor).

Our UDTs can work where-ever built-in values are required but will not satisfy a pointer to built-in type nor a non-const reference to a built-in type.

An Alternative to Micro-Derivation

Let me finish be revisiting my problem with HisObject. If you are unhappy with using derivation you could try this instead:

class MyObject {
  HisObject obj_m;
  static const HisObject def_s;
public:
  MyObject(HisObject data = def)
    : obj_m(data) {}
  operator HisObject () { return obj_m;}
};
HisObject MyObject::def_s(
  <data for construction> );

This assumes that a copy constructor is available for HisObject.

I leave it to readers to provide a comparison between micro-derivation and micro-layering as a mechanism for adding functionality. One difference is that micro-layering consumes the permitted explicit user-defined conversion whereas micro-derivation doesn't.

One of the things that I have become increasingly aware of is the potential that very small classes have for fixing coding problems. I wonder what other ideas readers have for useful class techniques that require less than a dozen lines of class interface?

Overload Journal #32 - Jun 1999 + Programming Topics