[Mono-list] Exceptions and error codes.
   
    Thong (Tum) Nguyen
     
    tum@veridicus.com
       
    Fri, 21 Mar 2003 09:33:09 +1200
    
    
  
> -----Original Message-----
> From: mono-list-admin@lists.ximian.com [mailto:mono-list-
> admin@lists.ximian.com] On Behalf Of Piers Haken
> Sent: Friday, 21 March 2003 8:59 a.m.
> To: tum@veridicus.com; mono-list@lists.ximian.com
> Subject: RE: [Mono-list] Exceptions and error codes.
> 
> > -----Original Message-----
> > From: Thong Nguyen [mailto:tum@veridicus.com]
> > Sent: Thursday, March 20, 2003 12:14 PM
> > To: mono-list@lists.ximian.com
> > Subject: [Mono-list] Exceptions and error codes.
> >
> >
> > Hiya guys,
> >
> > I recently read some recommendations on the GTK# mailing list
> > regarding the use of exceptions.
> 
> You make some good arguments, but I think most of it is irrelevant
> since, in order to remain compatible with .NET, Mono must behave the
> same way with respect to returning (or not) exceptions. The MSDN docs
> describe exactly what exceptions/return codes File.Exists and
File.Open
> should return, Mono should do the same (unless the docs are in error).
A
> lot of work has already been done on this. You'll notice that many of
> the test cases test whether or not the correct exception is being
> returned.
Definitely.  I was more referring to our own class libraries (such as
GTK#).
> 
> Of course, for new class libraries many of your arguments are valid.
> Although I'd argue that the case for exceptions in .NET isn't as
> clear-cut as you propose.
> 
> For example, since you're not required to declare the exceptions that
a
> method throws, it's just as easy to miss handling an exception as it
is
> to miss handling a return code.
That's true.  The issue of checked exceptions opens up another can of
worms that I'm not willing to open here ;-).
But remember, with exceptions you still have the security of knowing the
following statements won't execute.
> The argument that it's easy to forget to
> handle a return code is purely subjective. I've been writing COM code
in
> C++ since '95 and I've found that it's quite simple to get into the
> habit of checking the result of every call and doing it in a way
that's
> readable. 
Yes.  I've written a lot of COM code myself and have found that you do
get used to using the SUCCESS macro ;-).  It's just a pain when you want
to handle errors for a block of code in the same way -- which happens
very often.  In COM there is no choice; you *must* check and handle
every HRESULT.
> In fact I often find that code that explicitly checks return
> codes for each call is easier to read than code that relies on catch
> blocks, since you know exactly which error handling code is associated
> with each call. Catch locks are fine if you want to apply the same
> exception handling code to a whole bunch of code, but as soon as you
> have to nest them they become unwieldy.
> 
> For example, compare:
> 
> try
> {
> 	DoSomething ();
> 	try
> 	{
> 		DoSomethingElse ();
> 		// some more code here...
> 	}
> 	catch (Exception e)
> 	{
> 		// handle exception in DoSomething ()
> 	}
> }
> Catch (Exception e)
> {
> 	// handle exception in DoSomethingElse ()
> }
Typically, if you design a good exception hierarchy the code is a lot
tidier:
try
{
  DoSomething();
  DoSomethingElse();
}
catch (DoSomethingException e )
{
}
catch (DoSomethingElseException e)
{
}
Or you if you want to handle both the same way:
try
{
  DoSomething();
  DoSomethingElse();
}
catch (DoException e)
{
  // catch(exception) is bad cause you can swallow things
  // like OutOfMemorryException
}
You can write code for the "best case" (e.g. no error) and handle the
errors in a pseudo declarative way (with exceptions).  I'm a sucker for
declarative languages.
> 
> With
> 
> HRESULT hr;
> if (FAILED (hr = DoSomething ()))
> {
> 	// handle error in DoSomething ()
> }
> else if (FAILED (hr = DoSomethingElse ()))
> {
> 	// handle error in DoSomethingElse ()
> }
> else
> {
> 	// some more code here...
> }
> 
> 
> 
> Or, if you don't need nested catch blocks:
> 
> 
> HRESULT hr;
> if (FAILED (hr = DoSomething ()) ||
>     FAILED (hr = DoSomethingElse ()))
> {
> 	// handle error
> }
> else
> {
> 	// some more code here...
> }
> 
> Or, if you prefer your error handling to be at the end:
> 
> HRESULT hr;
> if (SUCCEEDED (hr = DoSomething ()) &&
>     SUCCEEDED (hr = DoSomethingElse ()))
> {
> 	// some more code here...
> }
> else
> {
> 	// handle error
> }
> 
The tidied try/catch looks nicer IMO :-).
What if you had 10 statements and they all should be handled the same
way?
Use this:
HRESULT hr;
if (SUCCEEDED (hr = DoSomething1()) &&
    SUCCEEDED (hr = DoSomething2()) &&
    SUCCEEDED (hr = DoSomething3()) &&
    SUCCEEDED (hr = DoSomething4()) &&
    SUCCEEDED (hr = DoSomething5()) &&
    SUCCEEDED (hr = DoSomething6()) &&
    SUCCEEDED (hr = DoSomething7()) &&
    SUCCEEDED (hr = DoSomething8()) &&
    SUCCEEDED (hr = DoSomething9()) &&
    SUCCEEDED (hr = DoSomething10()))
{
	// some more code here...
}
else
{
	// handle error
}
Or this:?
try
{
  DoSomething1();
  DoSomething2();
  DoSomething3();
  DoSomething4();
  DoSomething5();
  DoSomething6();
  DoSomething7();
  DoSomething8();
  DoSomething9();
  DoSomething10();
}
catch (DoException e)
{
}
All the best,
^Tum
---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.461 / Virus Database: 260 - Release Date: 10/03/2003