[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