views:

1014

answers:

15

My question is pretty vague :o) - But here is an example :

When I was writing C code, I was able to log counter's value when something failed :

   <...>
   for ( int i = 0 ; i < n ; i++ )
      if ( SUCCESS != myCall())
         Log( "Failure, i = %d", i );
   <...>

Now, using exceptions, I get this :

  try
   {
      <...>
      for ( int i = 0 ; i < n ; i++ )
         myCall();
      <...>
   }
   catch ( Exception exception )
   {
      Log( "Failure ! Maybe in myCall() ? Don't know. i's value ? No clue." );
   }

Of course, one may declare "i" outside of the try/catch statement (and this is what I'm doing). But I don't like it - I like declare variable where they are used, not before.

But maybe am I missing something here. Do you have any elegant solution ?

Thank in advance ! Sylvain.

ADDED : myCall() is an obscure API call - I have no clue what it can throw. Also, I can of course add a Try/Catch block around each call, but I would then be better to use return codes ? Would I then add a lot of noise around important lines of code ?.

+3  A: 

It can be more elegant, if the object that you throw, can hold the context information that tells you something about the nature of the error.

Derive a throwable object from an istream, and you can use >> to stream information into it. teach the object how to display itself <<.

When you detect an error condition, in the level below, or N levels below. Fill up your object with good context information, and throw it. When you catch the object, tell it to display its context information to the log file, and/or the screen and/or whereever you want it to.

EvilTeach
+6  A: 

how about:

for(int i = 0; i < n; i++)
{
  try
  {
    myCall();
  }
  catch(Exception e)
  {
    Log(String.Format("Problem with {0}", i));
  }
}
scottm
It's a valid solution, but the try/catch block will probably add a significant overhead when done inside a loop.
Hosam Aly
@Hosam: "probably"? If this is performance critical software, then the performance impact should be measured before changing the code. If this is not performance critical software (ie. it runs 10 times a day), then it's simply not a problem.
Greg Hewgill
@Hosam: The try/catch block will only incur overhead when an exception is thrown.
Scott Dorman
@Scott Dorman is correcthttp://stackoverflow.com/questions/52312/what-is-the-real-overhead-of-try-catch-in-c
scottm
It would works, of course, but imagine adding a try/catch block for each and every call ! It would be worst then using a simple return code (you replaced 2 lines of code with 11 - it seems a lot less readable)
Sylvain
you can put it on one line if you want.
scottm
+2  A: 

Of course, one may declare "i" outside of the try/catch statement (and this is what I'm doing).

Well … if you really need to know the value of i then this seems like a logging vehicle – structured exception handling probably isn't the best way then. If you want to handle the exception conditionally (i.e. only when debugging), put the try block inside the loop. Since this may hurt performance (depending on your environment), only do this in debug mode.

Konrad Rudolph
+1  A: 

First things, first. If you are trapping Exception you are wrong. You should be trapping the specific exception you are expecting.

But that aside, if your exceptions are being thrown by your own code, you can use intelligent exceptions to encompass all the data you need to know about that exception.

For instance, an ArrayIndexOutOfBoundsException will contain the index addressed.

Matthew Brubaker
+1  A: 

Well! you could do this:

   try
   {
      <...>
      for ( int i = 0 ; i < n ; i++ )
         try {
            myCall();
         } catch(Exception e) {
            println("bloody hell! " + i);
         }
      <...>
   }

I think Exceptions are cooler than Java shows it to you. What is really fun is to have the debugger come up on every exception that isn't handled and then take a look at the stack at the moment of failure, so that you can examine i without having to change a line of code. That is, I believe, what exceptions should be for.

nes1983
Exceptions may help you in debugging, but they are mainly intended to address run-time failures (unexpected ones in particular). Code is made to run *outside* the debugger! :)
Hosam Aly
+5  A: 

Yeah. 2 things.

Put the try-catch blocks where they make sense. If you're interested in exceptions from myCall (as well as i's value) then use

for ( int i = 0 ; i < n ; i++ )
    try { myCall(); } catch ( Exception exception ) {
        Log( "Failure, i = %d", i );
    }

Throw objects of different classes for different errors. If you're interested in logical errors occurring in financial processing, throw finances::logic_error, not std::exception("error msg") or something. This way you can catch what you need.

Well, you are right, but it seems to me that ypu add a lot of noise around your code (return codes would require less noise). I don't say return codes are better of course, just that it's hard to see the intent when we read this code. Thanks for your answer !
Sylvain
Hmm - BUT *are* you interested in i's value and in the exact throwing function? Even though myCall is just a "an obscure API call"? So you do this for all calls eh? Seems to me that you're doing your debugger's job.
iow: try describing your exact aim. Should help me answer you a bit better -- though I don't actually understand exceptions either (and hardly have done any error handling, heh)
Right - i'm a beginner here. I Have done more C than C# (15 years vs 2 years). I read books about C# and error handling - they say : don't catch exceptions you can't handle, let them bubble up. Nice, but when our softwares fails, we don't have local information. Your answer is still the one I prefer
Sylvain
+2  A: 

You can get more specific information in two ways. First, don't catch Exception, catch a specific exception. Second, use multiple try/catch statements in a function where you need to be sure which function call threw the exception.

Jon B
A: 

You can derive from RuntimeException and create your own exception that mycall() throws. Then you can catch that with try/catch.

mslot
+1  A: 

Many exception handling tools (MadExcept for Delphi is one) allow you to retrieve the entire stack trace when you catch the exception. So, you'd know exactly where it was thrown.

The common technique for getting "i" is to catch the exception, and add extra data to it (the istream technique) before rethrowing it. It's rare that this is necessary, but if you insist...

Roddy
+2  A: 

In my opinion, exceptions shouldn't be used in such a case, but if you really need them, I'd go the following way:

You could pass the 'i' as a parameter to the myCall(); function and if any error occured, some special exception would be thrown. Like:

public class SomeException : Exception
{
     public int Iteration;

     public SomeException(int iteration) { Iteration = iteration; }
}

The loop block:

try
{
    for(int i = 0; i < n; ++i)
    {
        myCall(i);
    }
}catch(SomeException se)
{
    Log("Something terrible happened during the %ith iteration.", se.Iteration);
}

And finally the myCall() function:

void myCall(int iteration)
{
    // do something very useful here

    // failed.
    throw new SomeException(iteration);
}
arul
+3  A: 

I don't like the "now, with exceptions..." expression.

Exceptions are a tool that you have for using it in your programming - if you think that it is the best option, use it, otherwise, don't.

I follow a personal rule of not throw any exceptions that I can avoid throwing, in internal code. For an API of a publicly available DLL, precondition checks should be left enabled and trigger exceptions if they fail, yes; but for internal logic, I seldom (if ever) include exceptions in my design. Conversely, when I'm using some function that documents that it will throw if some bad situation happens, I tend to capture the exception inmediately - it is an expected exception, after all.

If you think that your non-exceptional alternative is better - stick to it!

Daniel Daranas
+2  A: 

We lose the possibility to easily see how the code will handle failures in different places. Raymond Chen has written a good article about it

erikkallen
+3  A: 

I think you've got it wrong, and its not surprising as many other people do too.

Exceptions are not to be used for program flow. Read that again, its important.

Exceptions are for the "whoo, that's wasn't supposed to happen" errors that you hope never to see at runtime. Obviously you will see them the moment your first user uses it, which is why you have to consider the cases where they might happen, but you should still not try to put code in to catch, handle and continue as if nothing had happened.

For errors like that, you want error codes. If you use exceptions as if they were 'super error codes' then you end up writing code like you mentioned - wrapping every method call in a try/catch block! You might as well return an enum instead, its a lot faster and significantly easier to read error return code than litter everything with 7 lines of code instead of 1. (its also more likely to be correct code too - see erikkallen's reply)

Now, in the real world, it is often the case that methods throw exceptions where you'd rather they didn't (EndOfFile for example), in which case you have to use the "try/catch wrapper" anti-pattern, but if you get to design your methods, don't use exceptions for day-to-day error handling - use them for exceptional circumstances only. (yes, I know its difficult to get this kind of design right, but so is much of design work)

gbjbaanb
Think you're right. I read somewhere (pragmatic programmer ?) that your code should still work fine when you remove all exception handling code. That is to say, exception should only be unexpected condition, not common error handling. Thanks.
Sylvain
+3  A: 
Andrzej Doyle
+3  A: 

Consider the opinions of Raymond Chen as well as Microsoft's x64-thinking.
(( raymond chen exceptions )) as a Google-query is enough to get you to his classic essays "Cleaner, more elegant, and wrong -- Just because you can't see the error path doesn't mean it doesn't exist." and the clarification "Cleaner, more elegant, and harder to recognize".
(( x64 exception model )) gets you to the MSDN article "Everything You Need To Know To Start Programming 64-Bit Windows Systems", which contains the quote "The downside to table-based exception handling (relative to the x86 stack-based model) is that looking up function table entries from code addresses takes more time than just walking a linked list. The upside is that functions don't have the overhead of setting up a try data block every time the function executes."
To summarize this quote, in x64 it is free or nearly-free to setup a "catch" which is never used, but to actually throw-catch an exception is slower than in x86.

pngaz
Very interesting. 1 vote !
Sylvain