Topic: Proposal: enum flag extension


Author: 520001085531-0001@t-online.de ("Uenal Mutlu")
Date: Thu, 12 May 2005 06:44:36 GMT
Raw View
And me wonders why the following is still not possible in C++:

enum TEA
  {
    E1, E2, E3
  };

enum TEB : TEA
  {
    E4, E5
  };


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Fri, 13 May 2005 05:04:38 GMT
Raw View
Uenal Mutlu wrote:
> And me wonders why the following is still not possible in C++:
> enum TEA { E1, E2, E3 };
> enum TEB : TEA { E4, E5 };

Because this "derivation" is exactly the opposite of class derivation.
Every TEA is also a TEB, but every TEB is not a TEA.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: 520001085531-0001@t-online.de ("Uenal Mutlu")
Date: Fri, 13 May 2005 15:57:18 GMT
Raw View
"Hyman Rosen"
> Uenal Mutlu wrote:
> > And me wonders why the following is still not possible in C++:
> > enum TEA { E1, E2, E3 };
> > enum TEB : TEA { E4, E5 };
>
> Because this "derivation" is exactly the opposite of class derivation.
> Every TEA is also a TEB, but every TEB is not a TEA.

No. Why should it?
IMO every TEB is also a TEA, but every TEA is not a TEB, and
this is the expected behavior, and it's exactly the same like when using classes.
So there is IMO no reason (ie. any problem) for not adding this to the language.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Sat, 14 May 2005 02:44:39 GMT
Raw View
Uenal Mutlu wrote:
> IMO every TEB is also a TEA, but every TEA is not a TEB, and
> this is the expected behavior, and it's exactly the same like when using classes.
> So there is IMO no reason (ie. any problem) for not adding this to the language.

Excuse me? TEB contains extra enumerators beyond TEA. So if you allow
    TEB teb = E5;
    TEA tea = teb; // Now tea == E5 ??!!!
then tea now contains an illegal value.

With classes,
    struct TEA { int x; };
    struct TEB : TEA { int y; };
    TEB teb; teb.x = 1; teb.y = 2;
    TEA tea = teb; // Fine. tea.x == 1

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: 520001085531-0001@t-online.de ("Uenal Mutlu")
Date: Mon, 16 May 2005 16:22:43 GMT
Raw View
Hyman Rosen wrote
> Uenal Mutlu wrote:
> > IMO every TEB is also a TEA, but every TEA is not a TEB, and
> > this is the expected behavior, and it's exactly the same like when using classes.
> > So there is IMO no reason (ie. any problem) for not adding this to the language.
>
> Excuse me? TEB contains extra enumerators beyond TEA. So if you allow
>     TEB teb = E5;
>     TEA tea = teb; // Now tea == E5 ??!!!
> then tea now contains an illegal value.

I see.  But I have the feeling that inheritance should still be
made possible with enum-like values, either by extending the
existing enum concept (for example by using an implicitly added
method named isnull() or so),  or introducing a completely new
way for this. I think the latter would be easier to implement.
If the value is invalid then it should return a userdefined null value.
Here's a possible concept:

   xenum<-9> B {  E1, E2, E3 };    // nullvalue is -9
   xenum<-5> D1 : B  {  E4, E5 };  // nullvalue is -5
   xenum<>   D2 : D1 {  E6, E7 };  // nullvalue is -1 (the default)
   xenum     D3 : D1, B  {  E7, E8 };  // nullvalue is -1 (the default)

   D2 d2 = E6;  // d2 has value of E3 (ie. 2)
   D1 d1 = d2;  // d1 will be the userdefined nullvalue (-5) for D1
   B  b  = d1;  // b is nullvalue (-9)
   b = d2;      // b is nullvalue (-9)

Multiple inheritance should be possible.
There are the following implicit methods of xenum:
   T getnullvalue();   // returns the user defined null value (T is implicitly the type of the xenum)
   bool isnull();         // returns whether the value is the nullvalue
User code can make use of these methods.

As an example: such a method would allow extending a 3rd party
class/library without the need for modifying the 3rd party code.
Currently this (enum extension) is not possible without modifying
the original enum declaration.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: SeeWebsiteForEmail@moderncppdesign.com ("Andrei Alexandrescu (See Website For Email)")
Date: Mon, 16 May 2005 16:21:27 GMT
Raw View
Uenal Mutlu wrote:
> "Hyman Rosen"
>
>>Uenal Mutlu wrote:
>>
>>>And me wonders why the following is still not possible in C++:
>>>enum TEA { E1, E2, E3 };
>>>enum TEB : TEA { E4, E5 };
>>
>>Because this "derivation" is exactly the opposite of class derivation.
>>Every TEA is also a TEB, but every TEB is not a TEA.
>
>
> No. Why should it?
> IMO every TEB is also a TEA, but every TEA is not a TEB, and
> this is the expected behavior, and it's exactly the same like when using classes.
> So there is IMO no reason (ie. any problem) for not adding this to the language.

That's backwards. Inheritance would mean that a function getting a TEA
should be prepared for any value (because now TEA would be any
enumeration that includes E1=0, E2=1, and E3=2), which is contrary to
the currently accepted view on enumerated values (which is, you look at
the definition and get an idea about all of its possible values).

Andrei

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: christoph.seifert@gmx.net (Christoph Seifert)
Date: Sun, 8 May 2005 17:15:22 GMT
Raw View
Hello!
I am sorry, if I might pick up some old idea. I am missing
some extension of the enum keyword though.

The Problem:
===========
I am using enums for a type-safe interface for some
functions e.g. enum types { bla, blub, ... };
using it in say
do_something(const string& text, types type);
If I am using flags though like in
fl.open(ios::out | ios::append), I have to define the
parameter of open as being an integer i.e. open(int);,
which removes the type-safety of the function
parameter. This is due to the |, & etc. operators returning
an integer.
Checking the standard library, I see, that there is
already a type-safe interface implemented.
This solution though is at the cost of many lines of
rather akward if tricky code, which includes
defining bitwise operators for openmode types like ios::append.

Suggestion No. 1:
================
extend the enum keyword (or introducing some new keyword)

e.g. enum_flags ios_flags { out, append, ... };

the value of out is automatically (1<<0) = 1,
the value of append is (1 << 1) = 2 etc.
Any combination of existing flags e.g. ios::append | ios::out
would be a valid ios_flags number as well by default.

Advantage:
I would achieve the same type-safety as with the
openmode example of the ios_base class - with
a lot of lines less in the source code, lettting
it shrink to a mere line of declaration.

Looking forward for comments!
Sincerly,
Christoph Seifert

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Sun, 8 May 2005 23:52:16 GMT
Raw View
Christoph Seifert wrote:
> extend the enum keyword (or introducing some new keyword)
>
> e.g. enum_flags ios_flags { out, append, ... };

This is quite an old problem and has traditionally been solved
with enum and macros.  My personal opinion is that a different
approach is needed largely because the problem lies elsewhere in
the language -- namely with bit-fields.

I know of two major uses for bit-fields:

- Packing restricted range values into a compact space.

- Interface with external equipment.

The two uses have different requirements with the interface
application being the more restrictive.  As the language is
currently defined, it is very difficult (but not impossible)
to use bit-fields to specify a hardware interface.  As a result
bit-wise operators with enum values are used usually used to
implement this kind of application.

The first and most significant problem with using bit-fields
for interfaces is the fact that the order of allocation of
bit-fields is implementation defined and thus NOT portable.
There is also a problem with specifying the size of the
object being transferred through the interface.

A good solution would also allow BOTH bit-field and bit-wise
operations to be used on an interface.

I think it might be possible to restructure the language to
do this better.  The following is a rough draft for a proposal
that might be usable:

1) The data type of a bit field specifies the access width.
    Traditionally,  'char' is the narrowest accessible type,
    'short' the next less narrow with 'int', 'long' and 'long
    long' being wider and wider types.  (This is a non-decreasing
    sequence, but not necessarily an increasing sequence.)

2) The address of the store containing the bit-field changes
    when:

    a) the data type of the fields changes,
    b) there is no room int the store for the specified number
       of bits, or
    c) a zero width bit field is specified.  (See item 6 below for
       more details.)

    For this purpose the 'signedness' of the data type is
    ignored.

3) The sign of the width determines which end of the store the
    field is allocated from:

    :+n) allocates bits from the least significant end of the
         unassigned bits in the store, and
    :-n) allocates bits from the most significant end of the
         unassigned bits in the store.

     Note that 'n' can be a compile time constant expression and
     need not start with a literal '-' character.

4)  The width of a bit-field may be specified indirectly by
     (ab)using the enum keyword.  The width of the field will
     be the number of bits needed to hold the largest enumerated
     value.  A ': signed enum' is is allocated from the most
     significant end of the unassigned bits in the store while an
     ': unsigned enum' is allocated from the least significant end
     of the unassigned bits in the store.

     Note: The absence of either 'signed' or 'unsigned' in this
     context is ambiguous and warrants a diagnostic.  Also, all
     enumerated values shall not be negative.

5)  A bit-field does NOT require a name, however without a
     name, it will not be possible to access the specified set
     of bits as a bit-field.

6)  The name of the zero width bit field provides access to
     the entire store so that bit-wise and integer arithmetic
     operations can be performed on the store.  If the zero width
     bit field for a store is not named or is not present, no
     bit-wise or integer arithmetic operations can be applied to
     the store as a whole.  For the sake of the following
     discussion, the object designated as having zero width is
     not technically a bit-field and do not have any of the
     special members described in the next item (7).

7)  Bit-fields have three special members:

     .mask is a compile time constant that can be used with
            bit-wise operators to isolate the bit-field in the
            store.  (See item 6 for the way to designate access
            to the store as a whole.)

            [If absolutely required, this value could be
            constructed from the .bit and .width members
            described below.]

     .bit is a compile time constant that designates the low
            order bit of the field within the store.  (See item 6
            for the way to designate access to the store as a
            whole.)

            [It is tempting, but not absolutely necessary, to
            specify a member with the value '1 << field.bit'.]

     .width is a compile time constant that designates the
            width of the bit-field in bits.

     Note that these are NOT keywords in the usual sense.

8)  The address of a bit-field is that address of the whole
     store containing the bit-field.  (On a machine with 8
     bit characters and 32 bit long integers, the address of
     a 'long' bit-field at bit offset 8 would be the address
     of the long as a whole, not the address of the character
     within the long containing that bit.)

An example might be useful:  It should be possible to access
the various fields in a typical 'float' with the following
type:

struct float_fields {               // 32 bits total..
     signed long     sign : -1;      // The sign bit
     unsigned long   expo : -8;      // 8 bits of biased exponent
     unsigned long   frac : -23; };  // 23 bits of varying fraction bits

or

struct float_fields {               // 32 bits total..
     unsigned long   frac : 23;      // 23 bits of varying fraction bits
     unsigned long   expo : 8;       // 8 bits of biased exponent
     signed long     sign : 1; };    // The sign bit

max@mtew.isa-geek.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: christoph.seifert@gmx.net (Christoph Seifert)
Date: Tue, 10 May 2005 01:32:09 GMT
Raw View
Hello,

thank you very much for your comment!
I think my statement might have been a bit
confusing.

I still think, that an implementation
as in the standard library with enum,
declarations of variables and declaration
of bitwise operators is akward at best
and lengthy at the very least.

That's why I was suggesting some nice shortcut
for implementing a type-safe interface with
flags like ios::app, which handles bitwise
operators like | e.g. ios::out | ios::append
as well.

Your proposal aims at the portability
of bitfields for use with hardware interfaces.
This I think is a different, though
very important field.

Sincerely,
Christoph Seifert

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]