Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
December 15, 2013 enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
While I must first Admit I'm new to D. However; I have been a C/C++ programmer for 15 years. I am excited about D. One of the features I love is being able to access my legacy code. But there are some cases were a complete re-write/re-factor to D makes sense. I've come to it very frustrating code that has been stable for years now needs to be changed because of a language quirk. The main selling point about D is C/C++ is almost the same syntax, I see potential in D to replace C/C++. I've noticed that enum behavior is dramatically different. This is my opinion, but I see this as a flaw in D. Again let me repeat, My opinion. While I understand D's approach to enum's. It is a hard pill to swallow for an experienced programmer. The D compiler should know the type of the enum from the symbol. You should not have to type the NAME.element when doing a comparison or assignment. Declaring an enum FOO { one, two, three} should be the same as declaring a new type. So that when you declare `FOO bar;` in code, assignment and comparison of `bar` should know what bar is comprised of because it is of type enum FOO. Therefore anything of type enum FOO can only comprise of the values 'one', 'two', or 'three'. I've prepared 3 examples, a C, C++, and Finally D. All essentially the same code. You will notice that the D version, has some vast differences. For example you can not define an enum and declare the variable all at once. This gets me to the annoying part. assigning and Comparing. jrice@Wayland:~/prj/enum_example$ gcc -o enum_c enum.c jrice@Wayland:~/prj/enum_example$ g++ -o enum_cpp enum.cpp jrice@Wayland:~/prj/enum_example$ dmd enum.d jrice@Wayland:~/prj/enum_example$ ./enum_c It's test1 jrice@Wayland:~/prj/enum_example$ ./enum_cpp It's test1 jrice@Wayland:~/prj/enum_example$ ./enum It's test1 jrice@Wayland:~/prj/enum_example$ cat enum.c #include <stdio.h> void main() { enum TEST { test1=0, test2 } test; test = test1; switch (test) { case test1: printf("It's test1\n"); break; case test2: printf("It's test2\n"); break; default: break; } } jrice@Wayland:~/prj/enum_example$ cat enum.cpp #include <iostream> using namespace std; int main() { enum TEST { test1=0, test2 } test; test = test1; switch (test) { case test1: cout << "It's test1" << endl; break; case test2: cout << "It's test2" << endl; break; default: break; } return 0; } jrice@Wayland:~/prj/enum_example$ cat enum.d import std.stdio; void main() { enum TEST { test1=0, test2 }; TEST test = TEST.test1; switch (test) { case TEST.test1: writeln("It's test1"); break; case TEST.test2: writeln("It's test2"); break; default: break; } } So as you can see, D is just awkward, and it becomes tedious especially if you have many many many values in the enum. So D language Designers and maintainers: 1st I understand your reasons, it makes it un-ambiguous, becaause you know exactly which enum `test1` belongs too. 2nd What the heck, why do I have to type extra. It makes porting a little mre frustrating, and makes me question using D in the first place. 3rd I'm Pleading to you to consider making both syntax's valid. The Old C/C++ way, and the D way. If you have too, make compiler flag. |
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rice | Am Sun, 15 Dec 2013 02:16:39 +0100 schrieb "Joseph Rice" <ricejm01@gmail.com>: > While I must first Admit I'm new to D. However; I have been a C/C++ programmer for 15 years. I am excited about D. One of the features I love is being able to access my legacy code. But there are some cases were a complete re-write/re-factor to D makes sense. I've come to it very frustrating code that has been stable for years now needs to be changed because of a language quirk. The main selling point about D is C/C++ is almost the same syntax, I see potential in D to replace C/C++. > > I've noticed that enum behavior is dramatically different. This is my opinion, but I see this as a flaw in D. Again let me repeat, My opinion. While I understand D's approach to enum's. It is a hard pill to swallow for an experienced programmer. > > The D compiler should know the type of the enum from the symbol. You should not have to type the NAME.element when doing a comparison or assignment. Declaring an enum FOO { one, two, three} should be the same as declaring a new type. So that when you declare `FOO bar;` in code, assignment and comparison of `bar` should know what bar is comprised of because it is of type enum FOO. Therefore anything of type enum FOO can only comprise of the values 'one', 'two', or 'three'. > > I've prepared 3 examples, a C, C++, and Finally D. All essentially the same code. You will notice that the D version, has some vast differences. For example you can not define an enum and declare the variable all at once. This gets me to the annoying part. assigning and Comparing. > > jrice@Wayland:~/prj/enum_example$ gcc -o enum_c enum.c > jrice@Wayland:~/prj/enum_example$ g++ -o enum_cpp enum.cpp > jrice@Wayland:~/prj/enum_example$ dmd enum.d > jrice@Wayland:~/prj/enum_example$ ./enum_c > It's test1 > jrice@Wayland:~/prj/enum_example$ ./enum_cpp > It's test1 > jrice@Wayland:~/prj/enum_example$ ./enum > It's test1 > jrice@Wayland:~/prj/enum_example$ cat enum.c > #include <stdio.h> > > void main() { > enum TEST { > test1=0, > test2 > } test; > > test = test1; > > switch (test) { > case test1: > printf("It's test1\n"); > break; > case test2: > printf("It's test2\n"); > break; > default: > break; > } > } > jrice@Wayland:~/prj/enum_example$ cat enum.cpp > #include <iostream> > using namespace std; > > int main() { > enum TEST { > test1=0, > test2 > } test; > > test = test1; > > switch (test) { > case test1: > cout << "It's test1" << endl; > break; > case test2: > cout << "It's test2" << endl; > break; > default: > break; > } > return 0; > } > jrice@Wayland:~/prj/enum_example$ cat enum.d > import std.stdio; > > void main() { > enum TEST { > test1=0, > test2 > }; > > TEST test = TEST.test1; > > switch (test) { > case TEST.test1: > writeln("It's test1"); > break; > case TEST.test2: > writeln("It's test2"); > break; > default: > break; > } > } > > So as you can see, D is just awkward, and it becomes tedious especially if you have many many many values in the enum. void main() { enum TEST { test1, test2 } TEST test = TEST.test1; with(TEST) final switch (test) { case test1: writeln("It's test1"); break; case test2: writeln("It's test2"); break; } } -- Marco |
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rice | Joseph Rice:
> import std.stdio;
>
> void main() {
> enum TEST {
> test1=0,
> test2
> };
>
> TEST test = TEST.test1;
>
> switch (test) {
> case TEST.test1:
> writeln("It's test1");
> break;
> case TEST.test2:
> writeln("It's test2");
> break;
> default:
> break;
> }
> }
This is how you usually write that code in D:
void main() {
import std.stdio;
enum Test { t1, t2 }
auto test = Test.t1;
final switch (test) with (Test) {
case t1:
writeln("It's t1");
break;
case t2:
writeln("It's t2");
break;
}
}
The differences:
- The import is often better in the function.
- Type names (like Test) are better written with just the first letter uppercase.
- You often have to carry the type name around, so using shorter names is sometimes OK (like t1 and t2).
- In this code you want a final switch.
- Using with() you avoid repeating the enum type name.
In D you also have anonymous enums:
enum { test1, test2 }
Also, when you refer to C++, it's better to use the "enum class" of C++11.
D enums have some faults, like being weakly typed, having bad error messages, and sometimes being a bit too much long to write (when you pass an enum to a function, the function already knows the name of the enum type. But this is not so bad...).
Bye,
bearophile
|
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Sunday, 15 December 2013 at 01:52:01 UTC, bearophile wrote:
> D enums have some faults...
I've been in enough large scale C++ projects to enjoy D's verbose approach. Sure, C++ is convenient and works 99% of the time. But all you need is for some retard to create a Global enum containing things like the words "Yes, No, True, False, Red, Black, White", and then he's ruined it for *everyone* on the project.
|
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | On Sunday, 15 December 2013 at 08:29:59 UTC, monarch_dodra wrote:
> On Sunday, 15 December 2013 at 01:52:01 UTC, bearophile wrote:
>> D enums have some faults...
>
> I've been in enough large scale C++ projects to enjoy D's verbose approach. Sure, C++ is convenient and works 99% of the time. But all you need is for some retard to create a Global enum containing things like the words "Yes, No, True, False, Red, Black, White", and then he's ruined it for *everyone* on the project.
Resulting in people giving name like TestT1, TestT2 as enum values in C++. As a result, you end up with the same verbosity as in D, without the possibility of using 'with'.
|
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rice | Am 15.12.2013 02:16, schrieb Joseph Rice:
> While I must first Admit I'm new to D. However; I have been a C/C++
> programmer for 15 years. I am excited about D. One of the features I
> love is being able to access my legacy code. But there are some cases
> were a complete re-write/re-factor to D makes sense. I've come to it
> very frustrating code that has been stable for years now needs to be
> changed because of a language quirk. The main selling point about D is
> C/C++ is almost the same syntax, I see potential in D to replace C/C++.
>
> I've noticed that enum behavior is dramatically different. This is my
> opinion, but I see this as a flaw in D. Again let me repeat, My
> opinion. While I understand D's approach to enum's. It is a hard pill
> to swallow for an experienced programmer.
>
> The D compiler should know the type of the enum from the symbol. You
> should not have to type the NAME.element when doing a comparison or
> assignment. Declaring an enum FOO { one, two, three} should be the
> same as declaring a new type. So that when you declare `FOO bar;` in
> code, assignment and comparison of `bar` should know what bar is
> comprised of because it is of type enum FOO. Therefore anything of
> type enum FOO can only comprise of the values 'one', 'two', or 'three'.
>
> I've prepared 3 examples, a C, C++, and Finally D. All essentially the
> same code. You will notice that the D version, has some vast
> differences. For example you can not define an enum and declare the
> variable all at once. This gets me to the annoying part. assigning
> and Comparing.
>
> jrice@Wayland:~/prj/enum_example$ gcc -o enum_c enum.c
> jrice@Wayland:~/prj/enum_example$ g++ -o enum_cpp enum.cpp
> jrice@Wayland:~/prj/enum_example$ dmd enum.d
> jrice@Wayland:~/prj/enum_example$ ./enum_c
> It's test1
> jrice@Wayland:~/prj/enum_example$ ./enum_cpp
> It's test1
> jrice@Wayland:~/prj/enum_example$ ./enum
> It's test1
> jrice@Wayland:~/prj/enum_example$ cat enum.c
> #include <stdio.h>
>
> void main() {
> enum TEST {
> test1=0,
> test2
> } test;
>
> test = test1;
>
> switch (test) {
> case test1:
> printf("It's test1\n");
> break;
> case test2:
> printf("It's test2\n");
> break;
> default:
> break;
> }
> }
> jrice@Wayland:~/prj/enum_example$ cat enum.cpp
> #include <iostream>
> using namespace std;
>
> int main() {
> enum TEST {
> test1=0,
> test2
> } test;
>
> test = test1;
>
> switch (test) {
> case test1:
> cout << "It's test1" << endl;
> break;
> case test2:
> cout << "It's test2" << endl;
> break;
> default:
> break;
> }
> return 0;
> }
> jrice@Wayland:~/prj/enum_example$ cat enum.d
> import std.stdio;
>
> void main() {
> enum TEST {
> test1=0,
> test2
> };
>
> TEST test = TEST.test1;
>
> switch (test) {
> case TEST.test1:
> writeln("It's test1");
> break;
> case TEST.test2:
> writeln("It's test2");
> break;
> default:
> break;
> }
> }
>
> So as you can see, D is just awkward, and it becomes tedious especially
> if you have many many many values in the enum.
>
>
> So D language Designers and maintainers:
>
> 1st
>
> I understand your reasons, it makes it un-ambiguous, becaause you know
> exactly which enum `test1` belongs too.
>
> 2nd
>
> What the heck, why do I have to type extra. It makes porting a little
> mre frustrating, and makes me question using D in the first place.
>
> 3rd
>
> I'm Pleading to you to consider making both syntax's valid. The Old
> C/C++ way, and the D way. If you have too, make compiler flag.
It follows the same approach as many other modern languages, even C++ has them nowadays.
Obviously, the world at large has come to the conclusion that having enum identifiers creeping into global scope in C was not a good idea.
--
Paulo
|
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to Joseph Rice | On 15 December 2013 01:16, Joseph Rice <ricejm01@gmail.com> wrote: > > So as you can see, D is just awkward, and it becomes tedious especially if you have many many many values in the enum. > > You are in for a shock when you hear about C++11 http://www.stroustrup.com/C++11FAQ.html#enum That particular FAQ gives a good overview of the rationale of D enums when someone comes from a C++ background, and we should have something similar to describe the difference in the Porting / Interfacing to C/C++ pages. |
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | monarch_dodra:
> I've been in enough large scale C++ projects to enjoy D's verbose approach. Sure, C++ is convenient and works 99% of the time. But all you need is for some retard to create a Global enum containing things like the words "Yes, No, True, False, Red, Black, White", and then he's ruined it for *everyone* on the project.
By the way, I am not criticizing "D verbose approach". I have criticized the weak typing:
enum Foo { good, bad }
void main() {
int x = Foo.good; // Weak typing.
}
And some people have criticized the verbosity in special situations, like this:
enum Foo { good, bad }
void bar(Foo f) {}
void main() {
// bar(bad); // Not enough
bar(Foo.bad);
}
Bye,
bearophile
|
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | On Sunday, 15 December 2013 at 11:27:51 UTC, bearophile wrote: > By the way, I am not criticizing "D verbose approach". I have criticized the weak typing: > > enum Foo { good, bad } > void main() { > int x = Foo.good; // Weak typing. > } Hum... Well, it's not actually weak typing. It's strong typing with implicit cast *to* the base type (int by default). For example: enum Foo { a, b, c, } void foo(Foo) {} void main() { foo(1); //Nope. I want a Foo. } Whether this is a good or bad thing I don't know. If D where "just" D, I'd say it's a bad thing (it should require an explicit cast). However, arguably, there might be enough C heritage in D to justify it. As long as we don't have "int to enum" implicit conversion, I think it's fine. > And some people have criticized the verbosity in special situations, like this: > > > enum Foo { good, bad } > void bar(Foo f) {} > void main() { > // bar(bad); // Not enough > bar(Foo.bad); > } I am of those that think this is a good thing. > Bye, > bearophile |
December 15, 2013 Re: enum behaivor. another rehash of the topic | ||||
---|---|---|---|---|
| ||||
Posted in reply to deadalnix | On Sunday, 15 December 2013 at 09:38:28 UTC, deadalnix wrote: > Resulting in people giving name like TestT1, TestT2 as enum values in C++. As a result, you end up with the same verbosity as in D, without the possibility of using 'with'. I've usually seen the "namespace" or "struct "approach, eg: namespace CheckerBoardColor // or struct CheckerBoardColor { enum Enumeration { Red, Black, }; }; This allows using "CheckerBoardColor::Red", which (IMO) is nice and verbose. you can use "using CheckerBoardColor" for the equivalent of "with" (namespace only). Unfortunatly, the actual enum "type" is "CheckerBoardColor::Enumeration", which is strangely verbose. |
Copyright © 1999-2021 by the D Language Foundation