www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Bug 3999 and 4261

reply bearophile <bearophileHUGS lycos.com> writes:
Probably each of the ~25 bugs of the short list I have shown here recently need
a bit of discussion (also because some of them are little breaking changes over
current DMD and/or TDPL). Even if some of them may need to wait in Bugzilla for
two years, it's positive to discuss them already. But you can't discuss all of
them at the same time.

This is one of them, chosen almost randomly, because it was recently commented
by Andrej Mitrovic:
http://d.puremagic.com/issues/show_bug.cgi?id=4261
It's related to:
http://d.puremagic.com/issues/show_bug.cgi?id=3999
http://d.puremagic.com/issues/show_bug.cgi?id=3308

I think bug 3999 shows the root of the situation, so I focus on it (indeed bug
4261 was not in that short list).
In C++0x Foo::V1 == 10 is a compile error, enum and int can't be compared
(don't miss the 'class' there):

enum class Foo { V1 = 10 };
int main() {
    int b = Foo::V1 == 10;
}

test.cpp: In function 'int main()':
test.cpp:3: error: no match for 'operator==' in '(Foo)10 == 10'
test.cpp:3: note: candidates are: operator==(int, int) <built-in>


The point of the change suggested in bug 3999 is that this looks good to be
adopted in D too. Enumerated sequences in my opinion are less bug-prone if they
are true distinct types.

--------------------

Note: despite in D unfortuntately constants and enumerated values share the
same keyword, here I am not talking about constants like this one:

enum int foo = 10;

This foo is really of type int, it's not an enumeration, it's not a sequence of
symbols of length 1 named foo. Semantically it is another thing (this is also
why using the enum keyword for both things was the wrong choice).

Bye,
bearophile
Aug 31 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
A way to tell them apart is the presence of the EnumTag, if it's present, then
the enum is a new type:

enum V1 = 10;
enum { V2 = 20 }
enum Foo { V3 }
void main() {
    assert(V1 == 10);    // OK
    assert(V2 == 20);    // OK
    assert(Foo.V3 == 0); // ERROR, type mismatch
}

Bye,
bearophile
Aug 31 2010
next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
bearophile schrieb:
 A way to tell them apart is the presence of the EnumTag, if it's present, then
the enum is a new type:
 
 enum V1 = 10;
 enum { V2 = 20 }
 enum Foo { V3 }
 void main() {
     assert(V1 == 10);    // OK
     assert(V2 == 20);    // OK
     assert(Foo.V3 == 0); // ERROR, type mismatch
 }
 
 Bye,
 bearophile

I sometimes find it convenient to just treat those values as integers, e.g. when reading/writing them with a stream (to a file, to some other process with SocketStream, ...). Like --- int x; stream.read(x); // btw: this often sucks - why not x = stream.readInt()? if(x == MyEnum.DIE) return 0; else if(x == MyEnum.CALLFOO) foo(x); --- or something like that (switch() might be better, but whatever). Also treating named and unnamed enums differently seems inconsistent to me. Cheers, - Daniel
Aug 31 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"Daniel Gibson" <metalcaedes gmail.com> wrote in message 
news:mailman.24.1283298345.858.digitalmars-d puremagic.com...
 ---
 int x;
 stream.read(x); // btw: this often sucks - why not x = stream.readInt()?

Better yet: stream.read!int()
 if(x == MyEnum.DIE)
 return 0;
 else if(x == MyEnum.CALLFOO)
 foo(x);
 ---
 or something like that (switch() might be better, but whatever).

 Also treating named and unnamed enums differently seems inconsistent to 
 me.

D's enums are *already* two completely different things. Some enums create a new type with a pre-determined set of possible values, and some *ahem* "enum"s *cough* just simply create a manifst constant and no new type. I gotta say, I'm completely with bearophile on these enum issues. One of the things that drew me to D from C/C++ is the increased emphasis on *strong* typing, but D's enums (and the death of typedef, athough I do understand the reasons for that) make me feel like I'm right back in the middle of C's shitty so-called "type system". Plus, even if you do want to treat a...*real* enum (such as MyEnum above) as little more than a series of manifest constants (which I think is terrible design for an enum system), then the whole point of them is to replace magic numbers with real names. So if they get printed out as their base type, then we're right back into useless "magic number" territory. I've never once, in any language, printed out the value of an enum variable, gotten the value of the *base* type, and *not* needed to convert that back into the enum symbol name either in my head or by looking up the enum definition (or mechanically). And I've rarely, if ever, in any language, printed out the value of an enum variable, gotten the actual symbol name and actually needed the value of the base type instead.
Aug 31 2010
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Daniel Gibson:
 I sometimes find it convenient to just treat those values as integers,

Yes, I am sure in some situations it can be handy. But it's a a bit of convenience that has a too much high price, the semantics is less clean, and it's more bug prone. So no thanks. Keeping things tidy is more important. Bye, bearophile
Aug 31 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Daniel Gibson:
 Then there still is the consistency-issue (anon. enums are treated 
 differently then named enums).

Look at this:Se enum int n = 10; enum Color { Red, Green, Blue } Color color; if (color == Color.Red) { ... Color is a sequence of symbols, Red, Green and Blue, named Color. When you write your program often all you need to know is if color is Red or Green, and you don't care much how the compiler represents those symbols. The n is a compile-time constant value. It's not a sequence of something. Now, just for fun, replace the first enum with something as: ctconst int n = 10; enum Color { Red, Green, Blue } Color color; if (color == Color.Red) { ... ctconst is a fictional keyword that denotes compile-time constants. Now you are probably able to see that there is no correlation between the n and Color. In D they are using the same keyword by accident, probably because Walter thinks that saving a keyword is more important than keeping the semantics tidy. So today you are probably struck with using "enum" to define compile-time constants. The C++0x design group has not introduced the "enum class" for fun, their strong typing nature is useful to make the code less bug-prone. See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1719.pdf See for example "Problem 1: Implicit conversion to an integer". Bye, bearophile
Aug 31 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Daniel Gibson:

 Why not use the non-fictional const keyword? "The const attribute 
 declares constants that can be evaluated at compile time."[1]

But you can use const for constants that are known at run-time only. While you can't use enum for constant known at run-time.
 "enum int n = 10;" looks really strange. I don't know if this is needed..

I think it helps in a linker issue. But I am not expert on this. Maybe LDC (based on LLVM) doesn't need enums much.
 But "enum : int { FOO, BAR, BAZ };" does not look so strange to me and 
 I'd prefer this to "const int FOO=0; const int BAR=1; const int BAZ=2;".
 The syntax is shorter, it shows that these keywords kind of belong 
 together and the values are enumerated automatically.

I agree, and I have never said I want to disallow it. You can cast those FOO, BAR, etc implicitly to int. It's the example V2 I have shown, no error there: enum V1 = 10; enum { V2 = 20 } enum Foo { V3 } void main() { assert(V1 == 10); // OK assert(V2 == 20); // OK assert(Foo.V3 == 0); // ERROR, type mismatch } Thank you for your doubts and questions, they help me express better what I meant. It seems I was not clear enough at the beginning. Bye, bearophile
Aug 31 2010
next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
bearophile schrieb:
 Daniel Gibson:
 
 Why not use the non-fictional const keyword? "The const attribute 
 declares constants that can be evaluated at compile time."[1]

But you can use const for constants that are known at run-time only. While you can't use enum for constant known at run-time.

Really? Than that definition from the language docs is inaccurate.
 
 "enum int n = 10;" looks really strange. I don't know if this is needed..

I think it helps in a linker issue. But I am not expert on this. Maybe LDC (based on LLVM) doesn't need enums much.
 But "enum : int { FOO, BAR, BAZ };" does not look so strange to me and 
 I'd prefer this to "const int FOO=0; const int BAR=1; const int BAZ=2;".
 The syntax is shorter, it shows that these keywords kind of belong 
 together and the values are enumerated automatically.

I agree, and I have never said I want to disallow it. You can cast those FOO, BAR, etc implicitly to int. It's the example V2 I have shown, no error there: enum V1 = 10; enum { V2 = 20 } enum Foo { V3 } void main() { assert(V1 == 10); // OK assert(V2 == 20); // OK assert(Foo.V3 == 0); // ERROR, type mismatch } Thank you for your doubts and questions, they help me express better what I meant. It seems I was not clear enough at the beginning. Bye, bearophile

I know what you meant - but my point is that anon. enums make sense (I guess we agree on that one) and that allowing implicit casting to int for them and not for named enums seems inconsistent. Of course disallowing implicit casting for anon. enums is not really an options (how should that even work.. maybe "cast(enum:int)foo" or something like that..) so IMHO a reasonable solution is keeping it the way it is. Cheers, - Daniel
Aug 31 2010
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Daniel Gibson:

 Really? Than that definition from the language docs is inaccurate.

This compiles, here n is known at run-time only: void main(string[] args) { const int n = args.length; } This compiles, but I think it's a bug: void main(string[] args) { enum int n = args.length; } This shows that there is a problem: template Foo(int n) { } void main(string[] args) { enum int n = args.length; alias Foo!(n) _; }
 I know what you meant - but my point is that anon. enums make sense (I 
 guess we agree on that one) and that allowing implicit casting to int 
 for them and not for named enums seems inconsistent.

The real inconstancy is using 'enum' for them both in the first place. They are conceptually two different things. It looks inconsistent if you think of them as similar things. But even if you like to think of them as the same thing, you may think of my proposal as a way to enforce more strong typing, to remove a subset of the allowed behaviours of one subclass of those enum thinghies that you think are all the same thing. So you may see it as an inconstancy introduced on purpose to remove some risky behaviours. D has introduced some other of such 'inconsistencies' (compared to a uniform C behaviour) where they help disallow some behaviours that are regarded as negative.
 Of course disallowing implicit casting for anon. enums is not really an 
 options (how should that even work.. maybe "cast(enum:int)foo" or 
 something like that..)

Right.
so IMHO a reasonable solution is keeping it the way it is.

In my opinion (and probably in the opinion of the people that are designing C++x0) this is not a good enough solution, because it's a little error-prone. Bye, bearophile
Aug 31 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Daniel Gibson" <metalcaedes gmail.com> wrote in message 
news:i5kbpr$24tn$1 digitalmars.com...
 bearophile schrieb:
 Daniel Gibson:

 Why not use the non-fictional const keyword? "The const attribute 
 declares constants that can be evaluated at compile time."[1]

But you can use const for constants that are known at run-time only. While you can't use enum for constant known at run-time.

Really? Than that definition from the language docs is inaccurate.

You were looking at the D1 docs. The whole const system changed in D2.
Aug 31 2010
parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Nick Sabalausky schrieb:
 "Daniel Gibson" <metalcaedes gmail.com> wrote in message 
 news:i5kbpr$24tn$1 digitalmars.com...
 bearophile schrieb:
 Daniel Gibson:

 Why not use the non-fictional const keyword? "The const attribute 
 declares constants that can be evaluated at compile time."[1]

While you can't use enum for constant known at run-time.


You were looking at the D1 docs. The whole const system changed in D2.

http://www.digitalmars.com/d/2.0/attribute.html#const says the same.
Sep 01 2010
parent "Nick Sabalausky" <a a.a> writes:
"Daniel Gibson" <metalcaedes gmail.com> wrote in message 
news:i5lrkr$1ijr$1 digitalmars.com...
 Nick Sabalausky schrieb:
 "Daniel Gibson" <metalcaedes gmail.com> wrote in message 
 news:i5kbpr$24tn$1 digitalmars.com...
 bearophile schrieb:
 Daniel Gibson:

 Why not use the non-fictional const keyword? "The const attribute 
 declares constants that can be evaluated at compile time."[1]

While you can't use enum for constant known at run-time.


You were looking at the D1 docs. The whole const system changed in D2.

http://www.digitalmars.com/d/2.0/attribute.html#const says the same.

Yea, that's probably wrong then. Unless there's something I don't know.
Sep 01 2010
prev sibling parent reply Rainer Deyke <rainerd eldwood.com> writes:
On 8/31/2010 19:46, bearophile wrote:
 But you can use const for constants that are known at run-time only.
 While you can't use enum for constant known at run-time.

In C++, const is used for both run-time and compile-time constants. In practice, this works out fine. It its value can only be known at run-time, it's a run-time constant. If its value is used at compile-time, it's a compile-time constant. If both of these apply, it's an error. If neither applies, nobody cares if it's a compile-time or run-time constant. (The actual rules in C++ are a bit more complex, less intuitive, and less useful than that, which is presumably why Walter chose not to copy the C++ in this case. Still, overloading 'const' for both compile-time and run-time constants is viable, and more intuitive than the current situation with 'enum'.) -- Rainer Deyke - rainerd eldwood.com
Sep 01 2010
next sibling parent Don <nospam nospam.com> writes:
Rainer Deyke wrote:
 On 8/31/2010 19:46, bearophile wrote:
 But you can use const for constants that are known at run-time only.
 While you can't use enum for constant known at run-time.

In C++, const is used for both run-time and compile-time constants. In practice, this works out fine. It its value can only be known at run-time, it's a run-time constant. If its value is used at compile-time, it's a compile-time constant. If both of these apply, it's an error. If neither applies, nobody cares if it's a compile-time or run-time constant. (The actual rules in C++ are a bit more complex, less intuitive, and less useful than that, which is presumably why Walter chose not to copy the C++ in this case. Still, overloading 'const' for both compile-time and run-time constants is viable, and more intuitive than the current situation with 'enum'.)

The enum situation exists ONLY because of linker limitations. It seems most people still don't understand that.
Sep 01 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
so:
 (I hope that example of bearophile is just a bug.)

I have added it as bug 4786 Bye, bearophile
Sep 01 2010
prev sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday, September 01, 2010 11:58:39 so wrote:
 I have never had troubles with C++ compile/runtime "const" difference,
 and don't think it is a problem in C++. With this in mind "enum" is a
 great keyword
 of choice to express compile-time types, as long as it is forbidden for
 run-time constants.
 (I hope that example of bearophile is just a bug.)
 
 Thanks.

C++ doesn't have CTFE. CTFE is why it really matters in D. If you're dealing with a compile-time constant, it uses CTFE. If you're dealing with a runtime constant, it doesn't. So, you need to be explicit. Personally, I don't really care about using enum the way it is. Having enums freely converting to and from their base type is more of a concern, though I'm not sure how much that really does or doesn't matter. It's quite clear when an enum is used as a manifest constant and when it's used as an enum, so I don't really see a problem with the way it is, though I can see why someone wouldn't like it. - Jonathan M Davis
Sep 01 2010
parent "Nick Sabalausky" <a a.a> writes:
"Jonathan M Davis" <jmdavisprog gmail.com> wrote in message 
news:mailman.33.1283368612.858.digitalmars-d puremagic.com...
 Personally, I don't really care about using enum the way it is. Having 
 enums
 freely converting to and from their base type is more of a concern, though 
 I'm
 not sure how much that really does or doesn't matter.

I find it to be a pain nearly every time I need to convert one to a string.
Sep 01 2010
prev sibling next sibling parent reply Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday, September 01, 2010 12:36:04 Steven Schveighoffer wrote:
 AFAIK, enum meaning manifest constant was Andrei's request.  And I think
 if you have an idea to try and "fix" it, you might as well know now, it
 will never happen.  See this quote from Andrei in a bug report of mine
 (bug 1961):
 
 "And enum... you'll have to yank that out from my dead cold hands.
 Extending
 enum instead of adding yet another way of defining symbolic constants is
 The
 Right Thing to do. I am sure people would have realized how ridiculous the
 whole "manifest" thing is if we first proposed it. We just can't define one
 more way for each kind of snow there is."
 
 There was a point in D2 development with the 'manifest' keyword added to
 do exactly what enum now does (except for actual enumerations, for which
 enum was used).
 
 FWIW, I am not a huge fan of enum being used for meaning manifest
 constants that are not enumerations, but as far as daily usage, it's not
 really bad.  It's somewhat of a petty problem, since enum is not
 functionally deficient.  It just looks weird, especially to those used to
 other languages.  I suppose you could think of it as an enumeration with
 one member :)
 
 -Steve

It's the kind of thing that is distasteful from a language purity standpoint, but it really doesn't cause any problems in code as far as I can tell. Once you know that you use enum to declare a manifest constant, it's perfectly normal to see it in code that way, so it's not confusing. And since you're not going to try to enumerate over such enums, it's not like they cause any real confusion with "normal" enums. You can think of it a bit like static. Static is used for different things in different contexts (even though most contexts are quite similar - IIRC, there's a way to define static in C++ which fits all of its uses in C++, though D adds some more that don't fit that definitition), but it doesn't really cause any confusion. enum is the same way. Sure, from the standpoint of language purity, manifest constants shouldn't be declared using enum, but the reality of the matter is that it works just fine. - Jonathan M Davis
Sep 01 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"Jonathan M Davis" <jmdavisprog gmail.com> wrote in message 
news:mailman.38.1283370572.858.digitalmars-d puremagic.com...
 You can think of it a bit like static. Static is used for different things 
 in
 different contexts (even though most contexts are quite similar - IIRC, 
 there's a
 way to define static in C++ which fits all of its uses in C++, though D 
 adds some
 more that don't fit that definitition), but it doesn't really cause any 
 confusion.
 enum is the same way. Sure, from the standpoint of language purity, 
 manifest
 constants shouldn't be declared using enum, but the reality of the matter 
 is
 that it works just fine.

Static is a little bit better in that the uses of it at least have some connection to the dictionary meaning of "static", even if perhaps a little distant. But there's just no way to stretch the dictionary meaning of "enumeration" to include manifest constants. Like everyone else, I can at least live with it, but I look forward to the day the linker issue is fixed so we can finally mutilate/destroy/kill it, dead, dead, dead with extreme prejudice in favor of immutable. It's a stain - doesn't really cause a problem, but boy is it ever UGLY.
Sep 01 2010
parent reply "Nick Sabalausky" <a a.a> writes:
"so" <so so.do> wrote in message news:op.videg00w7dtt59 so-pc...
 Static is a little bit better in that the uses of it at least have some
 connection to the dictionary meaning of "static", even if perhaps a 
 little
 distant. But there's just no way to stretch the dictionary meaning of
 "enumeration" to include manifest constants. Like everyone else, I can at
 least live with it, but I look forward to the day the linker issue is 
 fixed
 so we can finally mutilate/destroy/kill it, dead, dead, dead with extreme
 prejudice in favor of immutable. It's a stain - doesn't really cause a
 problem, but boy is it ever UGLY.

Float is not floating and double is not doubling, are they next?

Float (short for "floating point"): The decimal point can "float" around as the value changes (not a literal use of "float", but there's nothing wrong with metaphoric uses of words, even in ordinary speech). This type is named in contrast to the fixed-point arithmetic that was often used as an old-school optimization (where the decimal point was always at a fixed location, for example, the high 16-bits may have been the whole-number part, and the low 16-bits may have been the decimal part). Double: This one's easy: It's double the size of a float.
Sep 01 2010
parent "Nick Sabalausky" <a a.a> writes:
"so" <so so.do> wrote in message news:op.vidgxic47dtt59 so-pc...
 Float (short for "floating point"): The decimal point can "float" around 
 as
 the value changes (not a literal use of "float", but there's nothing 
 wrong
 with metaphoric uses of words, even in ordinary speech). This type is 
 named
 in contrast to the fixed-point arithmetic that was often used as an
 old-school optimization (where the decimal point was always at a fixed
 location, for example, the high 16-bits may have been the whole-number 
 part,
 and the low 16-bits may have been the decimal part).

 Double: This one's easy: It's double the size of a float.

If you throw "2.7f" on a water, does it float or you need to multiply with pi first?

Like I said, "metaphor". By contrast there's no basis for a metaphor between "enumeration" and manifest constants.
 Why don't we change double to hmm... doubleTheSizeOfFloat? Lets test it!

Please don't go using strawmen. No one ever said anything about abbreviations being bad.
Sep 01 2010
prev sibling next sibling parent so <so so.do> writes:
 Static is a little bit better in that the uses of it at least have some
 connection to the dictionary meaning of "static", even if perhaps a  
 little
 distant. But there's just no way to stretch the dictionary meaning of
 "enumeration" to include manifest constants. Like everyone else, I can at
 least live with it, but I look forward to the day the linker issue is  
 fixed
 so we can finally mutilate/destroy/kill it, dead, dead, dead with extreme
 prejudice in favor of immutable. It's a stain - doesn't really cause a
 problem, but boy is it ever UGLY.

Float is not floating and double is not doubling, are they next? -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
so:
 Another taste discussion?

Nope. ----------------- Steven Schveighoffer:
And I think if you have an idea to try and "fix" it, you might as well know
now, it will never happen.<

There I was explaining something better to Daniel Gibson. The purpose of the enhancement request 3999 has nothing to do with a request for a different keyword. ----------------- I think now I have presented my point as well as I can, and people have given comments and opinions. I'd like to Walter or/and Andrei to express their opinion about the bug 3999 :-) Bye, bearophile
Sep 01 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/1/10 15:35 CDT, bearophile wrote:
 so:
 Another taste discussion?

Nope. ----------------- Steven Schveighoffer:
 And I think if you have an idea to try and "fix" it, you might as well know
now, it will never happen.<

There I was explaining something better to Daniel Gibson. The purpose of the enhancement request 3999 has nothing to do with a request for a different keyword. ----------------- I think now I have presented my point as well as I can, and people have given comments and opinions. I'd like to Walter or/and Andrei to express their opinion about the bug 3999 :-)

I think it's a good enhancement. C++'s good old enum has been instrumental in finding a few bugs and clarifying a few interfaces in a project at work. Based on that experience I'd say that there's a chance more restrictive is better. We need to find a principled way to define semantics though - if we disable comparison it really means we're disabling implicit conversion. Andrei
Sep 01 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:i5mfji$2qtd$1 digitalmars.com...
 I think it's a good enhancement. C++'s good old enum has been instrumental 
 in finding a few bugs and clarifying a few interfaces in a project at 
 work. Based on that experience I'd say that there's a chance more 
 restrictive is better. We need to find a principled way to define 
 semantics though - if we disable comparison it really means we're 
 disabling implicit conversion.

"...it really means we're disabling implicit conversion" And that's a problem?
Sep 01 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/1/10 16:39 CDT, Nick Sabalausky wrote:
 "Andrei Alexandrescu"<SeeWebsiteForEmail erdani.org>  wrote in message
 news:i5mfji$2qtd$1 digitalmars.com...
 I think it's a good enhancement. C++'s good old enum has been instrumental
 in finding a few bugs and clarifying a few interfaces in a project at
 work. Based on that experience I'd say that there's a chance more
 restrictive is better. We need to find a principled way to define
 semantics though - if we disable comparison it really means we're
 disabling implicit conversion.

"...it really means we're disabling implicit conversion" And that's a problem?

It's bound to break some code. Andrei
Sep 01 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Andrei:

 I think it's a good enhancement.

Good :-)
 C++'s good old enum has been 
 instrumental in finding a few bugs and clarifying a few interfaces in a 
 project at work. Based on that experience I'd say that there's a chance 
 more restrictive is better.

There is also the experience of the C++0x group of designers, and their "enum class". One of the purpose of those "enum class" is to remove implicit conversions to int: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1719.pdf
 We need to find a principled way to define 
 semantics though - if we disable comparison it really means we're 
 disabling implicit conversion.

I agree. If bug bug 3999 gets accepted in the form I meant, then probably the bug 4261 too may be considered, because then enums aren't "ints" and the most natural way to print them on default is by name and not by hidden representation value: http://d.puremagic.com/issues/show_bug.cgi?id=4261
 It's bound to break some code.

Yes, several of the about 25 entries of my 'short list' I have recently shown here are able to break some code. This is why I am showing them here now. I think of those bug reports are more "important" than the others I have put in Bugzilla because as more and more D2 code gets written, even tiny breaking changes become harder and harder to justify. Bye, bearophile
Sep 01 2010
prev sibling parent reply Don <nospam nospam.com> writes:
so wrote:
 Does this mean no more defining bits as enums?

Now that would be brutal, it is one of the best use cases of enum if not the best...

Yes. I reckon, if an enum doesn't explicitly define the value of each member, it shouldn't implicitly convert to int -- and it should not be possible to treat it as bits. OTOH if each member has an explicitly defined value, it's reasonable to perform logical operations on it.
Sep 02 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Don:
 OTOH if each member has an explicitly defined value, it's reasonable to 
 perform logical operations on it.

See my recent answer to Schveighoffer. I think that's not a fully good idea because when you define an enum like that and you use its values as powers-of-two flags, the type system doesn't help you enforce it is a true combination of the flags instead of a generic number (and you may put bugs when you define the values to assign to the flags), so I think something like a std.bitmanip.flagset that produces a struct is better when you need to define a flag set. Bye, bearophile
Sep 02 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"bearophile" <bearophileHUGS lycos.com> wrote in message 
news:i5p63u$2pl1$1 digitalmars.com...
 Don:
 OTOH if each member has an explicitly defined value, it's reasonable to
 perform logical operations on it.

See my recent answer to Schveighoffer. I think that's not a fully good idea because when you define an enum like that and you use its values as powers-of-two flags, the type system doesn't help you enforce it is a true combination of the flags instead of a generic number (and you may put bugs when you define the values to assign to the flags), so I think something like a std.bitmanip.flagset that produces a struct is better when you need to define a flag set.

I think all the discussions we've had about enum make it clear that enum suffers from a bit of an identity crisis. It doesn't know what it is and ends up being mediocre at everything it dabbles in.
Sep 02 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
  the type system doesn't help you enforce it is a true combination of the
flags instead of a generic number

I have used std.bitmanip.bitfields some time, and in my opinion its best quality is its overflow tests. They have caught few of my bugs (it's easy to overflow such little numbers). It's also another good example why having runtime integer overflow tests is a Good Thing. Bye, bearophile
Sep 02 2010
prev sibling parent reply Don <nospam nospam.com> writes:
bearophile wrote:
 Don:
 OTOH if each member has an explicitly defined value, it's reasonable to 
 perform logical operations on it.

See my recent answer to Schveighoffer. I think that's not a fully good idea because when you define an enum like that and you use its values as powers-of-two flags, the type system doesn't help you enforce it is a true combination of the flags instead of a generic number (and you may put bugs when you define the values to assign to the flags), so I think something like a std.bitmanip.flagset that produces a struct is better when you need to define a flag set. Bye, bearophile

That's impossible. That would make interfacing to C a nightmare. By the way, enums which consist of flags frequently have values which have more than one bit set. The case { A=1, B=2, C=4, D=8 } is only a special case. In the general case, it's not realistic to hope that the compiler could determine which values are valid, and which are not. But, with my suggestion, simple enums (a list of mutually exclusive values) would become strong enums.
Sep 02 2010
parent reply bearophile <bearophileHUGS lycos.com> writes:
Andrej Mitrovic:

 I just stumbled upon this in std.typecons:
 http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#defineEnum
 Might be useful from some, I guess.

Thank you. I think std.typecons.defineEnum() may be removed. I don't think it's useful now. Bye, bearophile
Sep 03 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 9/3/10 11:58 CDT, bearophile wrote:
 Andrej Mitrovic:

 I just stumbled upon this in std.typecons:
 http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#defineEnum
 Might be useful from some, I guess.

Thank you. I think std.typecons.defineEnum() may be removed. I don't think it's useful now. Bye, bearophile

Yah, that artifact predates the introspection means that make printing and parsing for enums possible. Andrei
Sep 03 2010
prev sibling next sibling parent so <so so.do> writes:
 Float (short for "floating point"): The decimal point can "float" around  
 as
 the value changes (not a literal use of "float", but there's nothing  
 wrong
 with metaphoric uses of words, even in ordinary speech). This type is  
 named
 in contrast to the fixed-point arithmetic that was often used as an
 old-school optimization (where the decimal point was always at a fixed
 location, for example, the high 16-bits may have been the whole-number  
 part,
 and the low 16-bits may have been the decimal part).

 Double: This one's easy: It's double the size of a float.

I know what they are, but at the same time was expecting you to get the point :) When you need a compile-time type in C/C++ mostly you don't need a type, just : enum { value = 10 }; // Also, this is suggested over const Coming from C/C++ enum constants are pretty straightforward as compile-time constants. And please, it is only 4 letters. (In case you missed, they are e, n, u, m. They are the 4 best looking characters on every editor!) This reminds me the "retro" case, where most argue against and making up names such like reverseAndSomeOtherUglyNonsense. Anyone here got trouble understanding what "enum" is and what it does? No, It wasn't the case in retro either. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling parent so <so so.do> writes:
 Float (short for "floating point"): The decimal point can "float" around  
 as
 the value changes (not a literal use of "float", but there's nothing  
 wrong
 with metaphoric uses of words, even in ordinary speech). This type is  
 named
 in contrast to the fixed-point arithmetic that was often used as an
 old-school optimization (where the decimal point was always at a fixed
 location, for example, the high 16-bits may have been the whole-number  
 part,
 and the low 16-bits may have been the decimal part).

 Double: This one's easy: It's double the size of a float.

If you throw "2.7f" on a water, does it float or you need to multiply with pi first? Why don't we change double to hmm... doubleTheSizeOfFloat? Lets test it! - manifest doubleTheSizeOfFloat pi=3.14; doubleTheSizeOfFloat f=2.7; if(!floats(f)) multiplyFirstOneWithTheSecondAndAssignToTheFirstParameter(f, pi); // that was the java operator overloading case? Yeh fundamental type but still it is funny! - enum pi=3.14; double f=2.7; if(!floats(f)) f *= pi; -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
This whole enum thing is making my head explode out of confusion. I
thought having a tag was just supossed to be used as a namespace for
enumerated values. E.g.:

enum { red =3D 1, green, blue }
...
if (getValue() =3D=3D green) {
    do..
}

and:

enum Tagged { red =3D 1, green, blue }
...
if (getValue() =3D=3D Tagged.green) {  // safer version
    do..
}

That is all that I thought enums are useful for. But apparently an
enum is a type and you can instantiate it.... and I don't even know
what an enum is anymore. I'll just stay out of this discussion for
now, lol. :)

 I agree, and I have never said I want to disallow it. You can cast those =

there:
 enum V1 =3D 10;
 enum { V2 =3D 20 }
 enum Foo { V3 }
 void main() {
 =A0 =A0assert(V1 =3D=3D 10); =A0 =A0// OK
 =A0 =A0assert(V2 =3D=3D 20); =A0 =A0// OK
 =A0 =A0assert(Foo.V3 =3D=3D 0); // ERROR, type mismatch
 }

 Thank you for your doubts and questions, they help me express better what=

 Bye,
 bearophile

Aug 31 2010
parent "Nick Sabalausky" <a a.a> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.28.1283307608.858.digitalmars-d puremagic.com...
That is all that I thought enums are useful for. But apparently an
enum is a type and you can instantiate it.... and I don't even know
what an enum is anymore. I'll just stay out of this discussion for
now, lol. :)

This is the way I've always seen an enum: An enum is a custom type with a pre-defined set of possible values, each individually-named. That's the primary purpose. Typically, an enum will have a "base" type which determines the physical in-memory representation of the values and allows for a convenient (but not accidentally-invoked) one-to-one mapping between the enum values and certain values from one other user-chosen type (ie, the base type).
Aug 31 2010
prev sibling next sibling parent so <so so.do> writes:
On Wed, 01 Sep 2010 11:06:51 +0300, Rainer Deyke <rainerd eldwood.com>  
wrote:

 On 8/31/2010 19:46, bearophile wrote:
 But you can use const for constants that are known at run-time only.
 While you can't use enum for constant known at run-time.

In C++, const is used for both run-time and compile-time constants. In practice, this works out fine. It its value can only be known at run-time, it's a run-time constant. If its value is used at compile-time, it's a compile-time constant. If both of these apply, it's an error. If neither applies, nobody cares if it's a compile-time or run-time constant. (The actual rules in C++ are a bit more complex, less intuitive, and less useful than that, which is presumably why Walter chose not to copy the C++ in this case. Still, overloading 'const' for both compile-time and run-time constants is viable, and more intuitive than the current situation with 'enum'.)

I have never had troubles with C++ compile/runtime "const" difference, and don't think it is a problem in C++. With this in mind "enum" is a great keyword of choice to express compile-time types, as long as it is forbidden for run-time constants. (I hope that example of bearophile is just a bug.) Thanks. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling next sibling parent so <so so.do> writes:
 (I hope that example of bearophile is just a bug.)

This one. void main(string[] args) { enum int n = args.length; } -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling next sibling parent so <so so.do> writes:
 ctconst is a fictional keyword that denotes compile-time constants. Now  
 you are probably able to see that there is no correlation between the n  
 and Color.

 In D they are using the same keyword by accident, probably because  
 Walter thinks that saving a keyword is more important than keeping the  
 semantics tidy.
 So today you are probably struck with using "enum" to define  
 compile-time constants.

 The C++0x design group has not introduced the "enum class" for fun,  
 their strong typing nature is useful to make the code less bug-prone.  
 See:
 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1719.pdf

 See for example "Problem 1: Implicit conversion to an integer".

 Bye,
 bearophile

Another taste discussion? Enum, again for "my taste" a great find for the job. Bugs aside, i can't seem to follow you. -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 01 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Tue, 31 Aug 2010 20:59:15 -0400, bearophile <bearophileHUGS lycos.com>  
wrote:

 Daniel Gibson:
 Then there still is the consistency-issue (anon. enums are treated
 differently then named enums).

Look at this:Se enum int n = 10; enum Color { Red, Green, Blue } Color color; if (color == Color.Red) { ... Color is a sequence of symbols, Red, Green and Blue, named Color. When you write your program often all you need to know is if color is Red or Green, and you don't care much how the compiler represents those symbols. The n is a compile-time constant value. It's not a sequence of something. Now, just for fun, replace the first enum with something as: ctconst int n = 10; enum Color { Red, Green, Blue } Color color; if (color == Color.Red) { ... ctconst is a fictional keyword that denotes compile-time constants. Now you are probably able to see that there is no correlation between the n and Color. In D they are using the same keyword by accident, probably because Walter thinks that saving a keyword is more important than keeping the semantics tidy.

AFAIK, enum meaning manifest constant was Andrei's request. And I think if you have an idea to try and "fix" it, you might as well know now, it will never happen. See this quote from Andrei in a bug report of mine (bug 1961): "And enum... you'll have to yank that out from my dead cold hands. Extending enum instead of adding yet another way of defining symbolic constants is The Right Thing to do. I am sure people would have realized how ridiculous the whole "manifest" thing is if we first proposed it. We just can't define one more way for each kind of snow there is." There was a point in D2 development with the 'manifest' keyword added to do exactly what enum now does (except for actual enumerations, for which enum was used). FWIW, I am not a huge fan of enum being used for meaning manifest constants that are not enumerations, but as far as daily usage, it's not really bad. It's somewhat of a petty problem, since enum is not functionally deficient. It just looks weird, especially to those used to other languages. I suppose you could think of it as an enumeration with one member :) -Steve
Sep 01 2010
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Wed, 01 Sep 2010 17:12:04 -0400, Andrei Alexandrescu  
<SeeWebsiteForEmail erdani.org> wrote:

 On 9/1/10 15:35 CDT, bearophile wrote:
 so:
 Another taste discussion?

Nope. ----------------- Steven Schveighoffer:
 And I think if you have an idea to try and "fix" it, you might as well  
 know now, it will never happen.<

There I was explaining something better to Daniel Gibson. The purpose of the enhancement request 3999 has nothing to do with a request for a different keyword. ----------------- I think now I have presented my point as well as I can, and people have given comments and opinions. I'd like to Walter or/and Andrei to express their opinion about the bug 3999 :-)

I think it's a good enhancement. C++'s good old enum has been instrumental in finding a few bugs and clarifying a few interfaces in a project at work. Based on that experience I'd say that there's a chance more restrictive is better. We need to find a principled way to define semantics though - if we disable comparison it really means we're disabling implicit conversion.

Does this mean no more defining bits as enums? enum myBits { flag1 = 1; flag2 = 2; flag3 = 4; } void fn(int flags); fn(myBits.flag1 | myBits.flag2); That was the one case where I really like the implicit conversion. -Steve
Sep 02 2010
prev sibling next sibling parent so <so so.do> writes:
 Does this mean no more defining bits as enums?

Now that would be brutal, it is one of the best use cases of enum if not the best... -- Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Sep 02 2010
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I just stumbled upon this in std.typecons:

http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#defineEnum

Might be useful from some, I guess.


On Fri, Sep 3, 2010 at 7:09 AM, Don <nospam nospam.com> wrote:

Sep 03 2010
prev sibling next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
bearophile schrieb:
 Daniel Gibson:
 I sometimes find it convenient to just treat those values as integers,

Yes, I am sure in some situations it can be handy. But it's a a bit of convenience that has a too much high price, the semantics is less clean, and it's more bug prone. So no thanks. Keeping things tidy is more important. Bye, bearophile

Then there still is the consistency-issue (anon. enums are treated differently then named enums). Apart from that inconsistency: Yes, it wouldn't be unreasonable to just cast the int to MyEnum or the other way round for comparison. (or, in my example: MyEnum x; stream.read(cast(int)x); ...) Cheers, - Daniel
Aug 31 2010
parent "Nick Sabalausky" <a a.a> writes:
"Daniel Gibson" <metalcaedes gmail.com> wrote in message 
news:mailman.26.1283301521.858.digitalmars-d puremagic.com...
 Then there still is the consistency-issue (anon. enums are treated 
 differently then named enums).

Anon. enums *are* fundamentally different from named enums. It's already inconsistent.
Aug 31 2010
prev sibling next sibling parent Daniel Gibson <metalcaedes gmail.com> writes:
bearophile wrote:
 
 ctconst is a fictional keyword that denotes compile-time constants. Now you
are probably able to see that there is no correlation between the n and Color.
 

Why not use the non-fictional const keyword? "The const attribute declares constants that can be evaluated at compile time."[1] "enum int n = 10;" looks really strange. I don't know if this is needed.. But "enum : int { FOO, BAR, BAZ };" does not look so strange to me and I'd prefer this to "const int FOO=0; const int BAR=1; const int BAZ=2;". The syntax is shorter, it shows that these keywords kind of belong together and the values are enumerated automatically. Cheers, - Daniel [1] http://www.digitalmars.com/d/1.0/attribute.html#const
Aug 31 2010
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
bearophile Wrote:

But enums are not integers

?? Where did you get it?
Sep 01 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Kagamin:

But enums are not integers

?? Where did you get it?

The whole point of this discussion about my enhancement request 3999 is to turn a certain subset of enums into "not integers" (or "not bytes", "not longs", etc). Bye, bearophile
Sep 01 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday, September 01, 2010 12:59:01 Nick Sabalausky wrote:
 "Jonathan M Davis" <jmdavisprog gmail.com> wrote in message
 news:mailman.33.1283368612.858.digitalmars-d puremagic.com...
 
 Personally, I don't really care about using enum the way it is. Having
 enums
 freely converting to and from their base type is more of a concern,
 though I'm
 not sure how much that really does or doesn't matter.

I find it to be a pain nearly every time I need to convert one to a string.

I wasn't even aware that there was a way. If I had to guess, I would assume that it involves stringof, but I'd have to try it. Now, assuming that that's the case, it would be pretty easy to write a template function which takes the enum type and the value to stringify, and it returns the string version of that enum value (or throws if it's not a valid value for that enum type). I can see how having it as a distinct type would be more desirable for that though, since then you could likely just use stringof on it directly. - Jonathan M Davis
Sep 01 2010
prev sibling next sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
I thought to!string(Enum) already does this? This was the example I
posted in bug report 4261:

import std.conv : to;
import std.stdio: writeln;
void main()
{
    enum Foo { Zero, One }
    Foo f = Foo.One;
    writeln(to!string(f));
}

Prints: One

On Wed, Sep 1, 2010 at 10:50 PM, Jonathan M Davis <jmdavisprog gmail.com> wrote:
 On Wednesday, September 01, 2010 12:59:01 Nick Sabalausky wrote:
 "Jonathan M Davis" <jmdavisprog gmail.com> wrote in message
 news:mailman.33.1283368612.858.digitalmars-d puremagic.com...

 Personally, I don't really care about using enum the way it is. Having
 enums
 freely converting to and from their base type is more of a concern,
 though I'm
 not sure how much that really does or doesn't matter.

I find it to be a pain nearly every time I need to convert one to a string.

I wasn't even aware that there was a way. If I had to guess, I would assume that it involves stringof, but I'd have to try it. Now, assuming that that's the case, it would be pretty easy to write a template function which takes the enum type and the value to stringify, and it returns the string version of that enum value (or throws if it's not a valid value for that enum type). I can see how having it as a distinct type would be more desirable for that though, since then you could likely just use stringof on it directly. - Jonathan M Davis

Sep 01 2010
parent "Nick Sabalausky" <a a.a> writes:
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message 
news:mailman.49.1283374449.858.digitalmars-d puremagic.com...
I thought to!string(Enum) already does this? This was the example I
 posted in bug report 4261:

 import std.conv : to;
 import std.stdio: writeln;
 void main()
 {
    enum Foo { Zero, One }
    Foo f = Foo.One;
    writeln(to!string(f));
 }

 Prints: One

Does it really work that way now? That must have changed then. I could swear it wasn't like that before.
Sep 01 2010
prev sibling next sibling parent Jonathan M Davis <jmdavisprog gmail.com> writes:
On Wednesday, September 01, 2010 13:53:51 Andrej Mitrovic wrote:
 I thought to!string(Enum) already does this? This was the example I
 posted in bug report 4261:
 
 import std.conv : to;
 import std.stdio: writeln;
 void main()
 {
     enum Foo { Zero, One }
     Foo f = Foo.One;
     writeln(to!string(f));
 }
 
 Prints: One

Well, like I said, it never occurred to me that you even could print enums as strings in D, so I don't know how it's typically done. However, if it's as simple as that, I don't really see what the problem is. Sure, it would be nice if they printed as strings by default rather than the generally useless base type of int or whatever, but using to!string like that is quite straightforward. - Jonathan M Davis
Sep 01 2010
prev sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
That's how it's described in TDPL, and yes it works.

On Wed, Sep 1, 2010 at 11:38 PM, Nick Sabalausky <a a.a> wrote:
 "Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message
 news:mailman.49.1283374449.858.digitalmars-d puremagic.com...
I thought to!string(Enum) already does this? This was the example I
 posted in bug report 4261:

 import std.conv : to;
 import std.stdio: writeln;
 void main()
 {
 =A0 =A0enum Foo { Zero, One }
 =A0 =A0Foo f =3D Foo.One;
 =A0 =A0writeln(to!string(f));
 }

 Prints: One

Does it really work that way now? That must have changed then. I could sw=

 it wasn't like that before.

Sep 01 2010