www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Enums - probably an old subject

reply "Steve Teale" <steve.teale britseyeview.com> writes:
import std.stdio;

enum Intention
{
    EVIL,
    NEUTRAL,
    GOOD,
    SAINTLY
}

void foo(Intention rth)
{
    if (rth == EVIL)
       writeln("Road to hell");
}


void main()
{
    foo(EVIL);
}


Why does the compiler complain in both places about EVIL. Can it 
not work out which EVIL I mean? There's only one choice.
Nov 20 2013
next sibling parent reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Thursday, 21 November 2013 at 07:22:39 UTC, Steve Teale wrote:
 import std.stdio;

 enum Intention
 {
    EVIL,
    NEUTRAL,
    GOOD,
    SAINTLY
 }

 void foo(Intention rth)
 {
    if (rth == EVIL)
       writeln("Road to hell");
 }


 void main()
 {
    foo(EVIL);
 }


 Why does the compiler complain in both places about EVIL. Can 
 it not work out which EVIL I mean? There's only one choice.
That should be: if( rth == Intention.EVIL ) and foo( Intention.EVIL );
Nov 20 2013
next sibling parent reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Thursday, 21 November 2013 at 07:28:14 UTC, Craig Dillabaugh
wrote:
 On Thursday, 21 November 2013 at 07:22:39 UTC, Steve Teale 
 wrote:
clip
 Why does the compiler complain in both places about EVIL. Can 
 it not work out which EVIL I mean? There's only one choice.
That should be: if( rth == Intention.EVIL ) and foo( Intention.EVIL );
I should also mention, this post likely better belongs in: digitalmars.D.learn That is the best place for questions about how the language works. This forum is more a place for the D Pros to fight it out over what features should/shouldn't be in the langauge.
Nov 20 2013
parent reply "Michal Minich" <michal.minich gmail.com> writes:
On Thursday, 21 November 2013 at 07:42:48 UTC, Craig Dillabaugh 
wrote:
 I should also mention, this post likely better belongs in:

 digitalmars.D.learn
I don't entirely think so. I think the OP is arguing that D should be able to identify symbol as specific enum's field when used: - in place of function argument when the fn parameters is of enum type - and when comparing for equality with variable of enum type. ie. the lookup of the symbol should be first inside the enum, and the continue normally. There was plan long long time ago to implement it, but I don't remember for which reason it was not. In order to consider this again for implementation I think proper DIP should be written where complete semantics of this should be described. For one I don't know how it should be have if you would have variable of the same name as enum field i.e: enum State { on, off } auto State s; auto on = 1; if (on == on) ? And I think it would be especially confusing when enum which is function parameters has the same field name as local variable on call site: void change (State s) {} void main () { State on = State.off, change (on) }
Nov 21 2013
next sibling parent reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Thursday, 21 November 2013 at 08:05:03 UTC, Michal Minich
wrote:
 On Thursday, 21 November 2013 at 07:42:48 UTC, Craig Dillabaugh 
 wrote:
 I should also mention, this post likely better belongs in:

 digitalmars.D.learn
I don't entirely think so. I think the OP is arguing that D should be able to identify symbol as specific enum's field when used: - in place of function argument when the fn parameters is of enum type - and when comparing for equality with variable of enum type.
Yes, perhaps that was his intention (no pun intended). First few times I used enums in D I was caught because I expected the behavior he is suggesting here would work.
Nov 21 2013
parent "Steve Teale" <steve.teale britseyeview.com> writes:
On Thursday, 21 November 2013 at 08:37:32 UTC, Craig Dillabaugh 
wrote:
 Yes, perhaps that was his intention (no pun intended). First few
 times I used enums in D I was caught because I expected the
 behavior he is suggesting here would work.
Pun was intended ;=)
Nov 21 2013
prev sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
On Thursday, 21 November 2013 at 08:05:03 UTC, Michal Minich 
wrote:
 On Thursday, 21 November 2013 at 07:42:48 UTC, Craig Dillabaugh 
 wrote:
 I should also mention, this post likely better belongs in:

 digitalmars.D.learn
I don't entirely think so. I think the OP is arguing that D should be able to identify symbol as specific enum's field when used: - in place of function argument when the fn parameters is of enum type - and when comparing for equality with variable of enum type. ie. the lookup of the symbol should be first inside the enum, and the continue normally. There was plan long long time ago to implement it, but I don't remember for which reason it was not. In order to consider this again for implementation I think proper DIP should be written where complete semantics of this should be described. For one I don't know how it should be have if you would have variable of the same name as enum field i.e: enum State { on, off } auto State s; auto on = 1; if (on == on) ? And I think it would be especially confusing when enum which is function parameters has the same field name as local variable on call site: void change (State s) {} void main () { State on = State.off, change (on) }
Michal, Well thank you for a sane reply! I've been with D since about 2006, and I prefer to not make a complete fool of myself. I have to admit that the question was asked in anger. I was working on some old code, and saw this large bare enum, so I gave it a qualifier. It then took me about six hours to stubbornly go through the rest of the code to add the qualifier - aargh! Yes, I agree that the circumstances under which the inference could be made may be limited, but in a function where a single argument is an enum name it's really surprising that it is not implemented. Could 'with' be extended to cover enum names do you think? Also a supplementary question - does auto lock out some things like this, are there other examples?
Nov 21 2013
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 11/21/13 8:48 AM, Steve Teale wrote:
 Could 'with' be extended to cover enum names do you think? Also a
 supplementary question - does auto lock out some things like this, are
 there other examples?
Guess it could. One other thing we could do is to make enum namespaces behave like imports. Andrei
Nov 21 2013
next sibling parent "Brad Anderson" <eco gnuk.net> writes:
On Thursday, 21 November 2013 at 17:39:28 UTC, Andrei 
Alexandrescu wrote:
 On 11/21/13 8:48 AM, Steve Teale wrote:
 Could 'with' be extended to cover enum names do you think? 
 Also a
 supplementary question - does auto lock out some things like 
 this, are
 there other examples?
Guess it could. One other thing we could do is to make enum namespaces behave like imports. Andrei
+1. I love this idea. Verbosity only when necessary.
Nov 21 2013
prev sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
On Thursday, 21 November 2013 at 17:39:28 UTC, Andrei 
Alexandrescu wrote:
 On 11/21/13 8:48 AM, Steve Teale wrote:
 Could 'with' be extended to cover enum names do you think? 
 Also a
 supplementary question - does auto lock out some things like 
 this, are
 there other examples?
Guess it could. One other thing we could do is to make enum namespaces behave like imports. Andrei
I'd love to understand "make enum namespaces behave like imports", but I should probably ask that on D Learn ;=)
Nov 21 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 21 November 2013 at 18:44:39 UTC, Steve Teale wrote:
 On Thursday, 21 November 2013 at 17:39:28 UTC, Andrei 
 Alexandrescu wrote:
 On 11/21/13 8:48 AM, Steve Teale wrote:
 Could 'with' be extended to cover enum names do you think? 
 Also a
 supplementary question - does auto lock out some things like 
 this, are
 there other examples?
Guess it could. One other thing we could do is to make enum namespaces behave like imports. Andrei
I'd love to understand "make enum namespaces behave like imports", but I should probably ask that on D Learn ;=)
When you import from a module, you only need to specify the module name if there is ambiguity. So for example: //---- import std.array; void main() { split("hello"); //OK! } //---- import std.array; import std.algorithm; void main() { split("hello"); //Wait... did you want std.algorithm.split, or std.array.split? std.array.split("hello"); //OK! That's clearer now. } //---- What Andrei is saying is that an enum *could* work the same way: enum RedBlack //For red black trees { Red, Black, } enum BlackWhite //For Checker boards { Black, White, } void main() { writeln(Red); //OK! No problem! writeln(Black); //I'm sorry... that's ambiguous :/ writeln(RedBlack.Black); //OK! That's clearer now! } Whether or not it *should*, I don't know. "Why not?" I like to say :)
Nov 21 2013
parent reply John J <john.joyus gmail.com> writes:
On 11/21/2013 02:20 PM, monarch_dodra wrote:
 When you import from a module, you only need to specify the module name
 if there is ambiguity. So for example:

 //----
 import std.array;

 void main()
 {
      split("hello"); //OK!
 }
 //----
 import std.array;
 import std.algorithm;

 void main()
 {
      split("hello"); //Wait... did you want std.algorithm.split, or
 std.array.split?
      std.array.split("hello"); //OK! That's clearer now.
 }
 //----

 What Andrei is saying is that an enum *could* work the same way:

 enum RedBlack //For red black trees
 {
      Red,
      Black,
 }
 enum BlackWhite //For Checker boards
 {
      Black,
      White,
 }

 void main()
 {
      writeln(Red); //OK! No problem!
      writeln(Black); //I'm sorry... that's ambiguous :/
      writeln(RedBlack.Black); //OK! That's clearer now!
 }

 Whether or not it *should*, I don't know. "Why not?" I like to say :)
If both these enums are coming from a module and I also have a RedBlack enum in my main program that has Black in it, then I guess it would be modulename.RedBlack.Black to call the one from the module. Does it make sense? I should be really in D.learn but asked that here in context ;)
Nov 21 2013
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 22 November 2013 at 00:50:25 UTC, John J wrote:
 On 11/21/2013 02:20 PM, monarch_dodra wrote:
 When you import from a module, you only need to specify the 
 module name
 if there is ambiguity. So for example:

 //----
 import std.array;

 void main()
 {
     split("hello"); //OK!
 }
 //----
 import std.array;
 import std.algorithm;

 void main()
 {
     split("hello"); //Wait... did you want 
 std.algorithm.split, or
 std.array.split?
     std.array.split("hello"); //OK! That's clearer now.
 }
 //----

 What Andrei is saying is that an enum *could* work the same 
 way:

 enum RedBlack //For red black trees
 {
     Red,
     Black,
 }
 enum BlackWhite //For Checker boards
 {
     Black,
     White,
 }

 void main()
 {
     writeln(Red); //OK! No problem!
     writeln(Black); //I'm sorry... that's ambiguous :/
     writeln(RedBlack.Black); //OK! That's clearer now!
 }

 Whether or not it *should*, I don't know. "Why not?" I like to 
 say :)
If both these enums are coming from a module and I also have a RedBlack enum in my main program that has Black in it, then I guess it would be modulename.RedBlack.Black to call the one from the module. Does it make sense? I should be really in D.learn but asked that here in context ;)
If the enum's name is RedBlack, and you want the Black value, than yes., you'd need to "double disambiguate". If you wanted Red though, then: modulename.Red Should be enough to un-ambiguously refer to the correct enum value.
Nov 21 2013
prev sibling parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
 Does it make sense?
 I should be really in D.learn but asked that here in context ;)
Sounds like most of us should be in D Learn on this topic. I should find the time to write up a case for Andrei's suggestion. I have no problem with the compiler telling me that my code is ambiguous, in fact I depend on it!
Nov 22 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 22 November 2013 at 17:34:09 UTC, Steve Teale wrote:
 Does it make sense?
 I should be really in D.learn but asked that here in context ;)
Sounds like most of us should be in D Learn on this topic. I should find the time to write up a case for Andrei's suggestion. I have no problem with the compiler telling me that my code is ambiguous, in fact I depend on it!
The "problem" with this approach though, is that if you import my module, and I introduce a new enum in my module, I could *break* your code by introducing ambiguity. Not that it's any different from adding functions in modules, that could create ambiguity of course. That said, functions have a "tendency" of not actually being ambiguous thanks to the fact that they overload on their arguments. enums on the other hand, have *no* contextual information to disambiguate.
Nov 22 2013
prev sibling parent "Meta" <jared771 gmail.com> writes:
On Thursday, 21 November 2013 at 16:48:59 UTC, Steve Teale wrote:
 Could 'with' be extended to cover enum names do you think? Also 
 a supplementary question - does auto lock out some things like 
 this, are there other examples?
Is this what you mean? enum Intention { EVIL, NEUTRAL, GOOD, SAINTLY, } void main() { with (Intention) { assert(EVIL == 0); assert(NEUTRAL == 1); assert(GOOD == 2); assert(SAINTLY == 3); } }
Nov 21 2013
prev sibling parent "Steve Teale" <steve.teale britseyeview.com> writes:
 That should be:

 if( rth == Intention.EVIL ) and
 foo( Intention.EVIL );
Phobos is less picky than the compiler. Try this: import std.stdio; enum Intention { EVIL, NEUTRAL, GOOD, SAINTLY } void foo(Intention rth) { if (rth == Intention.EVIL) writefln("The road to hell is paved with %s and %d", rth, rth); } void main() { foo(Intention.EVIL); }
Nov 21 2013
prev sibling next sibling parent "Daniel Kozak" <kozzi11 gmail.com> writes:
On Thursday, 21 November 2013 at 07:22:39 UTC, Steve Teale wrote:
 import std.stdio;

 enum Intention
 {
    EVIL,
    NEUTRAL,
    GOOD,
    SAINTLY
 }

 void foo(Intention rth)
 {
    if (rth == EVIL)
       writeln("Road to hell");
 }


 void main()
 {
    foo(EVIL);
 }


 Why does the compiler complain in both places about EVIL. Can 
 it not work out which EVIL I mean? There's only one choice.
I don't think it would be a good idea to let a compiler decide which symbol I mean :). So you must use Intention.EVIL instead of just EVIL. Or you can do some trick like this: enum Intention : int {_} enum : Intention { EVIL = cast(Intention)0, NEUTRAL = cast(Intention)1, GOOD = cast(Intention)2, SAINTLY = cast(Intention)3, } void foo(Intention rth) { if (rth == EVIL) writeln("Road to hell"); } void main() { foo(EVIL); } or use aliases: enum Intention { EVIL, NEUTRAL, GOOD, SAINTLY, } alias EVIL = Intention.EVIL; alias NEUTRAL = Intention.NEUTRAL; alias GOOD = Intention.GOOD; alias SAINTLY = Intention.SAINTLY; void foo(Intention rth) { if (rth == EVIL) writeln("Road to hell"); } void main() { foo(EVIL); }
Nov 21 2013
prev sibling parent reply "inout" <inout gmail.com> writes:
On Thursday, 21 November 2013 at 07:22:39 UTC, Steve Teale wrote:
 import std.stdio;

 enum Intention
 {
    EVIL,
    NEUTRAL,
    GOOD,
    SAINTLY
 }

 void foo(Intention rth)
 {
    if (rth == EVIL)
       writeln("Road to hell");
 }


 void main()
 {
    foo(EVIL);
 }


 Why does the compiler complain in both places about EVIL. Can 
 it not work out which EVIL I mean? There's only one choice.
Because of the follwoing: import foo.bar; enum Intention { EVIL, NEUTRAL, GOOD, SAINTLY } void foo(Intention rth) { ... } void main() { // imagine that this works foo(EVIL); } module foo.bar; // someone else adds this later enum OtherIntention { EVIL, NEUTRAL, GOOD, SAINTLY } BOOM! Code no longer compiles. As a rule, the code that compiles and works should preserve its behavior when new code is added, so this is prohibited. Also please post to D.learn
Nov 21 2013
parent reply "inout" <inout gmail.com> writes:
On Thursday, 21 November 2013 at 17:19:18 UTC, inout wrote:
 On Thursday, 21 November 2013 at 07:22:39 UTC, Steve Teale 
 wrote:
 import std.stdio;

 enum Intention
 {
   EVIL,
   NEUTRAL,
   GOOD,
   SAINTLY
 }

 void foo(Intention rth)
 {
   if (rth == EVIL)
      writeln("Road to hell");
 }


 void main()
 {
   foo(EVIL);
 }


 Why does the compiler complain in both places about EVIL. Can 
 it not work out which EVIL I mean? There's only one choice.
Because of the follwoing: import foo.bar; enum Intention { EVIL, NEUTRAL, GOOD, SAINTLY } void foo(Intention rth) { ... } void main() { // imagine that this works foo(EVIL); } module foo.bar; // someone else adds this later enum OtherIntention { EVIL, NEUTRAL, GOOD, SAINTLY } BOOM! Code no longer compiles. As a rule, the code that compiles and works should preserve its behavior when new code is added, so this is prohibited. Also please post to D.learn
forgot to add: void foo(OtherIntention rth) { ... } Which of the two is being called by main?
Nov 21 2013
parent reply "Steve Teale" <steve.teale britseyeview.com> writes:
 BOOM! Code no longer compiles.

 As a rule, the code that compiles and works should preserve 
 its behavior when new code is added, so this is prohibited.

 Also please post to D.learn
forgot to add: void foo(OtherIntention rth) { ... } Which of the two is being called by main?
I thought that compilers were supposed to help you if you did ambiguous things. An interesting example is: int bar(int n) { return n+1; } int bar(int n) { return n+2; } void main() { int v = 22; int n = bar(22); }
Nov 21 2013
parent John J <john.joyus gmail.com> writes:
On 11/21/2013 01:36 PM, Steve Teale wrote:
 I thought that compilers were supposed to help you if you did ambiguous
 things. An interesting example is:

 int bar(int n)
 {
     return n+1;
 }

 int bar(int n)
 {
     return n+2;
 }

 void main()
 {
     int v = 22;
     int n = bar(22);
 }
Compiler helps here by throwing an error. Those are two duplicate functions with same exact arguments.
Nov 21 2013