Topic: Subclassing" Enums


Author: David Apfelbaum <da0g+@andrew.cmu.edu>
Date: 1995/04/02
Raw View
Excerpts from netnews.comp.std.c++: 27-Mar-95 "Subclassing" Enums by
Joel Schmidt@bnr.ca
> I recently found myself in a situation where I had declared an
> enumeration in a base class, and then wished to "subclass" that
> enumeration in a derived class, i.e:


Could you do:

class base {
  enum baseEnum { FIRSTITEM = 1, SECONDITEM, THIRDITEM, MAXITEMS };
public:
  void func ( baseEnum theBaseEnum );
};

class derived : base {
   enum derivedEnum { OTHERITEM = baseEnum::MAXITEMS,
                      SECONDOTHERITEM,
                      MAXITEM };
public:
   void func ( baseEnum theBaseEnum ) { base::func ( theBaseEnum ); }
   void func ( derivedEnum theDerivedEnum );
};


Of course, this gets messy with multiple subclassings...  And you have
to define the "void func ( baseEnum theBaseEnum )" methods each time,
since base-class-methods are not automatically available when there's a
derived-class-method with the same method name.

(Before you complain about that being a language fault, think about it!
Think about what would happen with constructors -- say if a base class
constructor took an int, and a derived class constructor only took a
float, and you tried to construct the derived class with a int!  *BOOM* )

But, if you prefer, you could do:
   void func ( int theEnumValue )
   {
        if ( theEnumValue < base::MAXITEMS )
            base::func ( baseEnum(theEnumValue) );
        else switch ( theEnumValue ) {
            case OTHERITEM:
                __whatever__;
                break;
            case SECONDOTHERITEM:
                __whatever__;
                break;
            default:
                __whatever__;
                break;
        }
    }

Since enumerated types can always cast to integers automatically, so that
statments like func(base::FIRSTITEM) would be automatically translated to
func(1) by the compiler.

Which permits multiple subclassing rather nicely, but at the cost
of giving up static compile-time type-checking...

    -David Apfelbaum.







Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: 1995/03/30
Raw View
In article <D647K6.Fwy@cdf.toronto.edu>
           g2devi@cdf.toronto.edu "Robert N. Deviasse" writes:

[...]
>Actually, baseEnum is not a subclass of derivedEnum, it's an extension. Here's
>an example of the difference.
[...]
>Given this difference, the subclass syntax is quite misleading.
>
>The issue has been discussed here and in other forums before (eg in the Ada
>standardization effort). I can't remember the reasons (can anyone else
> remember?),

It's meaningless. More precisely, no one seems to be able to come up with
sensible semantics when pushed. As you pointed out, it's not subtyping so
using the inheritance syntax is misleading. If it's supertyping, the type
system will (sensibly) restrict most desired uses.

>but unfortunately it was discovered that this feature is problematic. Pity, I
> agree
>that it`s a feature that I`ve longed for once every blue moon.

You probably either need to use classes, or an unbound set of constants
which may be enum constants for syntactic convenience but packed into an
int or appropriate type. You may be able to do some magic auto casting
with templates.

Remember that enum is short for enumerated, ie. fully listed. Extension
implies anything but.

+---------------------------+-------------------------------------+
| Kevlin A P Henney         | Can you secure Christmas with an    |
| kevlin@wslint.demon.co.uk | approximation only eighteen million |
| Westinghouse Systems Ltd  | seconds left of the original old    |
|                           | red chimney?         - Jack Kerouac |
+---------------------------+-------------------------------------+





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/03/30
Raw View
In article <3l75on$b9l@engnews2.Eng.Sun.COM>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>
>The new rule about const static members makes these work even more like
>enums in classes, including having class scope:
>
> class base {
>  enum error_code { informational=0, warning=1000,
>      error=2000, fatal=3000 };
> };
>
> class derived : public base {
>  static const error_code weekday = 100;
>  ...
> };

 Yeah. Except you still have to write:

 const error_code derived::weekday;

somewhere (anyhwere!).

 I think this was not one of the better extensions.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/03/30
Raw View
In article <3l75on$b9l@engnews2.Eng.Sun.COM>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>The new rule about const static members makes these work even more like
>enums in classes, including having class scope:
>
> class base {
>  enum error_code { informational=0, warning=1000,
>      error=2000, fatal=3000 };
> };
>
> class derived : public base {
>  static const error_code weekday = 100;
>  ...
> };

 And further to my previous comments -- this code is wrong.
There is no implicit conversion from int to an enum type.
So you'd have to write:

 static const error_code weekday = error_code(100);

And now a technicality makes this illegal. error_code(100)
isn't a constant expression. The reason is that enumerations
are NOT arithmetic types, and only conversions to arithmetic
types are permitted in constant expressions. (I think that
is a bug in the WP). You can use an enumerator in a
constant expression because even though it is not an arithemtic
type it is explicitly allowed. But it is completely useless,
becaus ethe conversion to an integral type is not a conversion
from an arithmetic type to an arithmentic type -- the only
kind permitted in constant expressions.


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: smeyers@netcom.com (Scott Meyers)
Date: Thu, 30 Mar 1995 00:01:36 GMT
Raw View
In article <3l75on$b9l@engnews2.Eng.Sun.COM> clamage@Eng.Sun.COM writes:
|  class base {
|   enum error_code { informational=0, warning=1000,
|       error=2000, fatal=3000 };
|  };
|
|  class derived : public base {
|   static const error_code weekday = 100;

Doesn't this require a cast?  ARM 7.2 (p. 114) says it does.  Did this get
changed?   I'd expect

   static const error_code weekday = static_cast<error_code>(100);

I just love those new casting forms...

Scott




Author: chaos@bnr.ca (Joel Schmidt)
Date: 27 Mar 1995 13:06:25 -0600
Raw View
I recently found myself in a situation where I had declared an
enumeration in a base class, and then wished to "subclass" that
enumeration in a derived class, i.e:

clase base {
 enum baseEnum {
   // some values related to functionality of base class
 }
}

class derived : base {
 enum derivedEnum {
   // all values in base enum
   // plus some more associated with augmented functionality of derived class.
 }
}

The only way I could see to do this was to declare entirely new symbols
in the derived enumeration and equate them to those in the base enumeration.
This is of course both tedious and poses a maintenance nightmare.

Given the nature of class hierarchies, I think it would be quite beneficial
if you could say:

 enum derivedEnum : baseEnum {
   // just the new symbols
 }

Along similar lines, it would also be quite useful if you could specify
a basic type as the "base", e.g:

 enum anEnum : unsigned char {}

thereby giving some control over storage size/type compatibility.  This
would also put the final nail in #define's coffin.

--
[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]
[~ Joel A. Schmidt                      The reasonable man adapts himself ~]
[~ BNR, CSN Development.      to the world; the unreasonable one persists ~]
[~ I speak for myself.       in adapting the world to himself. Therefore, ~]
[~ chaos@bnr.ca           all progress depends upon the unreasonable man. ~]
[~ (214) 684-4251                                --George Bernard Shaw    ~]
[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]





Author: g2devi@cdf.toronto.edu (Robert N. Deviasse)
Date: Mon, 27 Mar 1995 20:00:04 GMT
Raw View
In article <3l72bh$8tf@crchh299.bnr.ca>, Joel Schmidt <chaos@bnr.ca> wrote:
>
>I recently found myself in a situation where I had declared an
>enumeration in a base class, and then wished to "subclass" that
>enumeration in a derived class, i.e:
>
>clase base {
> enum baseEnum {
>   // some values related to functionality of base class
> }
>}
>
>class derived : base {
> enum derivedEnum {
>   // all values in base enum
>   // plus some more associated with augmented functionality of derived class.
> }
>}
>
>The only way I could see to do this was to declare entirely new symbols
>in the derived enumeration and equate them to those in the base enumeration.
>This is of course both tedious and poses a maintenance nightmare.
>
>Given the nature of class hierarchies, I think it would be quite beneficial
>if you could say:
>
> enum derivedEnum : baseEnum {
>   // just the new symbols
> }
>

Actually, baseEnum is not a subclass of derivedEnum, it's an extension. Here's
an example of the difference.

       enum Decimal { Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine };
       enum Hexadecimal : Decimal { A, B, C, D, E, F };

       void fd(Decimal&);
       void fh(Hexadecimal&);

       Decimal d=A;            // illegal
       Hexadecimal h=Zero;     // legal
       fd(h);                  // legal
       fh(d);                  // illegal

Compare this with:
       struct Dec { Dec() {} };
       struct Hex : Dec { Hex() {} };

       void fd(Dec&);
       void fh(Hex&);

       Dec d=Hex();            // legal
       Hex h=Dec();            // illegal
       fd(h);                  // legal
       fh(d);                  // illegal


Given this difference, the subclass syntax is quite misleading.

The issue has been discussed here and in other forums before (eg in the Ada
standardization effort). I can't remember the reasons (can anyone else remember?),
but unfortunately it was discovered that this feature is problematic. Pity, I agree
that it`s a feature that I`ve longed for once every blue moon.

Someone posted a way to fake a version of this feature in C++ with templates some
time ago. I'll see if I still have a copy of it and mail it to you.


>--
>[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]
>[~ Joel A. Schmidt                      The reasonable man adapts himself ~]
>[~ BNR, CSN Development.      to the world; the unreasonable one persists ~]
>[~ I speak for myself.       in adapting the world to himself. Therefore, ~]
>[~ chaos@bnr.ca           all progress depends upon the unreasonable man. ~]
>[~ (214) 684-4251                                --George Bernard Shaw    ~]
>[~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]
>


Take care
    Robert
--
/----------------------------------+------------------------------------------\
| Robert N. Deviasse               |"If we have to re-invent the wheel,       |
| EMAIL: g2devi@cdf.utoronto.ca    |  can we at least make it round this time"|
+----------------------------------+------------------------------------------/




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 27 Mar 1995 20:04:39 GMT
Raw View
In article 8tf@crchh299.bnr.ca, chaos@bnr.ca (Joel Schmidt) writes:
>
>I recently found myself in a situation where I had declared an
>enumeration in a base class, and then wished to "subclass" that
>enumeration in a derived class, ...

This was considered by the C++ Committee, and rejected as unnecessary.
C++ now has the rule that any value in the extended range of the enum
may be applied to anything of that enum type. The "extended range"
is the range implied by the number of bits needed to represent all the
declared values. To ensure a maximum extended range, you can declare
a dummy value. (To be able to subclass an enum, you would have to do
that anyway in the original enum.)

Example:

 enum error_code { informational=0, warning=1000, error=2000, fatal=3000 };

Now you can add your own codes as constants:
 const error_code weekday = 100;            // informational
 const error_code might_overflow = 1100;    // warning
 const error_code conflicting_range = 2100; // error
 const error_code cyanide = 3100;           // fatal

These can be extended at will, in this case up to 4095.

The new rule about const static members makes these work even more like
enums in classes, including having class scope:

 class base {
  enum error_code { informational=0, warning=1000,
      error=2000, fatal=3000 };
 };

 class derived : public base {
  static const error_code weekday = 100;
  ...
 };

Now you can refer to base::error or derived::weekday with the same syntax
and semantics.
---
Steve Clamage, stephen.clamage@eng.sun.com