- 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
second go... in the real world you would probably find that the Connector class is already in the libraries which came with the compiler...
try { struct Connector { Connector(DB db) : _db(db) { _db.openConnection(); } ~Connector() { _db.closeConnection(); } private: DB _db; } connector(db); db.runSQL( sql ); } catch(SqlException sqlex) { error_panel.ErrorMessage = sqlex.Message; //.Procedure/.Line error_panel.Visible = true; }
Admin
Exactly! The RWTF is that the author doesn't understand the use of finally blocks.
Captcha: bathe (not today, thanks)
Admin
Not exactly. Your open should be outside the try{} block that closes the connection, in its own try{}:
try { db.openConnection(); try { db.runSQL( sql ); } catch(SqlException sqlex) { error_panel.ErrorMessage = sqlex.Message; //.Procedure/.Line error_panel.Visible = true; } finally { db.closeConnection(); } } // end of db.openConnection try catch(Exception ex) { // handle DB open failure, which is // probably not an SQL exception }
I know, you probably just dashed something off as a quick example, but any example anywhere could end up copied into production code as a pattern.
Admin
Actually, in Delphi we can use two different blocks:
which executes the block after finally regardless of whether an exception was raised or not, but does not trap the exception. which executes the block after except only in the event of an exception, and traps it.They are usually nested as
Admin
than: var ret; if (test1) { ret = true; } else { if (test2) { ret = false; } else { if (test3) { ret = FILE_NOT_FOUND; } else { ret = NO_QUACK; } } } return ret;
especially if you don't have elseif as a keyword in your language (and it's rendered superfluous by using exit points anyway)
Admin
What could possible be the point?
I often do: try{ //something nasty }catch(SomeCheckedExceptionThatICantPossibleHandle ex) { throw new RuntimeException(ex); }
A classic example is ThreadInterruptedException There's nothing I can do about it, and the only time I've ever seen one in the wild was in response to a System.exit() call. Might as well rethrow it as unchecked.
The WTF here is why did java make some exceptions checked, when there is no way to recover from them.
Admin
Should be InterruptedException, not ThreadInterruptedException
Admin
Admin
It's very aparent that the guy was too lazy to lookup TryParse. It happens..
Admin
I agree. A single exit point can sometimes lead to very bad code.
I had a co-worker once who littered her code (Delphi) with all sorts of junk like this:
Code like that just stinks, and cries out for an earlier return to avoid the declaration of the test value and all the tests that have to be made.
Admin
Wow, gotta love some of these pearls of wisdom being posted in the comments...
Right, because it's actually physically possible to know every conceivable exception that a 3rd-party component might throw. And there's never a situation where you're, say, running a batch process with 15,000 subtasks, and you just want to log errors for individual errors rather than having the entire batch fail.
Guys, there are valid reasons to catch generic exceptions. Now, it's rarely valid to catch and just ignore them, but if that's what you mean, then you have to qualify it that way.
Honestly, if this had any grounding in reality then don't you think the compilers would explicitly disallow it?
A much better rule of thumb is that a function should return as early as possible. That leads to much better maintainability by humans and also minimzes the branch coverage needed by automated tests, if you're into that sort of thing.
Admin
Actually the author is taking advantage of Java behavior. He is building a string. He doesn't want to bother with catching null pointers if something is null but a try forces SOMETHING like catch or finally. He uses multiple trys because he wants to build his string regardless if something in the middle dies.
Although it is ugly and I wouldn't have coded it this way, it is efficient if in fact it is rare that one of them are null.
Lighten up!
Admin
Admin
Remove all the try - finally blocks. The code works exactly the same.
Admin
Admin
finally is not just for freeing resources, but for doing anything that needs to be dealt with before the exception is thrown. They're not the same as C++ destructors for much more fundamental reasons than just determinism.
Admin
Foo *f = new Foo; try { f->bar(); } catch(std::exception& e) { delete f; throw; }
What does the word "finally" even mean? It's a weird meaningless word. Catch means, very directly, when some exception is thrown in the try {} block, do this instead of continuing. Very simple.
Admin
The implication of that statement is that the only use of a finally block is to deallocate resource and, worse, that all deallocation should take place in a destructor! That's a pretty heavy restriction, considering the semantics of finally blocks are wide-open, i.e., the code in the finally block will be executed no matter what the return path is, and need not consist of "deallocation" routines or destructors.
Admin
I see that (anti) pattern quite a bit with our new guys here (in Java).
My main gripe is really that it's not immediately obvious when you read it, but it does make perfect sense. Obviously if finally {} is empty it may as well be left out for readability sake. And the try {} if the method is declared to throw something.
captcha: smile
Admin
You can use the tools C++ provides to help you manage this. Namely, classes -- if you really must allocate obsenely large data structures of the heap, then it should be a class managing that data and representing it;
Admin
You can use the tools C++ provides to help you manage this. Namely, classes -- if you really must allocate obsenely large data structures of the heap, then it should be a class managing that data and representing it;
Admin
Seconded, everything you said.
The 'rumor' here is that MS gave him a $1 million signing bonus, however.
I've not been able to confirm it, but that was what was going around Borland during that time.
Admin
Some of you guys are obviously confusing two things. The Java and C# finally statement is NOT an equivalent to C++'s catch(...) statement. C++ provides a catch(...) statement that catches all exceptions regardless of their type because there is no forced single-rooted exception hierarchy. As I understand, catch(...) can be used to emulate finally:
Java / C# code: try { acquireResource(); doSomethingRisky(); } finally { disposeResource(); }
C++ code: try { acquireResource(); doSomethingRisky(); disposeResource(); } catch(...) { disposeResource(); throw; }
C++ implementation produces duplicate code, but allows for greater flexibility. I wonder why Java doesn't support operator overloading "because it is too complicated", but supports exceptions. I think that operator overloading is easier to understand and use correctly. Granted, it has a greater abuse potential, like overloading a comma, but once people understand how to use this feature, they rarely come up with such bizarre ideas.
Admin
And why not? I use this idiom all the time:
// just a quick example... int open_file( char *st ) { if ( 0 == strcmp( st, "" ) ) { // no pathname provided - nothing to do... return( FILE_NAME_EMPTY_ERROR ); }
// continue with processing... // comments don't throw exceptions... :-) return( SUCCESS ); }
How else would you handle such a situation?
Admin
Also, what about this idiom: I'm inside a worker class that is doing some back end database stuff. Suddenly the database connection dies (or something equally catastrophic). There's not much else I can do at that point so the end user needs to know. I don't want the worker class putting up a dialog so rather than do that, I'll just re-throw the exception so the UI layer can catch it and deal with it (generally, display a message to the user).
This is just one example and I suppose I could just get rid of the try/catch and let the exception propagate by itself but I prefer to have the >option< to perform some logging or to do something inside of the catch block rather than just let the exception fling itself up the stack by itself.
Admin
What would be an example where you couldn't create a useful scope?
Admin
I've dealt with folks who don't do enough exception handling. Then there are those who take it to the other extreme, but don't quite get it. Sadly, I run into this a lot:
And they'll throw a block like this around 3 lines of code, and again for the next 3, and so on, and then there's the Mother-of-All-Try-Catch-Finally (TM) blocks wrapped around the whole thing. Sheesh - look up refactor!
Admin
Everybody is wrong. The real WTF here is Java requiring extra cleanup code everywhere an object is used, rather than just once in the object itself (as C++ does). What a mess!!! heh.
captcha cognac. Yes, please.
Admin
You might wish to read this
Admin
Admin
I do know about finalize(), although I will admit to not knowing Java as well as C++. But it's my understanding that it depends on the non-deterministic vagaries of the garbage collector. Which is not acceptable most of the time. Well, tell me I'm wrong, maybe I am...there are plenty of other things to hate about Java ;)
Admin
[quote user="snoofle"]
Heh, this isn't that bad, because after all, you "gotta catch 'em all" :-P
Admin
Meh. Pretty small WTF. I've done the same thing a couple of times, just to remind myself that I need to add some finally code. Mind you, I actually get around to putting something in the finally block before I deploy. :)
Admin
You might wish to look into finalizers more. Not only are they not required to execute at a given point (the exit from a scope), they are not required to execute AT ALL if the GC never reclaims that object. (In other words, if the program exits before the GC is invoked, your finalizer won't be called.)
In other words, they're next to useless.
Admin
Until .NET 2.0, TryParse only existed on Double; you could "TryParse" ints with it, by providing an integer format indicator (too lazy to look it up ATM), and THEN, if successful, you could safely use Convert.ToInt32 or Int32.Parse to get the actual integer value, without doing error trapping.
The coder's confusion with regards to TryParse is no mystery; that part of .NET 1.0 is the result of laziness and inconsistency in the designers. "We'll just put this method in Double, and people looking to parse integers should look there for it." In .NET and the tools, it's infrequently easier to hack around it than spend hours finding the real system facility for it.
Admin
Well that makes sense in a way - people who habitually use ON ERROR NEXT are nincompetent in general, so why would C# make them any better.
Admin
I agree. The real WTF is thinking that a garbage collector (useful for freeing memory) could be a replacement for deterministic destructors (useful for freeing all resources).
Main reason for introducing multiple destructors in MS C++/CLI. Another WTF...
Admin
I've used that as a tool to start a refactoring process when the original code caught exception and rethrew Exception, in other words replacing a WTF with a wtf.
Admin
I could swear that the level of competence displayed in the comments here used to be higher than this. Now they're worse than the original "WTF" half of the time. Either that or they're posting the captcha (I'm sure the spammers appreciate that).
Admin
So for those of you who are still confused, this:
is exactly equivalent to this:
Admin
:)
Admin
It seems likely the guy was just inserting templates from his editor that included the 'finally'. Since the empty finally block doesnt actually do anything, this isnt much of a wtf.
Admin
Looks like auto-generated code or just plain newbie-misunderstanding code (ie, maybe he thought it was required as part of the syntax of try-catch when in fact it is not).
Admin
What you suggest is another anti-pattern. The idiomatic way to do it in C++ is:
Then to use the resource:
Admin
hey, most (of other people's) code that I read doesn't even have the try part. So he gets some points for at least trying a little bit.
Admin
I commonly use try--finally blocks to undo a tempory change. E.g. This is a "recursion" safe version ToString for a Collection.
[ThreadLocal] private bool inToString = false; public override string ToString() { if(inToString) return "..."; else { inToString = true; try { StringBuilder ret = new StringBuilder("{"); foreach(T obj in this) { ret.Append(String.valueOf(obj)); //whatever the c# function is. ret.Append(","); } ret.Append("}"); } finally { inToString = false; } } }
I also commonly use it when disabling gui buttons while doing an operation, and re-enabling them in a finally block.
Using a constructor and destructor to do more than the initialization of the object is an anti-pattern.
Admin
Are you really that dumb???
If you don't have a convenient scope, where the heck are you going to place your finally???
And are you arguing for or against C++ with that last comment? Why should so many random finally blocks need to know the (easy to forget) cleanup details when the objects themselves can handle it?
Admin
if I remember correctly Delphi (I have not done Delphi for more than a year, and I would confirm it, but I would have to reinstall it on my computer) doesn't have a return statement, the only thing that is close to a return statement is:
Result := <return value>; exit;
OR
FunctionName := <return value>; exit;
Admin
I suppose you could solve that problem over and over again when you need to. Or, you could solve it once.
class nest; class nest_var { friend nest;
public: bool is_nested() { return depth != 0; }
int get_depth() { return depth; }
private: int depth = 0; }
class nest { public: nest(nest_var &_var) : var(_var) { var.depth++; }
~nest() { var.depth--; }
private: nest_var &var; }
................
class some_class { private: nest_var guard;
.........
void some_func() { if (guard.is_nested()) { //Do something } else { nest(guard);
} .........
}
I used something very similar to handle calls to UpdateData in an MFC application. I also found other users for it throughout the code base.
The best part is if it's ever needed I can change out the implementation of nest & nest_var to transparently deal with multithreading.
Admin
Using a constructor and destructor to do more than the initialization of the object is an anti-pattern.
I'm afraid it's not that simple.
The purpose of a constructor is to prepare the environment so the object can safely do it's work.
The purpose of a destructor is to reset the environment back to the state it was in before the constructor was called (except for documented intentional side effects).
In an ideal world "the environment" is limited to the local members of the class, and it devolves into your example. But, if the real world was always that simple we'd all be using Haskell.