Implicit enum conversions are a stupid PITA

yigal chripun yigal100 at gmail.com
Tue Mar 23 15:42:19 PDT 2010


Nick Sabalausky Wrote:

> I'm bringing this over here from a couple separate threads over on "D.learn" 
> (My "D1: Overloading across modules" and bearophile's "Enum equality test").
> 
> Background summary:
> 
> bearophile:
> > I'm looking for D2 rough edges. I've found that this D2 code
> > compiles and doesn't assert at runtime:
> >
> > enum Foo { V1 = 10 }
> > void main() {
> >  assert(Foo.V1 == 10);
> > }
> >
> > But I think enums and integers are not the same type,
> > and I don't want to see D code that hard-codes comparisons
> > between enum instances and number literals, so I think an
> > equal between an enum and an int has to require a cast:
> >
> > assert(cast(int)(Foo.V1) == 10); // OK
> 
> He goes on to mention C++0x's "enum class" that, smartly, gets rid of that 
> implicit conversion nonsense.
> 
> To put it simply, I agree with this even on mere principle. I'm convinced 
> that the current D behavior is a blatant violation of strong-typing and 
> smacks way too much of C's so-called "type system".
> 
> But here's another reason to get rid it that I, quite coincidentally, 
> stumbled upon right about the same time:
> 
> Me:
> > In D1, is there any reason I should be getting an error on this?:
> >
> > // module A:
> > enum FooA { fooA };
> > void bar(FooA x) {}
> >
> > // module B:
> > import A;
> > enum FooB { fooB };
> > void bar(FooB x) {}
> >
> > bar(FooB.fooB); // Error: A.bar conflicts with B.bar (WTF?)
> 
> In the resulting discussion (which included a really hackish workaround), it 
> was said that this is because of a rule (that I assume exists in D2 as well) 
> that basically goes "two functions from different modules are in conflict if 
> they have the same name." I assume (and very much hope) that the rule also 
> has a qualification "...but only if implicit conversion rules make it 
> possible for one to hijack the other".
> 
> It was said that this is to prevent a function call from getting hijacked by 
> merely importing a module (or making a change in an imported module). That I 
> can completely agree with. But I couldn't understand why this would cause 
> conflicts involving enums until I thought about implicit enum-to-base-type 
> conversion and came up with this scenario:
> 
> // Module Foo:
> enum Foo { foo }
> 
> // module A:
> import Foo;
> void bar(Foo x){}
> 
> // module B version 1:
> import Foo; // Note: A is not imported yet
> void bar(int x){}
> bar(Foo.foo); // Stupid crap that should never be allowed in the first place
> 
> // module B version 2:
> import Foo;
> import A; // <- This line added
> void bar(int x){}
> bar(Foo.foo); // Now that conflict error *cough* "helps".
> 
> So thanks to the useless and dangerous ability to implicitly convert an enum 
> to its base type, we can't have certain perfectly sensible cross-module 
> overloads.
> 
> Although, frankly, I *still* don't see why "bar(SomeEnum)" and 
> "bar(SomeOtherEnum)" should ever be in conflict (unless that's only D1, or 
> if implicit base-type-to-enum conversions are allowed (which would make 
> things even worse)).
> 
> 

This also interacts with the crude hack of "this enum is actually a constant". 
if you remove the implicit casts than how would you be able to do:
void foo(int p); 
enum { bar = 4 }; // don't remember the exact syntax here
foo(bar); // compile-error?!

I feel that enum needs to be re-designed. I think that C style "enums are numbers" are *bad*, *wrong* designs that expose internal implementation and the only valid design is that of Java 5.

e.g.
enum Color {blue, green}
Color c = Color.blue;
c++; // WTF?  should NOT compile

A C style enum with values assigned is *not* an enumeration but rather a set of meaningful integral values and should be represented as such.

This was brought up many many times in the NG before and based on past occurences will most likely never change.



More information about the Digitalmars-d mailing list