Implicit enum conversions are a stupid PITA

Regan Heath regan at netmail.co.nz
Wed Mar 24 03:22:10 PDT 2010


Nick Sabalausky wrote:
> 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.

One thing being able to convert enum to it's base type does allow is this:

import std.stdio;

enum FLAG
{
   READ  = 0x1,
   WRITE = 0x2,
   OTHER = 0x4
}

void foo(FLAG flags)
{
   writeln("Flags = ", flags);
}

int main(string[] args)
{
   foo(FLAG.READ);
   foo(FLAG.READ|FLAG.WRITE);
   return 0;
}


I find being able to define bit flag values with an enum and combine 
them using | and |= or negate with &= ~flag etc very useful.

Languages without the implicit conversion typically give an error when 
using |, |= etc forcing you to cast, eg.
   foo((int)FLAG.READ|(int)FLAG.WRITE);
which, in addition, breaks type safety as you're casting to 'int'.

Alternately they require you to define |, |= etc for the 'strong' enum 
type which is a PITA, IMO.

Granted, that's probably the most 'correct' way for a strongly typed 
language to do things, but it just feels un-necessary for someone who is 
used to the convenience of the implicit conversion.


All that said, I also find method/function collision very annoying. 
True, it is easily solvable with alias, but that's always felt a bit 
hackish and messy to me.


So, imagining we have a strongly typed 'enum' with no implicit 
conversion.  Can we get back the convenience of being able to call 
numeric operators on them without casts or all the legwork involved?

Could the compiler not automatically generate them?  The downside is 
that this would result in multiple copies of what was essentially the 
same function for int and every enum type.

We could make the programmer ask for it with a special base type, eg.
   enum FLAG : numeric {}
but, ideally we want existing code to continue to work.

I wonder if the compiler could safely do the (cast) for us without 
loosing type safety?  i.e. case the enum to int, call the int operator, 
and cast the result back.

The result would be that this works:
   foo(FLAG.READ|FLAG.WRITE);

but this would error:
   foo(FLAG.READ|FLAG.WRITE|5);

and enum would appear to be a strong type, and would no longer collide 
on function resolution but we'd have the convenience of numeric 
operators - a common usage pattern for enums.  Are there other usage 
patterns this would break?

R



More information about the Digitalmars-d mailing list