2011-10-20

Adding "Invalid" value to enumeration

Please don't do that:

    enum TrafficLightColor
    {
        red,
        yellow,
        green,
        invalid
    };

You've just artificially extended domain for every function that wants to operate on TrafficLightColor. Now everywhere we need to do stupid things:

    uint32_t toRgb(TrafficLightColor c)
    {
        switch(c)
        {
        case red: return 0x00FF0000;
        case yellow: return 0x0000FF00;
        case green: return 0x000000FF;
        default:
            assert(false);
            return 0xFFFFFFFF;
        }
    }

But why would one pass "invalid" to this function? Wouldn't it be clear if red, yellow, and green are the only possible values, and thus function just never fails?

I assume that generally the less values has function domain, the better.

The first reason why enums got this stupid "invalids", "unknowns" etc. is that somewhere in the code we convert from integer to enumeration.

    TrafficLightColor fromInteger(uint32_t n)
    {
        switch (n)
        {
        case 0: return red;
        case 1: return yellow;
        case 2: return green;
        default: return invalid;
        }
    }

That is the place where you should fail loudly on incorrect integer -- in conversion function! Either with firing an assert of with throwing an exception (depends on many factors).

The second one is that there is a code that wants to know about number of elements in enumeration, and we actually want to use it in the following manner:


    enum TrafficLightColor
    {
        red,
        yellow,
        green,
        invalid,
        number_of_element = invalid + 1
    };
   
    for (TrafficLightColor c = red; c < number_of_elements; ++c)
       ...

Don't do that either. Just make up something like

    enum TrafficLightColor
    {
        red,
        yellow,
        green
    };
    
    static uint32_t const number_of_elements = green + 1;

Don't bother too much that you'll need to change this constant every time you change enum: all clients that use TrafficLightColor needed to be recompiled anyway.

You want your compiler to complain about cases in switch statements that don't cover some enumeration values. And you should fail on enum construction time, not when enum is actually used.