If at first you don't succeed, try try again.....but only for a minute (taking a 3 second rest after every try), then give up!



  • Saw this in an application I'm working on... 

     

    DateTime startTime = DateTime.Now;

    do
    {
        try
        {
            dataAdaptor.Fill(dataSet);
            return dataSet.Tables[0];
        }
        catch (Exception err)
        {
            if (DateTime.Now.Subtract(startTime).TotalMinutes > 1)
            {
                throw new Exception(err.Message);
            }

            Thread.Sleep(3000);
        }
    } while (true);

     

    Thing is, if it fails the first time, it's going to fail each time after that, so why not throw the exception right away. 



  • Looking at the code, I'd guess that it sometimes fails because of temporary conditions (network problems, race conditions, whatever).



  • Depends on why it failed.  If you're just bringing the system up, and this process came up before whatever it's talking to, it's best to wait.

     



  • This is just a web application.



  • @ammoQ said:

    Looking at the code, I'd guess that it sometimes fails because of temporary conditions (network problems, race conditions, whatever).

    Probably, but that's no excuse. There are better ways of handling these cases.
     



  • @bobday said:

    @ammoQ said:

    Looking at the code, I'd guess that it sometimes fails because of temporary conditions (network problems, race conditions, whatever).

    Probably, but that's no excuse. There are better ways of handling these cases.
     

     Indeed. Use more catch blocks with specific exception types to catch such problems. That way you could throw a caught exception faster if you can't treat it instead of retrying.



  • @ammoQ said:

    Looking at the code, I'd guess that it sometimes fails because of temporary conditions (network problems, race conditions, whatever).

     Java would probably be 20% less abused if it wasn't possible to catch Exception. It's the most common WTF we see here, try some block of code, catch Exception, then either immediately reraise or do nothing.



  • @savar said:

    @ammoQ said:

    Looking at the code, I'd guess that it sometimes fails because of temporary conditions (network problems, race conditions, whatever).

     Java would probably be 20% less abused if it wasn't possible to catch Exception. It's the most common WTF we see here, try some block of code, catch Exception, then either immediately reraise or do nothing.

    IMO it's hard to tell in this case without knowing the circumstances. Catching Exception looks odd, but having three identical catch-blocks (catching SQLException, IOException, FooBarException) might be just as bad.



  • You could just call the same method on all the three specifid catch blocks, and then do something else more elaborated on other catch blocks.



  • @savar said:

     Java would probably be 20% less abused if it wasn't possible to catch Exception. It's the most common WTF we see here, try some block of code, catch Exception, then either immediately reraise or do nothing.

    I'm inclined to agree, but failure to handle error conditions was a problem in C programs, even before Java existed. Thus the invention of lint.



  • @ammoQ said:

    @savar said:

     Java would probably be 20% less abused if it wasn't possible to catch Exception. It's the most common WTF we see here, try some block of code, catch Exception, then either immediately reraise or do nothing.

    IMO it's hard to tell in this case without knowing the circumstances. Catching Exception looks odd, but having three identical catch-blocks (catching SQLException, IOException, FooBarException) might be just as bad.

    True, sometimes you want an operation to fail the same way (such as rolling back a transaction) regardless of the actual exception thrown. Particularly in database or file I/O you can get all types of security exceptions, network exceptions, and InvalidBooleanValueExceptions when a file's not found.

    I imagine that in Java, with checked exceptions, almost all 'catch (Exception)'s and 'throws Exception' are used somewhat-irresponsibly to swallow compiler complaints.

     C#, on the other hand, doesn't have checked exceptions, so those useless 'catch (Exception)'s you see in sub-par code are just as unforgivable as 'catch (Throwable)' in Java.
     


     



  • @bobday said:

    @ammoQ said:

    IMO it's hard to tell in this case without knowing the circumstances. Catching Exception looks odd, but having three identical catch-blocks (catching SQLException, IOException, FooBarException) might be just as bad.

    True, sometimes you want an operation to fail the same way (such as rolling back a transaction) regardless of the actual exception thrown. Particularly in database or file I/O you can get all types of security exceptions, network exceptions, and InvalidBooleanValueExceptions when a file's not found.

    That is what finally is for.

    Though, one valid reason for catch(Exception), is if there's a "show a custom dialog box and email the error to the devs" function that every exception is supposed to go through rather than reaching the user through the system "unhandled exception" box. That should only be used on top-level entry points [i.e., event handlers] where possible though.

    Javascript doesn't have finally, but it also doesn't have a typed catch statement at all, so you basically have to check the "type" (i.e. the name) and re-throw.



  • @Random832 said:

    Javascript doesn't have finally

    Actually it does: try { alert("Hello"); throw 42 } finally { alert("world!") }



  • @Random832 said:

    That is what finally is for.

     I said "fail the same way", mang. You usually don't want to rollback a transaction in a finally block.



  • @bobday said:

    @Random832 said:

    That is what finally is for.

     I said "fail the same way", mang. You usually don't want to rollback a transaction in a finally block.

    try { Do some stuff; Do some more stuff; completed = true; } finally { if(!completed) rollback; else commit; }

    couldasworn, though, that there are at least some languages where the finally block is only used if there was an exception. 



  • That wouldn't make sense. What I do know is that you can use Finally without the need for Catch before it.

    In .NET transactions inherit from IDisposable, so you could do it like this:

    using (/* Create transaction here */) { try{ /* Do stuff */ transaction.Commit(); } catch { transaction.Rollback(); } }

    Or

    try { /* Do stuff */ transaction.Commit(); } catch { transaction.Rollback(); } finally { transaction.Dispose(); }



  • Exceptions of the try...catch format still just strike me as being a horribly convoluted method of letting people get away with poorly structured code that doesn't check operation success when it happens.

    Makes me want to just say "Do, or do not. There is no try."

    I think what bothers me most is that an error can happen anywhere in a try block and get thrown in the catch, and it allows people to forget exactly why things in a block might fail. I'd rather force people to know every possible outcome of every operation in a block and have to know explicitly what to do when those cases occur rather than just "Hey, I'll throw a try...catch around it and that will work!".

    That said, this is only an issue for mediocre programmers; a good programmer will code fine with or without exceptions, garbage collection, etc.  Those things won't save a bad programmer either - they'll just figure out new ways to cause things to break.

    But, of course, we all know that, else we wouldn't be commenting here now would we?
     



  • @too_many_usernames said:

    Makes me want to just say "Do, or do not. There is no try."

    I'd rather force people to know every possible outcome of every operation in a block and have to know explicitly what to do when those cases occur rather than just "Hey, I'll throw a try...catch around it and that will work!".

    True; a trycatch generally has no permanent place in production code.

    However, there are (^H^H) exceptions. There are times when the program depends on external factors that cannot be predicted, and you're using a call to code that you do not control, which may or may not throw an error. It is there that a try-catch is in one of its rightful places.



  • [quote user="Renan "C#" Sousa"]

    using (/* Create transaction here */) { try{ /* Do stuff */ transaction.Commit(); } catch { transaction.Rollback(); } }
    Expected ‘(’ -----------------------------------------------------------------------------^

    [/quote]

    And no “don’t nitpick pseudocode”, this difference was the WHOLE POINT of what I was saying—so you don’t have to either catch Exception [which is bad] or have half a dozen identical catch blocks [which is annoying. And can introduce subtle bugs, so it’s bad too.]



  • @too_many_usernames said:

    Exceptions of the try...catch format still just strike me as being a horribly convoluted method of letting people get away with poorly structured code that doesn't check operation success when it happens.

    Makes me want to just say "Do, or do not. There is no try."

    I think what bothers me most is that an error can happen anywhere in a try block and get thrown in the catch, and it allows people to forget exactly why things in a block might fail. I'd rather force people to know every possible outcome of every operation in a block and have to know explicitly what to do when those cases occur rather than just "Hey, I'll throw a try...catch around it and that will work!".

    That said, this is only an issue for mediocre programmers; a good programmer will code fine with or without exceptions, garbage collection, etc.  Those things won't save a bad programmer either - they'll just figure out new ways to cause things to break.

    But, of course, we all know that, else we wouldn't be commenting here now would we?

    Well, the same principle applies here as to not wanting to make half a dozen identical catch blocks - you might have general cleanup stuff to do that you don't want to duplicate at every single possible point of failure. Situations where, to be honest, I'd use a goto in C.



  • @Random832 said:

    [quote user="Renan "C#" Sousa"]

    using (/* Create transaction here */) { try{ /* Do stuff */ transaction.Commit(); } catch { transaction.Rollback(); } }
    Expected ‘(’ -----------------------------------------------------------------------------^

    And no “don’t nitpick pseudocode”, this difference was the WHOLE POINT of what I was saying—so you don’t have to either catch Exception [which is bad] or have half a dozen identical catch blocks [which is annoying. And can introduce subtle bugs, so it’s bad too.]

    [/quote]

    Sorry, I had missed that point. I agree with you on that.



  • @dhromed said:

    @too_many_usernames said:
    Makes me want to just say "Do, or do not. There is no try."

    I'd rather force people to know every possible outcome of every operation in a block and have to know explicitly what to do when those cases occur rather than just "Hey, I'll throw a try...catch around it and that will work!".

    True; a trycatch generally has no permanent place in production code.

    In Java, you have to "handle" some exceptions that will never ever (as defined in: "from the invention of computers till the end of the universe" ) be really thrown. You cannot simply ignore them in the program - at least you have to declare that your method "possibly" throws that kind of exception, which only moves the problem one level up in the call stack.



  • Like, AssignmentError or something?



  • I'm pretty sure that many methods in JDBC drivers under no circumstances throw the exception they could. But since the JDBC interface says they could, the program has to handle them.



  • @dhromed said:

    @too_many_usernames said:
    Makes me want to just say "Do, or do not. There is no try."

    I'd rather force people to know every possible outcome of every operation in a block and have to know explicitly what to do when those cases occur rather than just "Hey, I'll throw a try...catch around it and that will work!".

    True; a trycatch generally has no permanent place in production code.

    That's basically how error handling in C works: exceptions by return code. Now what was the initial reason why people invented try...catch again?

    @ammoQ said:

    In Java, you have to "handle" some exceptions that will never ever (as defined in: "from the invention of computers till the end of the universe" ) be really thrown. You cannot simply ignore them in the program - at least you have to declare that your method "possibly" throws that kind of exception, which only moves the problem one level up in the call stack.

    If it's a "non-problem" anyway, I don't see why it should be bad practice to reach it up the call stack. In fact, isn't the whole idea of try...catch that you only catch the exceptions that you know how to handle and leave the rest up to other parts of the program?

    For example, you could make a rule that all actually sane exceptions should be caught somewhere below Main() and just let the rest bubble up using Throws. Then make a final block around Main() that gives the user some kind of "Sorry, this should never happen, please tell the developers, they will buy you a beer" statement and be done with it.
     




  • That said, this is only an issue for mediocre programmers; a good programmer will code fine with or without exceptions, garbage collection, etc.  Those things won't save a bad programmer either - they'll just figure out new ways to cause things to break.

    "A good programmer doesn't need a debugger..."

    That's probably not what you mean but it just sounds too similar. 



  • @PSWorx said:

    @dhromed said:

    True; a trycatch generally has no permanent place in production code.

    That's basically how error handling in C works: exceptions by return code. Now what was the initial reason why people invented try...catch again?

    Execution of destructors for objects located on the stack, while unwinding. Ironically enough, Java is purely garbage collected, so try/catch is not required; a simple long jump would suffice. Java has try/catch because C++ has try/catch, not because it's necessarily a good idea.

    (Overall, I find Java's exception mechanism to be vastly overcomplicated for the task it performs, but not actually a misfeature. There are plenty of real problems with the language, this one is merely less than ideal)



  • @asuffield said:

    Ironically enough, Java is purely garbage collected, so try/catch is not required; a simple long jump would suffice.

    GC is "unreliable" when it comes to closing database connections and similar resources. 



  • Aren't those unmanaged stuff? That's why there is an IDisposable interface and special language (like 'using' in C#) and runtime features in .NET - The GC won't touch anything that's not managed, so you have to make sure stuff is properly disposed yourself.

    -----

    I think dhromed already said it all. It doesn't matter how good a programmer is, there is always some situation which is not under his control - machine failure, wronged user input etc. try-catch is for those situations, even in production code.

    Suppose you have a block of code that executes some operations in a network. If some cable gets damaged, a machine loses connectivity and that block as a whole fails. Without a feature to group all the code that could fail that way somehow, you'd end up checking for a live connection before every line of actual code. It's much more productive to just place it in some try and right after it you catch for whatever type of Exception has to do with dead connections.



  • [quote user="Renan "C#" Sousa"]

    Aren't those unmanaged stuff? That's why there is an IDisposable interface and special language (like 'using' in C#) and runtime features in .NET - The GC won't touch anything that's not managed, so you have to make sure stuff is properly disposed yourself.

    [/quote]

    It's not a question of managed vs. unmanaged. The real problem is: A database is configured to allow only, say, 200 concurrent connections. Let's assume a long-running server programm connects regulary, but leaves disconnecting to the GC. Now when will the GC start collecting, thus closing the old database sessions? Only when it thinks it's time to do so, i.e. when memory is low. Unfortunately, it might just happen that the program does not run out of memory, so the GC never starts collecting and the database starts refusing new connections.




  • [quote user="Renan "C#" Sousa"]

    Suppose you have a block of code that executes some operations in a network. If some cable gets damaged, a machine loses connectivity and that block as a whole fails. Without a feature to group all the code that could fail that way somehow, you'd end up checking for a live connection before every line of actual code. It's much more productive to just place it in some try and right after it you catch for whatever type of Exception has to do with dead connections.

    [/quote]

    There are many other models to handle this, several of which are often neater and saner than the exception-catching mechanism. For example, the thread-cancellation model is often a good one; it is used by unix platforms as the default model for processes (if you drop a connection, and don't handle it, then a SIGPIPE terminates your process and the parent is responsible for cleaning up and/or restarting it).

    That's not to say that the exception-catching model doesn't have its uses, but it is hardly necessary. 


Log in to reply