improving enumeration types n1513 03 0096 by david e miller l.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
Improving Enumeration Types [N1513=03-0096] by David E. Miller PowerPoint Presentation
Download Presentation
Improving Enumeration Types [N1513=03-0096] by David E. Miller

Loading in 2 Seconds...

play fullscreen
1 / 23

Improving Enumeration Types [N1513=03-0096] by David E. Miller - PowerPoint PPT Presentation


  • 321 Views
  • Uploaded on

Improving Enumeration Types [N1513=03-0096] by David E. Miller Review by Yuriy Solodkyy http://parasol.tamu.edu/~yuriys/ Problem description Summary of issues Inconsistent relationship between enumerations of separate types Limitation to integral types

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'Improving Enumeration Types [N1513=03-0096] by David E. Miller' - Lucy


An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
improving enumeration types n1513 03 0096 by david e miller

Improving Enumeration Types[N1513=03-0096]by David E. Miller

Review by Yuriy Solodkyy

http://parasol.tamu.edu/~yuriys/

problem description
Problem description
  • Summary of issues
  • Inconsistent relationship between enumerations of separate types
  • Limitation to integral types
  • Inability to specify actual storage space and type to be used
  • Potentially conflicting names, unless separated by namespace use
  • Denormalized tables mapping enumeration values to printable names and vice versa
1 inconsistent relationship between enumerations of separate types
1. Inconsistent relationship between enumerations of separate types

Although it is not permitted to assign from one enumeration type to another, it is permitted to compare such values, in that the values are silently converted to integral types.

enum Color { ClrRed, ClrOrange, ClrYellow, ClrGreen, ClrBlue};

enum Alert { CndGreen, CndYellow, CndRed };

Color c = ClrYellow;

Alert a = CndYellow;

int i = 0;

c = a; // not allowed under existing rules

if (c >= a) … // allowed, but most probably incorrect

a = i; // not allowed, needs cast: a = static_cast<Alert>(i);

i = a; // allowed, but looses type information of the value

if (c >= i) … // allowed, but error prone to future changes

proposed solution
Proposed solution

Extending the "explicit" keyword to enumeration types can eliminate the implicit conversion without breaking any existing code.

explicit enum Color { ClrRed, ClrOrange, ClrYellow, ClrGreen};

explicit enum Alert { CndGreen, CndYellow, CndRed };

Color c = ClrYellow;

Alert a = CndYellow;

int i = 0;

c = a; // not allowed under existing rules

if (c >= a) … // won’t be allowed anymore

a = i; // not allowed, needs cast: a = static_cast<Alert>(i);

i = a; // won’t be allowed anymore by definition of explicit

If (c >= i) … // won’t be allowed anymore

issues
Issues
  • How to force conversion to int?static_cast<int>(c)reinterpret_cast<int>(c)
  • Allows verification of exhaustiveness of cases in switch statements based on enum type [2]
  • Library Solution?
2 limitation to integral types
2. Limitation to integral types

Although it is common to consider enumerations to be specific values, as listed in the declarations, they are also used to represent bit combinations and ranges, among other purposes. It is convenient to be able to specify floating point values as enumerations, particularly as values to be passed to functions, which by being declared to take floating enumeration parameters, can be protected at compilation time against invalid values.

Proposed solution

Extending the allowed constants for enum types can extend enumeration types without breaking any existing code.

enum FloatEnum { LowVal = 1.23, MidVal = 4.56, HighVal = 7.89 };

issues7
Issues
  • Why only floating point types? Type can also be infered from string, bool and char literals
  • What should be the type of enum that mixes several types of literals?
3 inability to specify actual storage space and type to be used
3. Inability to specify actual storage space and type to be used
  • The need to be able to know, definitely, how much space will be used by an enumeration variable, particularly in a packed struct
  • The need to be able to specify how that enumeration will be treated when used as a number, e.g. as signed or unsigned.

Currently both are compiler/platform specific

proposed solution9
Proposed solution

Borrowing from a C# approach, it is suggested there be an option to specify the underlying data type, which would also be the type to which implicit numeric conversions would be made. When utilized, this option would supersede the current size and type specifications.

typedef enum { Ver1 = 1, Ver2 = 2 } VersionSChar: signed char, VersionInt: int ;

issues10
Issues
  • Proposed syntax introduces name clash in the global namespace: e.g. there is Ver1 of type VersionInt and of type VersionSChar.
  • Why not use C-like prefix syntax:signed short enum A {…} ?
  • Library solution?
library only solution
Library only solution

What we really need is a type build on top of enum that :

  • Behaves like an original enum
  • Does not provide implicit conversion to int
  • Allows to specify storage requirements
first approximation
First approximation

template <class E>

struct enumeration

{

enumeration(E e) : m_e(e) {}

operator E() const { return m_e; }

private:

E m_e;

};

This will allow us to write:

enum Season { Spring, Summer, Autumn, Winter};

enumeration<Season> es = Summer; // Initialization by enum value

Season s = es; // Casting back to enumval

es = s; // Assignment

es = 2; // Not allowed as with original enums

es = ClrYellow; // Not allowed as with original enums

first problems
First problems

Comparison with a value from different enum is still valid, while it shouldn’t:if (es >= ClrYellow) … // valid but misleading

Original enum might have had some operators defined on it: [1]Season& operator++(Season& s){ switch(s){ case Spring: s = Summer; break; case Summer: s = Autumn; break; case Autumn: s = Winter; break; case Winter: s = Spring; break; } return s;};Season s = Spring; enumeration<Season> es = Summer;++s; // valid++es; // fails to compile

Original enum can be explicitly initialized by intSeason s = Season(1);enumeration<Season> es = enumeration<Season>(1); // fails

revised solution
Revised solution

template <class E>

struct enumeration

{

enumeration(E e) : m_e(e) {} explicit enumeration(int n) : m_e(E(n)) {}

operator E() const { return m_e; } enumeration& operator++() { ++m_e; return *this; }

bool operator>=(E e) const { return m_e > e; }

bool operator>=(const enumeration& e) const { return m_e > e.m_e; }

private:

template <class U> bool operator>=(U e) const;

private:

E m_e;

};

issues15
Issues
  • Similar has to be done for all overloadable operators
  • We make certain assumptions about return types which might not be the case. This should be resolved in C++0x by decltype proposal.
  • Size is still compiler/platform dependent
tackling size type problem
Tackling size/type problem

Whenever certain alignment and size constraints have to be met union is often used:

template <class E, class I = int>

union enumeration

{

enumeration(E e) : m_e(e) {}

explicit enumeration(int n) : m_e(E(n)) {}

operator E() const { return m_e; }

bool operator>=(E e) const { return m_e > e; }

bool operator>=(const enumeration& e) const { return m_e > e.m_e; }

enumeration& operator++() { ++m_e; return *this; }

private:

template <class U> bool operator>=(U e) const;

private:

E m_e;

I m_i; // used only to define lower size limit

};

This only partially resolves our problem as it defines lower limit on size but not an upper one

alternative
Alternative

template <class E, class I = E>

struct enumeration

{

enumeration(E e) : m_i(I(e)) {}

explicit enumeration(int n) : m_i(I(n)) {}

operator E() const { return E(m_i); }

bool operator>=(E e) const { return E(m_i) > e; }

bool operator>=(const enumeration& e) const { return E(m_i) > E(e.m_i);}

enumeration& operator++(){ E e = E(m_i); ++e; m_i = I(e); return *this;}

private:

template <class U> bool operator>=(U e) const;

private:

I m_i;

};

And appropriate usage would be:

enumeration<Season,unsigned char> euc = Summer;

assert(sizeof(euc) == sizeof(unsigned char));

4 potentially conflicting names
4. Potentially conflicting names

In a single scope, declaring two enumerations with values that have the same name results in a conflict.enum Color { Yellow, Red };enum Alert { Yellow, Green };

Problem can be resolved without changes to the language by wrapping up enum into namespace:namespace BaseColors { enum Color { Blue, Green, Red }; }BaseColors::Color c = BaseColors::Blue;enumeration<BaseColors::Color,char> eb = BaseColors::Blue;

Such solution though seems to be counterintuitive to the novices who expect enum name to serve as a scope for name resolution:Color::Yellow, Alert::Green

proposed solution19
Proposed solution

Allow the enum name to be used as a scope modifier to the enumeration constants.

5 denormalized tables mapping enumeration values to printable names and vice versa
5. Denormalized tables mapping enumeration values to printable names and vice versa

It is common to need functions to convert back and forth between enumeration values and printable strings corresponding to the names.

Proposed solution

The language should specify the conversion functions’ names and algorithms, including what to do when input is invalid. To avoid name collisions, it is suggested that the enumeration type be used as a disambiguating scope.

issues21
Issues
  • Examples of programs that use such facility often should be provided
  • In which encoding should it be parsed and represented?
  • Should it be case sensitive or case insensitive?
  • Exhaustiveness of manually coded switch can be warned by compiler.
compile time mapping
“Compile time” mapping

Just as an example of what modern compilers can do in regard to the previous problem [3]:inline const char* enumname(Season s) { switch(s) { case Spring: return "Spring"; case Summer: return "Summer"; case Autumn: return "Autumn"; case Winter: return "Winter"; }}

Example of the code that uses enumname:std::cout << enumname(Spring) << std::endl;

and code that compiler generated:std::cout << enumname(Spring) << std::endl;00401771 push offset string "Spring" (410200h) 00401776 push offset std::cout (414EE8h) 0040177B call std::operator<<<std::char_traits<char> > (401380h)

references
References

1. B. Stroustrup. “The Design and Evolution of C++”. Addison Wesley, March 1994. ISBN 0-201-54330-3.

2. Scott Langham. “Proposal: explicit switch”Discussion in comp.std.c++http://groups.google.com/group/comp.std.c++/browse_thread/thread/dd571aa4f927990b/596f9f38db29b9a4?lnk=st&q=explicit+switch&rnum=1#596f9f38db29b9a4

3. “Idea for ANSI standard - compile time hashing for speed“. Discussion in comp.std.c++http://groups.google.com/group/comp.std.c++/browse_thread/thread/c7921e75078e75cf/43084a6ffe9cd521?lnk=st&q=compile+time+map&rnum=5#43084a6ffe9cd521