n2liquid's sandbox

Enum Inheritance – The Chii Programming Language

Posted on: June 30, 2011

Sometimes an enum has the same possible values as another enum, plus some new values, in a way that it could appear in the signature of an overriding method to offer additional functionality to clients knowing about the derived interface, while maintaining compatibility with the overridden method through argument covariance.

Such a scenario could be aided by using some language construct that permitted the greater enum inherit the values of another enum.

To illustrate:

enum FilterType { NEAREST_NEIGHBOR };
enum SpecialFilterType : FilterType { LINEAR, BILINEAR, BICUBIC };

FilterType f;
SpecialFilterType sf;

f = NEAREST_NEIGHBOR;
f = LINEAR;           // err; LINEAR is not part of FilterType

sf = NEAREST_NEIGHBOR;            // ok; NEAREST_NEIGHBOR is part of
                                  // SuperFilterType
f = sf;                           // err; cannot implicitly cast to
                                  // FilterType
f = dynamic_cast<FilterType>(sf); // ok; sf == NEAREST_NEIGHBOR,
                                  // which's part of FilterType

sf = LINEAR;
f = dynamic_cast<FilterType>(sf); // throws; sf == LINEAR,
                                  // which's not part of FilterType

The problem with this construct is that it can be a bit misleading. While calling this inheritance certainly makes sense (yeap, by all means, SuperFilterType inherited FilterType), this isn’t the inheritance we’re used to deal with.

Enum inheritance doesn’t create an “Is-a” relationship like class inheritance creates, nor does it create a “Has-a” relationship like object composition creates, even though it looks almost like the latter.

It’s something different that happens to make sense with very similar terminology. I’d love if I could find a better name for this so that it would be less confusing, but for now let’s leave it at that.

Although enum inheritance seems to blatantly go against Liskov’s Substitution Principle (hereafter called just LSP) – in fact, it looks like the polar opposite of it: the subtypes of T can be replaced by T, but not the contrary…? –, it doesn’t, and actually aids at creating classes that respect another important OOP principle: the Open-Closed Principle (hereafter called just OCP).

Enum inheritance doesn’t go against LSP because it actually has nothing to do with that. LSP applies to class subtyping, and, like I said, enum inheritance is not the same as class inheritance, and it is not a form of subtyping, but a slightly unusual, brand-new form of composition instead.

Let’s see how these all click together to ease OCP compliance when designing a small class hierarchy:

class Base
{
public:
    virtual ~Base() {}

    enum SampleEnum { A, B, C };

    virtual void doSomething(SampleEnum arg)
    {
        // does something with arg, which can be either A, B, or C;
        // nothing more
    }
};

class Derived : public Base
{
public:
    enum DerivedSampleEnum : Base::SampleEnum
    {
        // waw, such super awsum added functionality!
        D, E, F, G
    };

    void doSomething(DerivedSampleEnum arg)
    {
        // does something with arg, which can be either A, B, C,
        // D, E, F, or G; nothing more
    }
};

Derived d;
Base b, &bRef = d;

d.doSomething(Derived::D); // calls Derived::doSomething
b.doSomething(Base::B);    // calls Base::doSomething
bRef.doSomething(Base::A); // calls Derived::doSomething

Notice that even though Derived::doSomething accepts different argument types, it still has overridden Base::doSomething, because Derived::DerivedSampleEnum is covariant with Base::SampleEnum.

As such, Derived can be used wherever a Base object is expected, as long as its implementation doesn’t do something incompatible with what is expected from an object of type Base. That is, nothing here hurts LSP.

On the other hand, the authors of class Derived managed to easily add new, albeit respectful to the interface it belongs, behavior to method doSomething, enjoying OCP compliance at its best.

Conclusion: Enum Inheritance eases the life of designers wanting to develop class derivations that extend their base classes without having to modify them. If a C++ class featured a method accepting an enum, there would be no way for an overriding method to extend functionality tied to such an enum without modifying the base class, thus hurting OCP.

If Chii managed to accomplish enum inheritance without adding overhead where it’s not due, Chii would’ve successfully fixed a broken aspect of C++’s enum system (and also Java / C#, for that matter).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Cute bouncing pixels

un.ma.i!

Twitter (technical)

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

Twitter (personal)

Error: Twitter did not respond. Please wait a few minutes and refresh this page.

Get messaged when I post something new!
Just enter your e-mail and hit Follow:

Join 171 other followers

%d bloggers like this: