April 13, 2014
On Saturday, 12 April 2014 at 22:06:42 UTC, froglegs wrote:
>  Oh you D guys, arguing about enums for 187 posts! Find something more interesting to talk about, this is boring:(
>

This line of reasoning have been used before: http://a.abcnews.com/images/US/abc_aerial_sinkhole_lpl_130304_wmain.jpg
April 13, 2014
On Saturday, April 12, 2014 12:19:56 Walter Bright wrote:
> On 4/12/2014 5:59 AM, Jonathan M Davis wrote:
> > And what would the purpose by of giving them their own type?
> 
> We are *really* going around in circles here.

So, it would seem. Clearly, I have a very different viewpoint on what enums are supposed to be and do that either you or Andrei (though based on other comments in this thread, I don't seem to be alone).

- Jonathan M Davis
April 13, 2014
On Saturday, April 12, 2014 12:43:32 Andrei Alexandrescu wrote:
> On 4/12/14, 5:59 AM, Jonathan M Davis wrote:
> > If the enum
> > doesn't enumerate all of the values, then you're clearly going to be using
> > other values with it, meaning that any restrictions on setting a variable
> > to those other values is going to be a problem (as is currently the case
> > with enums - assignment and initialization are protected against
> > non-enumerated values). You'd just end up with a enum type which is
> > effectively an alias for the enum's base type except that assigning it
> > non-enumerated values requires casting, and you can overload a function
> > on the enumerated values vs the non- enumerated ones (or at  least,
> > non-enumerated ones which aren't cast to the enum type) by overloading a
> > function on the enum type and its base type - which would be highly
> > bug-prone IMHO.
> 
> Sorry, your speculations are mistaken. The pattern works well and we've been using it repeatedly and with good results since C++ introduced "enum class".

I would have expected that all of the required casting would be annoying and that overloading between the enum and its base type would be error-prone, because all you have to do is forget to cast when passing a literal, and you end up with the wrong overload being called. But I guess if you view casting to the enum type like a constructor, then it makes sense, and apparently, it's working for you.

Regardless, I'd never use an enum to partially enumerate values for a type, because I think that that violates the very concept of what an enumeration is. And I expect that enums get used so frequently in other ways primarily due to the fact that C's enums are so weakly typed. I'd use a struct for any case where I wanted a new type which didn't have a full enumeration of its values, and any constants would probably just be static variables or manifest constants on the struct.

So, I'm not at all interested in having D's enum not fully protect against having a variable of that enum type end up becoming a non-enumerated value, and I don't at all value the ability to have enums which aren't intended to enumerate all of their values. But clearly, not everyone agrees on that.

So, if we add final enum, and it properly protects against any operation on a variable of that enum type ever becoming a non-enumerated value without a cast, and it works with final switch, then great. I won't like what non-final enums do, and I'll never use them, but at least then we can have non-buggy behavior for enums which are intended to enumerate all of their values.

As it stands, I think that C++'s enum class are better than D's enums, because they actually protect against any operations (other than casts) giving the enum a non-enumerated value, and Ds enums don't  - though enum classes arguably go a bit far, because they don't provide implicit conversions to their base type, and you have to overload any operators on the type that you want to use. But I'd still rather have that than have to worry about enum variables becoming non-enumerated values like we currently have to worry about in D - and features like final switch just make it that much worse when an enum variable ends up with a non-enumerated value.

- Jonathan M Davis
April 13, 2014
On 2014-04-08 19:08:46 +0000, Andrei Alexandrescu said:
> 
> The current design is loose enough to accommodate all of the above uses, probably too loose because it allows a bunch of nonsensical code to compile. There are several questions to ask ourselves:
> 
> Andrei

Can we step off the trying to prevent nonsensical code from compiling thing?   Anything that's turing complete will allow nonsensical code to run.   I'd rather have static analysis tools that issue warnings which are supressable.   The whole thing with @safe and shared makes a lot of sensical code NOT compile without atrocious workarounds.

-S.

April 13, 2014
On 4/12/14, 8:15 PM, deadalnix wrote:
> On Saturday, 12 April 2014 at 19:43:30 UTC, Andrei Alexandrescu wrote:
>> Sorry, your speculations are mistaken. The pattern works well and
>> we've been using it repeatedly and with good results since C++
>> introduced "enum class".
>>
>
> Can you provide a sample code so we understand what you are talking
> about ? It do not seems to me that enum classes defeat Jonathan point,
> but I may be wrong.

The UserID example is a good one. You need to cast a couple of times when doing I/O, then passing user IDs around is nice because no other integers can be passed instead.

Andrei

April 13, 2014
On 4/13/14, 12:24 PM, Shammah Chancellor wrote:
> On 2014-04-08 19:08:46 +0000, Andrei Alexandrescu said:
>>
>> The current design is loose enough to accommodate all of the above
>> uses, probably too loose because it allows a bunch of nonsensical code
>> to compile. There are several questions to ask ourselves:
>>
>> Andrei
>
> Can we step off the trying to prevent nonsensical code from compiling
> thing?

We shouldn't.

> Anything that's turing complete will allow nonsensical code to
> run.   I'd rather have static analysis tools that issue warnings which
> are supressable.   The whole thing with @safe and shared makes a lot of
> sensical code NOT compile without atrocious workarounds.

Yah, that's what makes type system design difficult.


Andrei

April 14, 2014
On Sunday, 13 April 2014 at 13:50:14 UTC, Jonathan M Davis wrote:
> Regardless, I'd never use an enum to partially enumerate values for a type,
> because I think that that violates the very concept of what an enumeration is.

Then you cannot write forward compatible code without creating lots of unused enum values, but I guess that is a reasonable tradeoff.

> And I expect that enums get used so frequently in other ways primarily due to
> the fact that C's enums are so weakly typed.

No, it was recommended as a better way to create integer constants than #define. Older codebases use #define more.

Ola.



April 14, 2014
On Monday, April 14, 2014 02:27:24 Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>@puremagic.com wrote:
> On Sunday, 13 April 2014 at 13:50:14 UTC, Jonathan M Davis wrote:
> > Regardless, I'd never use an enum to partially enumerate values
> > for a type,
> > because I think that that violates the very concept of what an
> > enumeration is.
> 
> Then you cannot write forward compatible code without creating lots of unused enum values, but I guess that is a reasonable tradeoff.

Well, since code needs to be able to handle all enum values appropriately, adding or removing enum values does tend to break code. That's why we have final switch - to make it so that code breaks and the problem is caught rather than having the code silently break.

Whether it makes sense to create unused enum values depends on what the enum is for, but at the moment, I can think of any enum where I would have thought that that was appropriate. It's pretty much just a fact of life that if you change the values enumerated by an enum, you're going to break code that deals with all of the enum values (though code that only deals with some of them can avoid breakage).

- Jonathan M Davis

April 14, 2014
On Sat, 12 Apr 2014 03:25:34 -0400, deadalnix <deadalnix@gmail.com> wrote:

> On Saturday, 12 April 2014 at 03:07:39 UTC, Steven Schveighoffer wrote:
>> I don't really understand this statement. The problem I'm trying to solve is that final switch doesn't do what it's supposed to do.
>>
>
> final switch is a fine construct. The fact that it can be fed garbage is the problem.
>
> It can be fed garbage because enum to not provide any guarantee whatsoever. You are trying to solve a political problem because it appear that Walter is not gonna admit that he conflated 2 semantic in one thing, and achieve to make it useless for both.

Final switch doesn't exist without a well-behaved enum. The fact that it was built upon a broken enum system is the exact problem. Without an enum that guarantees (without type subversion) that it can only be one of the prescribed values, final switch is broken. Of course it's fine as a concept, but it needs the guarantee. I'm trying to fix the guarantee, or at least add a mechanism for future programmers to provide the guarantee.

>> final switch is fundamentally broken. It is supposed to be an input condition to final switch that the value MUST be one of the enum values. By allowing arbitrary math on enums, this is not the case, even in @safe code.
>>
>
> You are arguing that final switch is broken, but your argument show that enums fail to provide any guarantee. You are avoiding the logical conclusion.

What is the logical conclusion that I am avoiding?

>> In any case, it doesn't solve all enum problems, just that one. Will it break code? Code that is written correctly, it will break trivially (just add final to the enum declaration). Code that is not written correctly, you will either have to use normal switch, or fix the code.
>>
>
> The most basic, fundamental building block that is needed is a type with retained values. Literally every single other use case presented here can be built on top of this as library.
>
> Additionally, this is also the only use case where compiler can take advantage of the knowledge it has for other things (optimization purpose, or additional feature like final switch).
>
> There is no point in introducing additional core language feature, simply sanitize what exists and extends library support for uses cases discussed in this thread.

I'd not be against doing this, but we have to weigh the benefits against the code breakage. For cases where enum is NOT used in a final switch (like the UserId case), what are the benefits?

What I'm trying to do is solve the final switch without affecting code that doesn't care about final switch.

-Steve
April 14, 2014
On Sunday, 13 April 2014 at 22:49:54 UTC, Andrei Alexandrescu
wrote:
> On 4/12/14, 8:15 PM, deadalnix wrote:
>> On Saturday, 12 April 2014 at 19:43:30 UTC, Andrei Alexandrescu wrote:
>>> Sorry, your speculations are mistaken. The pattern works well and
>>> we've been using it repeatedly and with good results since C++
>>> introduced "enum class".
>>>
>>
>> Can you provide a sample code so we understand what you are talking
>> about ? It do not seems to me that enum classes defeat Jonathan point,
>> but I may be wrong.
>
> The UserID example is a good one. You need to cast a couple of times when doing I/O, then passing user IDs around is nice because no other integers can be passed instead.
>
> Andrei

I understand the benefit of that, but how does that require
language support ?