View mode: basic / threaded / horizontal-split · Log in · Help
October 13, 2012
Feature request: enum init shouldn't create a new enumeration
I'd like to be able to specify a default value for a named enum, 
E.init, without creating a new enumeration. There are three 
reasons:
1) Default initializing enum variables to an "invalid" value
2) Being able to use 'final switch' without the 'init' case
3) "Invalid" init value wouldn't affect E.min or E.max

Here's what currently happens:

enum MyEnum
{
    init = -123,
    first = 0,
    second = 1
}

void main()
{
    static assert(MyEnum.min == -123);

    MyEnum me;

    final switch (me)
    {
    case MyEnum.first:  break;
    case MyEnum.second: break;
    case MyEnum.init: // I'm forced to specify init case too
    }
}

This is what I'd like to happen:

enum MyEnum
{
    init = -123,
    first = 0,
    second = 1
}

void main()
{
    static assert(MyEnum.min == 0); // no effect on min/max

    MyEnum me;

    final switch (me) // no init case necessary nor allowed
    {
    case MyEnum.first:  break;
    case MyEnum.second: break;
    }
}
October 13, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Saturday, 13 October 2012 at 15:39:24 UTC, Tommi wrote:
> enum MyEnum
> {
>     init = -123,
>     first = 0,
>     second = 1
> }
>
> void main()
> {
>     static assert(MyEnum.min == -123);
>
>     MyEnum me;
>
>     final switch (me)
>     {
>     case MyEnum.first:  break;
>     case MyEnum.second: break;
>     case MyEnum.init: // I'm forced to specify init case too
>     }
> }


Also, a quick question:

Why in case its need to write name of the enum?

     case first:  break;
     case second: break;
     case init: // I'm forced to specify init case too

looks better for me.
October 13, 2012
Re: Feature request: enum init shouldn't create a new enumeration
denizzzka:

> Why in case its need to write name of the enum?

Because D enums have a very simple design. But with() helps.

Bye,
bearophile
October 13, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On 10/13/2012 11:01 AM, bearophile wrote:
> denizzzka:
>
>> Why in case its need to write name of the enum?
>
> Because D enums have a very simple design. But with() helps.

For me, that is the only benefit of 'with':

    final switch (me) with (MyEnum)
    {
    case first:  break;
    case second: break;
    case init: break;
    }

The other uses of 'with' are more like obfuscations.

>
> Bye,
> bearophile

Ali
October 13, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Saturday, October 13, 2012 17:39:23 Tommi wrote:
> I'd like to be able to specify a default value for a named enum,
> E.init, without creating a new enumeration. There are three
> reasons:
> 1) Default initializing enum variables to an "invalid" value
> 2) Being able to use 'final switch' without the 'init' case
> 3) "Invalid" init value wouldn't affect E.min or E.max
> 
> Here's what currently happens:
> 
> enum MyEnum
> {
>      init = -123,
>      first = 0,
>      second = 1
> }
> 
> void main()
> {
>      static assert(MyEnum.min == -123);
> 
>      MyEnum me;
> 
>      final switch (me)
>      {
>      case MyEnum.first:  break;
>      case MyEnum.second: break;
>      case MyEnum.init: // I'm forced to specify init case too
>      }
> }
> 
> This is what I'd like to happen:
> 
> enum MyEnum
> {
>      init = -123,
>      first = 0,
>      second = 1
> }
> 
> void main()
> {
>      static assert(MyEnum.min == 0); // no effect on min/max
> 
>      MyEnum me;
> 
>      final switch (me) // no init case necessary nor allowed
>      {
>      case MyEnum.first:  break;
>      case MyEnum.second: break;
>      }
> }

Think about that for a moment. What happens when that final switch statement is 
actually run? Which statement would MyEnum.init use? The whole point of final 
switch is that the compile _knows_ that every single value for that type has a 
case. With your suggestion, it specifically _doesn't_ have a case for one of 
the type's values. And it _will_ happen at some point that you'll hit a switch 
like that with the init value rather than a valid one. I don't see how that 
can possibly work or make any sense at all.

And remember, that in many cases, T.init is considered to be perfectly valid. 
By allowing a final switch _not_ to have it, it then becomes easy to forget to 
add a case for it when you _need_ to, completely defeating the purpose of the 
final switch (to make it so that both you and the compiler know that all of the 
possible values are accounted for).

- Jonathan M Davis
October 14, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Saturday, 13 October 2012 at 20:25:56 UTC, Jonathan M Davis 
wrote:
>> 
>>      MyEnum me;
>> 
>>      final switch (me) // no init case necessary nor allowed
>>      {
>>      case MyEnum.first:  break;
>>      case MyEnum.second: break;
>>      }
>> }
>
> Think about that for a moment. What happens when that final 
> switch statement is actually run?

There's a bug in that code, because MyEnum default-initializes to 
an invalid value. It's effectively the same as this following 
code, where the programmer has failed to initialize MyEnum 
variable with a valid value:

enum MyEnum { first, second }

void main()
{
    MyEnum me = cast(MyEnum)(-123);
	
    final switch (me)
    {
    case MyEnum.first:  break;
    case MyEnum.second: break;
    }
}

I think that the final switch statement above should throw an 
unrecoverable error. I tested it, and nothing happens. I strongly 
disagree with this behavior of the compiler (a bug perhaps?).

> And remember, that in many cases, T.init is considered to be 
> perfectly valid. By allowing a final switch _not_ to have it,
> it then becomes easy to forget to add a case for it when you
> _need_ to, completely defeating the purpose of the final
> switch (to make it so that both you and the compiler know that 
> all of the possible values are accounted for).

If T.init is considered to be perfectly valid, then it means, 
that a synonym for it exists among the enumerations. E.g:

enum MyEnum  { init = 1, first = 1, second = 42 }
enum ThyEnum { first, second }

In both of those cases, T.first is the synonym of T.init, which 
is what both of those enums default-initialize to. Therefore, if 
T.init is a valid value, and thus has a synonym among the 
enumerations of T, then you can't add a case for init in a final 
switch:

MyEnum me;

final switch (me)
{
    MyEnum.first:  break;
    MyEnum.second: break;
    MyEnum.init:   // Error: duplicate case cast(MyEnum)1
                   // in switch statement
}

So, this situation you describe, where you *need* to add a case 
for init in a final switch, it doesn't exist. T.init should 
always either 1) have a synonym among the enumerations or 2) 
represent an invalid value.
October 14, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Sunday, October 14, 2012 08:20:40 Tommi wrote:
> There's a bug in that code, because MyEnum default-initializes to
> an invalid value. It's effectively the same as this following
> code, where the programmer has failed to initialize MyEnum
> variable with a valid value:

Valid or not, MyEnum.init is still a value for MyEnum and _must_ be accounted 
for. Trying to treat MyEnum.init as not being a value of MyEnum is likely to 
break all kinds of stuff. Being able to have a variable of an enum type with a 
value which is not really a member of the enum is just plain broken.

And honestly, declaring a specific init value for an enum is a stupid idea. 
It's going to screw with all kinds of stuff. Anything assuming that the init 
property is the first value (is it is in _all_ other cases but isn't 
necessarily if you declare your own) will be broken. It's still going to end 
up being in stuff like std.traits.EnumMembers or pretty much anything which 
operates on enums unless all kinds of special casing is added. TDPL does 
mention (p. 275) that you can declare enum members with the names max, min, 
and init, but it also points out that it's a dumb idea. I'd argue that it 
shouldn't even be legal at all. It's just begging for trouble.

- Jonathan M Davis
October 14, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Sunday, 14 October 2012 at 06:51:48 UTC, Jonathan M Davis 
wrote:
> And honestly, declaring a specific init value for an enum is a 
> stupid idea.

I think that declaring a specific *valid* init value for an enum 
has no purpose. But declaring a specific *invalid* init value, to 
which the enum initializes to by default, is a very good idea. 
The reason for why it's a good idea, is exactly the same as why 
default-initializing floating point variables to NaN is a good 
idea. Others have reasoned about that enough, thus I don't have 
to.

On Sunday, 14 October 2012 at 06:51:48 UTC, Jonathan M Davis 
wrote:
> ... It's going to screw with all kinds of stuff.

True, it would break code.
October 14, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Sun, 14 Oct 2012 09:16:28 +0200
"Tommi" <tommitissari@hotmail.com> wrote:

> On Sunday, 14 October 2012 at 06:51:48 UTC, Jonathan M Davis 
> wrote:
> > And honestly, declaring a specific init value for an enum is a 
> > stupid idea.
> 
> I think that declaring a specific *valid* init value for an enum 
> has no purpose. But declaring a specific *invalid* init value, to 
> which the enum initializes to by default, is a very good idea. 
> The reason for why it's a good idea, is exactly the same as why 
> default-initializing floating point variables to NaN is a good 
> idea. Others have reasoned about that enough, thus I don't have 
> to.
> 

Yes, but it still has to be taken into account in things like "final
switch". You can't just pretend that nothing will ever have that value,
because by making it the init value, you've *made* it an actual
possible value, one that just happens to indicate "uninitialized".
October 15, 2012
Re: Feature request: enum init shouldn't create a new enumeration
On Sunday, 14 October 2012 at 19:40:17 UTC, Nick Sabalausky wrote:
> Yes, but it still has to be taken into account in things like 
> "final switch". You can't just pretend that nothing will ever
> have that value, because by making it the init value, you've
> *made* it an actual possible value, one that just happens to
> indicate "uninitialized".

*I* know that named enum variables can have whatever values; it's 
rather *you* and DMD who are pretending that enum variables can 
have only those values which are specifically enumerated.

You say that final switch should take into account an enum init 
value which can be used to represent an invalid value. I say that 
final switch shouldn't consider that (invalid) init value any 
different from all the other values that are invalid for that 
specific enum type, that is: all the values that are not 
speficied explicitly by the enumerations. And the way final 
switch should take all those invalid values into account, is by 
throwing an error when a final switch switches on a value not 
specifically defined by the enumerations.

Dmd also seems blinded into thinking that the specified 
enumerations are all that an enum variable can ever be, while in 
reality, it's very easy to write a bug that makes an enum 
variable have an invalid value. E.g:

enum MyEnum { first, second, third }

auto me = MyEnum.min;

while (me < MyEnum.max)
{
    // do something
    ++me;
}

switch (me) // this should throw
{
case MyEnum.first:  break;
case MyEnum.second: break;
case MyEnum.thrird: break;
}
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home