On Friday, February 22, 2013 4:53:27 AM UTC-8, Joao S. O. Bueno wrote:
Again, I thinnkt hat my 2002 code that expected a (1) working when it got a (True) instead was a great, great thing. And I think that lots of places where magical strings today ("str.decode" errors argument, "compile" mode argument) should be lifted up to expect constants and still keep working if one pass them the strings "replace" or "eval".
Ok, first of all, nobody's suggesting that wouldn't work. I'm not talking about comparing enums with base types (which I have no problem working like this), I'm talking specifically about comparing enums directly with other enums from a different category.
Requiring that things compare differently, IMHO, is too much
statically-typed-minded - it is not the way of Python. As for Alex's surreal example of someone defining "NO" and "YES" with different values in different Enums and passing the wrong one to a given call - this person will have it comming.
I think this is unnecessarily dismissive. Obviously, my example was simplified, but what if these two enums were created by two completely different people in different modules that just happen to be used in the same program? Does the hapless programmer "have it coming" then?
You say that my suggestion is more like C++ than Python, but I counter that your suggestion seems to me a lot more like Perl than Python. It smacks of one of the things I dislike most about Perl, which also happens to be, in my opinion, one of the language features most responsible for (often subtle) bugs in Perl code even by experienced programmers: The contents of variables can have very different semantic meanings depending solely on the context in which they're evaluated (scalar vs array, etc). In this case what you're saying is that just because entirely unrelated programmers happened to use the same int value underneath, that Align.TOP and Errno.EPERM and Choice.OK should all be considered to mean exactly the same thing everywhere (even if none of the programmers actually intended or foresaw that possibility), but what that meaning is actually depends entirely on what context they happen to be evaluated in.
Another way of looking at this is that what you're proposing is effectively implicit type-casting between enums of different types. Python does support implicit casting in a very few well-defined cases, but not most of the time, and only when doing so does not discard important semantic information (i.e. "meaning"). For ints, floats, etc, they really only have one piece of semantic information ("a number value"). Enums, however, have more than that. They have (potentially) a number value, but they also have names, and they (preferably) have information about "what type of thing am I". Automatically throwing out that extra information on a comparison where both objects have the extra info and it's not the same on both objects is, in my opinion, just wrong. If there were no extra semantic meaning to enums, then this wouldn't be an issue, but the symbolic information they carry is clearly important, because it's the whole reason we're having this discussion in the first place instead of just using ints everywhere.
(Indeed, it could easily be argued that the entire point to things like int-enums is that the programmer isn't supposed to have to care what the underlying value is, but should be able to think of things entirely symbolically.)
In pretty much all the cases I can imagine (and that have been suggested thus far), it seems to me that passing a different class of enum than the other side is testing against is almost always going to be an accident, or at the very least sloppy code (if there are cases where it is intentional, it's unlikely to be common, and the programmer should be able to explicitly cast between them somehow). Given this, I think that the Principle of Least Surprise enters into things here as well. If somebody makes a coding mistake and uses the wrong type of enum somewhere, which is likely to be the least surprising outcome?:
1. If you use an enum of the wrong type, it won't be considered equivalent to any of the expected options. 2. If you use an enum of the wrong type, it might not be considered to be equivalent to any of the expected options, or it might match one of them and do something either the same or completely different than you expect, but you have no way to tell what will happen without looking at an underlying constant which you're not supposed to have to care about.