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

Reply via email to