Programming

Wednesday, January 10, 2007

Never use built in types

This sounds really daft, but it is not. A lot of programmer errors are caused by confusion about values. For example, assigning an address to a name. Was the value in minutes or seconds? To make matters worse, C++ actually encourages implicit conversion between types, and the programmer needs to go out of his/her way to make constructors explicit to prevent this conversion.

Another problem is documentation. If a function takes an "int", there is little clue about the semantics of the value. The meaning must be elaborated in the function name, parameter name or documentation.

A large class of error is caused by programmers passing the wrong kind of value.

Another problem is the premature commitment and viscosity (to use CD terms) of one particular build-in type. Suppose you write an application to use char, then realise that you really wanted a wchar_t. You would need to change every instance. Not a problem but a hassle.

The solution
You would think that using a typedef would aleviate some of these problems. e.g.
typedef int seconds;
typedef int minutes;
This helps a lot but does not prevent mistakes when converting between the two. So you create a class

class Seconds
{
public:
explicit Seconds(int value);
int operator*() const;
};

This is fine but is a lot of work to introduce a new type. Instead I propose to tag each value with a type, as follows
template
class tag_t
{
public:
explicit tag_t(const Prim value &= Prim() ) : m_value(value) { }
template
tag_t(const tag_t &v) : m_value(*t) { }
const Primitive &operator*() const { return m_value; }
private:
Primitive m_value;
}


template tag_t tag(const Prim &p)
{
return tag_t(p);
}

Examples
struct SecondsTag; struct MinutesTag;

void setTime(tag_t mins,
tag_t secs);

setTime(tag(12), tag(0) );
Next
This is turning into a units library. We should see how we can extend this basic implementation to deal with multiples and conversions.