I have discussed a bit this topic probably one year ago, but it's good to talk 
some more about it.

Jane Street is a known trading firm, they use the OCaML language because it's 
efficient and because its type safety, it is a very statically typed language.

For them one of the simple but important qualities of OcaML (and some other 
functional language) are the "match" statement (for pattern matching) because 
it statically forbids missed cases and redundant cases. This is very useful 
because if you add one more case in an enumerated type, the compiler will 
produce an error for all the match present in your whole program. This makes 
much more safe to modify code.

They talk about it here, from 33 minutes, it's an interesting video on the 
whole:
http://vimeo.com/14317442

I presume Walter has added the "final switch" to D for the same purpose: if you 
add or remove one element from an enum, final switches will give you errors at 
compile time. This removes a common source of bugs in C code.

Recently I have created a bug caused (not caught) by the nature of D enums. 
This is just the last one of similar bugs.

The following is reduced code of a small game. The main contains a while that 
loops until the game is finished.

The original version of this program was simpler, and instead of using the 
GameState enum, it just used 0, 1 and -1 constants in the code. So the original 
version of isFinished tests if winner() != -1.

I have added the enum GameState, now winner() returns. But I have forgotten to 
update the isFinished() function too. The D language doesn't catch that simple 
bug:


enum GameState { inProgress, draw, humanWins, computerWins }

GameState winner() {
    // this function used to return -1, 1, 0 values
    // ...
}
bool isFinished() {
    return winner() != -1; // not updated function!
    //return winner() != GameState.inProgress; // correct code!
}
void main() {
    while (!isFinished()) {
        // ...
    }
    // ...
}


In a bigger program it becomes less easy to catch a similar bug (this bug was 
not found also because of another waeak typing characteristic of D language: 
inside isFinished it allowes you to compare an unsigned size_t value with -1, 
despite -1 is statically visibly outside the range of possible unsigned values).

If I write similar code in C++11, it catches that bug:


enum class GameState {
    inProgress,
    draw,
    humanWins,
    computerWins
};
GameState winner() {
    return GameState::draw;
}
bool isFinished() {
    return winner() != -1; // line 11, error
}
int main() {}


G++ 4.6.0 outputs:

test.cpp: In function 'bool isFinished()':
test.cpp:11:25: error: no match for 'operator!=' in 'winner() != -0x000000001'


In D final switches where introduced to avoid essentially the same class of 
bugs.

So I think I'd like named D enums to be strongly typed. Weak typing is better 
left to old versions of the C language.

More info in my enhancement request:
http://d.puremagic.com/issues/show_bug.cgi?id=3999


Do you know what are the disadvantages of this change in D enums? Do you know 
if it is going to cause other bugs or problems?

If you really want to keep weakly typed enums in D then I am able to invent a 
new D syntax to specify strongly typed enums, like this, but I suggest to not 
go this way:

typedef enum GameState { inProgress, draw, humanWins, computerWins }

Bye,
bearophile

Reply via email to