Caller has Custody

I recently discussed the idea of custody with Kevlin Henney. The general rule in software is the caller has custody. This is perhaps one of those things that's obvious once you realize but that until you realize it you might miss it. To take a simple example - calling a method with an argument. If the argument is a value there is no custody to worry about. But what if the argument is a pointer (or reference - something that creates a level of indirection).
void method(type * p);
Caller Has Custody is concerned with deciding who has custody for the object p points to. Who is responsible for creating/destroying that object? And the answer, clearly, is the code calling the method. It's not the method itself. Less experienced programmers (to generalize horribly) seem to be overly worried by this and, particularly in C++, have a tendency to use smart pointers to express this rather than using a simple raw pointer.

Perhaps Caller Has Custody is not quite so obvious for constructors. It's natural for a constructor to remember the information passed in via its parameters.
class eg
{
public:

    eg(type * p)
        : p(p)
    {
    }
    ...
}
Perhaps the nagging doubt with a constructor is that since a constructor creates a new object any information saved as part of the state of the object can easily persist beyond the duration of the constructor call itself. Perhaps that's why (again to generalize horribly) less experienced programmers seem to want to copy/clone the argument - that way the callee can take custody of the clone, and the newly created object becomes completely self contained; free from any lifetime dependencies on anything outside itself.
class eg
{
public:

    eg(type * p)
        : p(p ? p->clone() : 0)
    {
    }
    ...
}

This has a supercial attraction but it's not a good road to take. The right road is to take a deep breath and, just like in real life, accept the interdependent nature of things. A big part of mastering object-oriented programming is mastering the nature of the connections. We all chant the mantra low-coupling high-cohesion but rarely do we really embrace it. By definition a highly cohesive class does one thing and one thing only. It has a single defining responsibility. That implies two things: first, cohesive classes tend to be small and second, systems are composed of lots of objects. But all the objects in a system have to be connected together (if they're not then you've got more than one system). Thus an important part of designing an object is designing it's connections to other objects. Objects are never totally self contained. They always live in a larger context, and it's the larger context that gives them meaning.

No comments:

Post a Comment