- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
Admin
In the Framework Design Guidelines section 5.7.2: “Do not use Enum.IsDefined for enum range checks.”
In the annotated version, Brad Abrams then gives a lengthy discussion about why you should check each value instead of depending on Enum.IsDefined.
There is nothing wrong with the code presented.
Admin
Ah- you're thinking of Enterprise-level data persistence. In that case, for best results, write the correct results to a hardcopy XML file. That way, it's human-readable, too. There are those who would write the values in JSON notation, but there will always be those who go overboard.
Admin
Except of course that the code throws System.Exception which is a no-no according in section 7.3.1 of said Guideline.
Also the content to the annotation you reference can be found http://blogs.msdn.com/brada/archive/2003/11/29/50903.aspx which I referenced in an earlier comment.
-Pedantic Joe
Admin
Wow. I know that the comments here are usually pretty silly, but some of today's really are terrible. Let's recap .NET 101 here:
This code is doing type conversion, not range checking. The types appear to be identical, but we don't know that. The EmailFormat enum might contain HTML = 3 and Text = 4 along with a few other formats, which would make type conversion based on direct casts incorrect.
The switch construct here MUST have a default case, otherwise it would produce a compiler error.
Enums in C# let you specify the values. This has many uses, including the FlagsAttribute as well as the ability to wrap some database column with an enum or support a direct cast to a different type. It also means that automatic range checking would be abominably slow for large enums (and there are several).
For the geek who posted the C++ code with a constructor and operator overload, an Enum in C# isn't a struct. It doesn't have constructors, and it doesn't have operators. That's precisely why you'd write a conversion method in an actual class (this one's even declared static!).
Enums in C# are far more flexible and easier to use than the retarded BitSet in Java. I'm not going to expand on that because it really ought to be obvious to anyone who's actually had experience with both languages (and if you haven't - keep quiet!)
Point (2) is really the most important here. C# doesn't actually do static analysis on your code in order to verify that you've covered every possibility (FYI, neither does Java). It makes certain assumptions. For example, if you write this useless bit of code:
It won't compile. You'll get a "not all code paths return a value" error. It's pretty obvious to a programmer that all code paths do, in fact, return a value. "o" is either null or not null. But the C# compiler just sees that you have an if/else-if without an else and without a subsequent return. If you don't evaluate each and every conditional against the entire scope of possible conditions (and it's practically impossible for a compiler to do this in reasonable time), then it looks like the return value might actually be undefined.
Same goes with switch/case constructs. Even if you've covered every possible enum value, the compiler can't know this before the code is actually compiled! So it insists on either a default case, or a return/throw statement after the switch. In this case, the programmer has chosen to throw rather than return a default value. He knows that branch should never be executed! It's essentially a choice between an arbitrary return value and a meaningless exception.
Having said that, there is a convention for this that makes a little more sense. What you're supposed to do is:
This code is much easier to maintain because it explicitly acknowledges that "Text" should be the only remaining option after all others have been tried. If another programmer adds a new Enum type (say EmailsFormat.RichText) and forgets to add that to the conversion function, this will fail in debug mode but use a default value in release mode. That may or may not be what you really want, but it's generally better than a runtime error.
If I really need something like that to produce a runtime error, i.e. because using a default value could corrupt other data, then I usually use the NotImplementedException. If I ever get a bug report with that (and I never have), it tells me "Whoops, you changed something but forgot to change this other part that depends on it!" This is rare, though; usually the Assert behaviour is preferable.
Admin
I think the code is actually:
I like it. I would have written something similar myself, if I had to convert enums from one library convention to another. This has got to be the least WTF-ey code ever posted on WTF.
So, the REAL WTF is that Alex has no QA on the submissions. I bet he didn't spot the Email/Emails difference when reading (which I did on the first try, for some reason, thus having to look hard for any WTF-ery).
Admin
I don't understand that sentence at all.
Admin
Speaking of pedantic guideline adherance, "HTML" should be "Html"
Admin
All I can say is OMG WTF.
Admin
Admin
What's not to understand? It's a very clear sentence. It's also very incorrect.
Admin
Even if there is a 1-to-1 correspondence, this is a really bad idea. The problem is that if someone decides to rename the enumeration values (because of new code style standards, for example), the "optimized" code will still compile, but it won't work anymore. If that section of code isn't used very often, the problem might not be noticed until a customer runs into it. But the line-by-line conversions will cause a compiler error. (They might even be renamed automatically, depending upon where they are in the solution.)
Admin
Have you actually read the documentation? It clearly states that IsDefined is supported all the way back to 1.0.
Admin
Absolute and utter rubbish!
Biffa is absolutely right. There's no difference between "some other code than a 'throw' command" and a "throw command". By "some other code" you obviously mean a call to method throwing an Exception - which is in fact nothing else than a method with a "throws"-clause. How do you think the exception is thrown in that "other" code? Yes, you guessed it (or perhaps not): by a "throw" statement...
This is in fact quite close to valid Java - if you'd run this through the Java-compiler, you'd get basically 2 errors:
There are also two breaches of naming conventions: The enum-constants should both be uppercase ("TEXT") and the first character of the method name should be lowercase - there's a reason why types (classes, interfaces, enums and annotations) are the only constructs written with an uppercase first letter in Java! Nevertheless, this misnomers wouldn't faze the compiler.
To make this correct Java, you'd write:
If you don't like having to declare the exception in the method signature, leave out the "throws"-clause and use
instead. The semantics change slighty then - the caller of the method is not required to handle the Exception in the latter case.
Otherwise (in presence of "throws Exception") he is facing the choice of either using a "try/catch" block around the call or declaring "throws Exception" himself and thereby letting the Exception propagate further up the call stack.
But in fact the best practice when dealing with unknown values in a "switch/case" statement is to use
which also does not have to be declared in the "throws"-clause (so you can leave that out again) and was coined specifically for cases like this.
You're welcome to try both the original and the above version and see for yourself :oP
Admin
100% agree - checks like that make code solid.
If you write a library that others use and you want to check input parameters you have to check enum-parameters like this. Unfortunately you can't do something like ((a >= first-enun) && (a<= last_enum))
That might work in java (don't know ... ) but in C and C++ you can define enums with gaps in it, and you can pass ints to functions expecting enums without warnings.
Admin
I've been soundly proven wrong.
It was my error; I was clearly lied to by various sources.
My apologies.
Admin
first time "not a WTF" comes to my mind, it looks like a good way to prevent you from updating the code correctly later, if you add a new value to the enum.
Admin
If that is C++ code, someone could cast any value to the parameter for that function, so it is possible for that function to get an invalid value. I would argue that throwing an exception is not the most gentle way to handle the error.
Captcha: gygax (Gary Gygax? The D&D guy?)
Admin
I'm prepared to accept your analysis. I've never met you. I've never had to write this sort of code in, say, C#. I can, however, look it up o the web if needs be.
I do find it difficult to deal with comments such as "There is nothing wrong with the code presented,"
In a sense, this is true. It will compile. It is almost self-documenting, in a way, It will probably (in a static environment) do its job.
However, it seems to be a classic case of what Alex is forced by Grandmother Demand to call "Worse Than Failure."
If you really, really, think that there is nothing wrong with the code as presented, then please think again. Perhaps there are two or three subtleties that you'd like to revisit.
Admin
Eff Five: The "you" here is mis-directed. Jeffrey L. Whitledge: What's the matter, sweetheart? Lost control of the trust fund and had to make your way in the real world?
If so, I'd try harder. The "you" above specifically refers to you. Personally.
No, really, I've just checked. Apparently, you don't have a clue.
Admin
I agree that this is a bogus WTF. Moreover, it's a WTF lampooning what amounts to excellent coding practice. I always use the default in a switch statement to throw an "invalid value" exception (assuming that's an error condition, of course).
It's only a couple of extra lines of code, and it guards against real maintenance issues, the most obvious of which is adding new enum values after the code is written.
IsDefined() is great, but only gets you as far as making sure it's a real enum before switching on it. What you're guarding against is a new, valid value falling silently through the switch, and IsDefined won't do jack for that.
Admin
If it was Java, you would: a) use a lowerCaseMethodName b) omit the needless 'default', because nothing else is possible c) therefore not need a throws-statement d) write TEXT in UPPERCASE, because it's a kind of constant e) -- not mentioned before --: Move the method into the class, where it belongs..
And of course give a hint by a (more pretty than mine) comment, that we're not morons, but do useful work.
This is much better readable, and perhaps we would like to avoid the depedency SFormat -> _Format and leave it somewhere else.
Perhaps convert it in the EmailFormat-Enum? And just call it 'convert':
But it's C# - what a pity.
Admin
Perhaps EmailFormat is not an enum. Maybe it's a class and HTML is a well known instance of the class. Like the UTF8 conversion class in the .NET framework.
Admin
This reminds me of something I found in one of my first VB programs:
if foo = true then 'something else if foo = false then 'something else msgbox "omfg haxor alert" end end if
foo, of course, being Boolean. The captcha, "craaazy", describes this well.
Admin
Could be a leftover from another language. For instance, early VB versions did not enforce enums, they were just a way to put names on the alternatives. For instance, the following was perfectly legal:
Enum Color Red=0 Green=1 Blue=2 End Enum
Dim Col as Color
Col=Color.Red 'OK Col=3 'Also OK
Admin
Ha! He doesn't for a null value. He loses.
Admin
I think you were thinking about RuntimeException and it's derivatives; they don't ever need to be declared as thrown.
Admin
The submitter's WTF due to lack of knowledge...
Admin
And I should really read the whole thread before replying; sorry about repeating the correction after you'd acknowledged it.
Admin
That's more or less what all enums are in Java. The enum keyword was added to the language so that you would no longer need to write stuff like this:
public class Color {
}
Admin
This is called Hyper Secure Redundant Programming, HSRP.
Admin
I stand by my earlier statement. There is nothing wrong in the code presented.
It is a platonic ideal like a perfect circle.
In the world of all possible computer code in all languages, this represents not only a pinnacle of achievement, but the embodiment of absolute good.
Every day I get down on my hand and knees and pray that my code can only be a tenth as good as the example that was presented.
That was obviously what I meant the first time, and I stand by it now, and always will.
Admin
Admin
class SomeFlags { public boolean flag1, flag2, flag3; public UInt8 value; }
Admin
Just what I already said above ;o) And you have a valid point with e) (though it's not really necessary)
But I don't agree with b) and c).
Best practice is (as I also said above):
You are right when you state that no other values are possible.
Still, someone might add another constant and forget to update/recompile all occurrences of such switch-statements. Unfortunately, you won't notice that immediately and/or will likely get strange behaviour (depending on what you're doing in the case-branches). That's why it is best practice to throw an AssertionError, because it is a) unchecked b) not meant to be caught, because it is a subclass of Error and therefore c) perfect for asserting that no constant has been forgotten in the switch (now or in the future!)
Admin
Nice to know that I'm a geek, though. I presented a binary choice: (1) One: "rely on the language" -- hopefully .NET post 1.1 (2) Courtesy of http://en.wikipedia.org/wiki/Niklaus_Wirth, algorithms + data = programs.
The fact that I wrote the example in C++ doesn't make me a geek. It just suggests that I'm ignorant in terms of C# or Java.
What, exactly, should I write an example in? VB4? (Shudder...)
Admin
Only problem with that enum is that it doesn't enumerate anything; it's a bitfield.
Pl... please tell me C# can handle bitfields?
Admin
If I were code-reviewing that method, I would reject it for the fact that there are multiple returns in the method body (which I loathe). I would actually rewrite the method to be similar to:
This type of defensive coding protects against all the nasty things that can happen in switch{} expressions: 1.) accidental fall through in the cases (by missing a break statement) 2.) the default case is always handled by forcing the compiler to do the checking.
Admin
how can you accidential fail through, if you return immediately? Which default-case for email?
No one suffering on compulsion neurosis would review my code.
But here is still a better approach:
Admin
Regarding "like having a boolean sometimes be a string".
Hmm. I think you can, if you really try hard, make boolean behave strange in many languages.
int main(int argc, char *argv[]) { bool value = true; bool *ptr_b = &value; char *ptr_c = (char *) ptr_b;
}
Consider the wide range of possibilities :-)
Admin
The real WTF is that the submitter thought that this is a WTF.
Admin
hey guy! do you really know what is Enum? I don't think so...
I know it at http://www.enumobile.com and you can get your eNum here for FREE!
Admin
AHAHAHAHHAHAHAHAHHA
OH MY GOD THAT'S SO FUNNY! AHAHAH!!!!
...
Stop beating a dead horse.
Admin
Admin
I'd rather beat a TraumaPony.
Admin
Sure, and the actual code (including that, to handle those types of e-mails) is also to be stored in database, for ease of upgrade.
When the user wants ti run the program, he just launches MS Access, connects to SQL server, issues a needed EXECUTE PROCEDURE, then SQL server spits out needed code packases and runs them into JVM or CLR.
Database is a ways t othe future, anything that is not stored inside SQL database is jast a worthless crap!
Admin
Admin
Admin
What happens when your database goes down?
Admin
I can't tell if you're being sarcastic =P