3 ms·
Say you need to migrate a database to a new schema. You need 10 SQL statements to do this. Each statement may fail, in which case you want to write stuff in a l
by mercurial 14y ago
Say you need to migrate a database to a new schema. You need 10 SQL statements to do this. Each statement may fail, in which case you want to write stuff in a log and abort the transaction. In this case, wouldn't you agree that writing your statements in a try/catch/finally block would result in clean, easy to understand code, as opposed to adding explicit error handling after each statement?
- acqq 14y agoI wouldn't agree, as when I'd code it in C I'd have a function callSql which returns false and write the code you describe as: if ( callSql( s1 ) && callSql( s2 ) && callSql( s3 ) && callSql( s4 ) && callSql( s5 ) && callSql( s6 ) && callSql( s7 ) && callSql( s8 ) && callSql( s9 ) && callSql( s10 ) ) { endTransaction(); return true; } logAndAbortTransaction(); return false; No need for exceptions at all, and it's very clean and clear what's going on. I wrote the same code to my young exceptions-indoctrinated colleague who asked the same thing like you, and he couldn't believe at the start that that's all -- that much he wasn't used to a plain control flow. It's even obvious how it can be generalized for any sequence of commands: for ( int i = 0; i < n; i++ ) { if ( !callSql( s[ i ] ) { logAndAbortTransaction(); return false; } } endTransaction(); return true;
- dagw 14y agoWhile this code is nice and concise, the problem is that you don't automatically know which call failed or what the error was.
- acqq 14y agoIf you can, write a more concise code with exceptions which will automatically show you which call failed and what the error was. If we include all the declarations, I claim that your solution wouldn't be shorter or more readable than my C variant I'll write, which would only declare error code values, or even return strings as error reports. There's no advantage in exceptions, except when you use them for "hardware-like" generated exceptions (which is where they belong).
- mercurial 14y agoThat's very easy: void migrate() { try { callSql(s1); callSql(s2); ... endTransaction(); } catch(SQLException ex) { logAndAbortTransaction(ex); } } Now I have an exception to log, which means I have a stack trace which is going to tell me which statement failed rather having to play the guessing game. I may even get an explanatory message for free if the exception came with a message. For me, having exceptions over return codes has a number of advantages: * Within a single object, you get much more information (error message and stack trace). You need to return two different values if you need both a message and a return code * You don't want to handle the exception at the call site? no problem, just propagate it up the stack. On the other hand, if you want to try the same thing with return codes, you need a way to differentiate the return codes due an error in your migrate() function and the error codes resulting from a given callSql statement. * Which brings us to... another benefit: enforced compile-time checking of the exception. You can't write code that is going to check for a DogException when the callee throws a CatException. But it's very easy to check for -1 when the actual code is -2. Of course you can alleviate this somewhat using static constants, but it's still a safety issue. Obviously, exceptions are not all roses either, whenever you need a new one, you need to create a class for it. But the workflow interruption is not greater by an order of magnitude than adding a static constant somewhere to represent your new error code. Edited for better formatting.
- acqq 14y agoDoing exactly the opposite from what I asked, you omitted all the declarations of all the classes you use. Note that if I use C++ I can also use the classes with the same semantic and that also contain error messages. The stack trace you mention is a debugger feature, not something your classes do by the language definition (I speak about C++, I don't know what's in Java). If you'd include all the code needed for your lines, you'll see that I have more freedom and not less expression possibilities. If you claim that you already have everything in libraries, OK, but C++ libraries without exceptions can have equivalent functionality. Exceptions are absolutely not needed to write the clean code that handles all the error conditions.
- dbaupp 14y agoThe loop variant does know which call failed, and could easily be modified to know what the error was (if the underlying callSql had more than just a boolean failed/success return value).