Problems Handling Errors Correctly

D

Doug Semler

Jonathan Wood said:
Doug,


So the using statements for fs and gs are unnecessary in your example?

Only for this example. I worded my example VERY carefully. There is a
parameter to the GZipStream class that I did not specify, and that is
"leaveOpen". The paramter, if not used, is false. However, if you pass a
true to it, when the GZipStream is closed, the underlying stream *WILL*
remain open.

However, even though Close() calls Dispose() in these cases, I would never
count on it. If a class implements IDisposable, you should always call
Dispose via using or directly. The class should be able to handle you
calling Dispose a zillion times and not barf on it (and if it doesn't that's
a bug said:
I'm still pretty new to .NET but doesn't that prevent you from reusing a
closed stream? Or is the point that you would never want to reuse a closed
stream unless you reinitialized it? Or, better still, what if you wanted
to create another BinaryWriter on gs? You're saying you cannot once one
BinaryWriter based on gs has closed. That can't be a good thing can it?

Which is why, as has been alluded, Close() and Dispose() should be treated
differently. There's another thread recently that talked about this fact.
For these examples, I don't know what use reopening the types of streams
about which we are talking would be. The main point I was making is that
one has to be very careful about "chaining" streams together, because the
behavior of Close can lead to unexpected side effects...

Personally, I think that if a class has both a Close and Dispose, that
Dispose should call Close and Close should never call Dispose. It should
also be well (or better) documented that a Stream takes ownership of a
BaseStream when the base stream is passed in to the constructor. I've been
burned by that before...


--
Doug Semler, MCPD
a.a. #705, BAAWA. EAC Guardian of the Horn of the IPU (pbuhh).
The answer is 42; DNRC o-
Gur Hfrarg unf orpbzr fb shyy bs penc gurfr qnlf, abbar rira
erpbtavmrf fvzcyr guvatf yvxr ebg13 nalzber. Fnq, vfa'g vg?
 
J

Jonathan Wood

Doug,
The class documentation is (mostly) generated from code comments - I don't
remember the web site off hand but Google "SandCastle help generator" and
you'll find a utility that turns the xml file generated from the code
comments into MSDN style documentation (it is a public version of
Microsoft's tool they use to generate alot of the class documentation)

Aha! Pretty much what I expected. Since /// <summary> isn't the easiest
place to edit text, that really makes a lot of sense to me. Will check out
that generator too.
It's pretty complete (exception documentation, that is) in my experience.
Every once in a while you'll get an exception that's thrown from deep in
the stack that doesn't seem intuitve, but for me it's usually when I'm
dealing with remoting or xml stuff. I would think that requiring any
framework the size of .NET to document all possible Exceptions that could
be thrown from calls to subfunctions is next to impossible (and I think
MSDN's documentation had even stated in the past at least that the
<exception> doc tag should document excpetions thrown directly from the
function itself and not those from sub functions.

Yeah, the bottom line is that I don't particularly care for try...catch
exceptions. It gets to where you put try...catch in every routine if you
want to ensure you're program will never crash with an unhandled exception.

Jonathan
 
J

Jonathan Wood

Doug,
Only for this example. I worded my example VERY carefully. There is a
parameter to the GZipStream class that I did not specify, and that is
"leaveOpen". The paramter, if not used, is false. However, if you pass a
true to it, when the GZipStream is closed, the underlying stream *WILL*
remain open.

Okay, so it was more a general comment on possible behavior, and certainly
not a behavior you could rely on when writing code.
However, even though Close() calls Dispose() in these cases, I would never
count on it. If a class implements IDisposable, you should always call
Dispose via using or directly. The class should be able to handle you
calling Dispose a zillion times and not barf on it (and if it doesn't
that's a bug <g>)
Right.

Which is why, as has been alluded, Close() and Dispose() should be treated
differently.

Sure, I'd treat them differently. But if Close() calls Dispose(), then that
would be unexpected behavior for me.
Personally, I think that if a class has both a Close and Dispose, that
Dispose should call Close and Close should never call Dispose.

Definitely--I agree.

Jonathan
 
P

Peter Duniho

Jonathan said:
[...]
Yeah, the bottom line is that I don't particularly care for try...catch
exceptions. It gets to where you put try...catch in every routine if you
want to ensure you're program will never crash with an unhandled exception.

That's not a good idea, IMHO.

I never put exception handlers around code except when: a) I can recover
gracefully from the exception and want to, and b) it's something that is
known to be able to throw an exception.

If you are putting an exception handling block in every routine, you are
doing WAY too much work.

Lots of methods are documented as being able to throw exceptions, but in
many cases these exceptions are only thrown when you fail to call the
method correctly in the first place. Rather than spending your time
writing exception handling code for those methods, you should spend your
time ensuring that you are calling the method correctly so that it won't
throw an exception.

Pete
 
D

Doug Semler

Yeah, the bottom line is that I don't particularly care for try...catch
exceptions. It gets to where you put try...catch in every routine if you
want to ensure you're program will never crash with an unhandled exception.

To me, exceptions are just that: "exceptional cases that should not
occur in normal usage" I treat them as "I fu*ked something up
somewhere". If I get an exception (unhandled or otherwise) I try to
fix the underlying CAUSE of the exception, whether it be due to
invalid arguments to a function or openning a nonexistent file. There
are some cases that I can think of that would have been more
convenient to return an error status than throw an exception (remoting
servers not available comes to mind <g>) back to me, but those are the
cases where I trap an exception in my code so that I can provide
graceful recovery/retry/feedback (a user isn't going to want to see
"SocketException" when trying to connect to a server when the network
is down...). General top level exception handlers are, to me, a bad
thing, because they tend to hide the underlying cause of problems from
the programmer.


You can still gracefully exit from unhandled exceptions: Add the
appropriate delegate to the AppDomain.CurrentDomain.UnhandledException
event and (for WinForms code) one to the Application.ThreadException
event. This way you can gracefully exit from/display/log any
exceptions that your code would not otherwise handle.
 
J

Jonathan Wood

This reminds me of older QuickBASIC and then, later, Visual Basic (prior to
VB.NET). I could always tell when a program was written in these languages
by programmers without a tremendous amount of experience because trying a
few odd things would usually result in an unhandled error, which would crash
the program and terminate it without any chance to save your data, etc.

After years of writing fairly bullet-proof applications peppered throughout
with ASSERTS for debugging, I'm not prepared to go back to writing apps that
can crash this way.

That's why I'm not crazy about exception handling.

Jonathan

Peter Duniho said:
Jonathan said:
[...]
Yeah, the bottom line is that I don't particularly care for try...catch
exceptions. It gets to where you put try...catch in every routine if you
want to ensure you're program will never crash with an unhandled
exception.

That's not a good idea, IMHO.

I never put exception handlers around code except when: a) I can recover
gracefully from the exception and want to, and b) it's something that is
known to be able to throw an exception.

If you are putting an exception handling block in every routine, you are
doing WAY too much work.

Lots of methods are documented as being able to throw exceptions, but in
many cases these exceptions are only thrown when you fail to call the
method correctly in the first place. Rather than spending your time
writing exception handling code for those methods, you should spend your
time ensuring that you are calling the method correctly so that it won't
throw an exception.

Pete
 
J

Jonathan Wood

Doug,
To me, exceptions are just that: "exceptional cases that should not
occur in normal usage" I treat them as "I fu*ked something up
somewhere". If I get an exception (unhandled or otherwise) I try to
fix the underlying CAUSE of the exception, whether it be due to
invalid arguments to a function or openning a nonexistent file.

The problem is that entering an invalid filename is not an exceptional case.
Users do it all the time. If there's a method to first determine if a file
exists, then calling it would probably be a good idea (although I suspect
most developers do not). But issue like not having access to a file are, to
me, also not an exceptional case. (There are also software-design issues
that would dictate you program more defensively rather than relying on being
able to fix the underlying cause of every possible exception, but that's
another issue.)

There are hundreds of potential errors that I do not consider exceptional
cases and they all seem to be handled by throwing exceptions. If exception
handling was used ONLY for exceptional cases, it might not bother me as
much. But it's not. It's used for pretty much every type of error possible.
You can still gracefully exit from unhandled exceptions: Add the
appropriate delegate to the AppDomain.CurrentDomain.UnhandledException
event and (for WinForms code) one to the Application.ThreadException
event. This way you can gracefully exit from/display/log any
exceptions that your code would not otherwise handle.

I wasn't familiar with that. Although less than ideal, that's probably
something I will end up making use of.

Thanks.

Jonathan
 
P

Peter Duniho

Jonathan said:
[...]
After years of writing fairly bullet-proof applications peppered
throughout with ASSERTS for debugging, I'm not prepared to go back to
writing apps that can crash this way.

..NET has Asserts. And while it's true that other programmers can write
code so carelessly that you can crash the app and lose data in
relatively common scenarios, there's no reason you have to follow in
their footsteps.

Most importantly, however, is that to protect your application against
your own mistakes does not require putting exception handlers in every
routine. In fact, doing so goes against any sensible development
practice, IMHO. If you can anticipate the need to catch an exception,
you can simply spend the time to write the code to ensure it won't throw
an exception.

If you can't anticipate that need, then don't put an exception handler
there. You can instead put a single exception handler near the top of
the processing; the whole processing operation will of course fail if an
exception occurs, but that's likely anyway, even if you litter your code
with exception handling.

Pete
 
P

Peter Duniho

Jonathan said:
The problem is that entering an invalid filename is not an exceptional
case.

Sure it is.
Users do it all the time.

Well, obviously "all the time" is an exaggeration. More importantly, I
doubt that users even do it most of the time. If they do, you need
better users. :) Seriously though, unless you've got some awful UI
where a user has to type the entire filename instead of just selecting
it from a dialog, you're not actually going to see incorrect filenames
that often. That _is_ an exceptional case. Most of the time users will
be giving you correct filenames.
If there's a method to first determine
if a file exists, then calling it would probably be a good idea
(although I suspect most developers do not).

I disagree that you should check a filename for existence before trying
to use it. There's a lot of reasons that opening a file could fail, an
incorrect filename being but one of them. Even absent exception
handling, the correct thing to do is just try to open the file; if an
error happens, then you present the user with some specific information
about the error, based on the error code.

In the unmanaged Win32 API, you can use FormatMessage() to provide this,
and in .NET it's even easier, as you can just get the Message property
of the exception.

However, the more salient point here is that opening a file is a fairly
special case. You would have very strange code indeed if most or all
routines included a statement that opens a file, or even a statement
that is in some way like opening a file (that is, something that could
throw an exception even when coded correctly).

Even in the file opening case, you don't necessarily need an exception
handler around the line of code that could actually throw the exception.
You need it at the top level of the code that initiates whatever
action the user asked the code to do. The user provided you with bogus
data, and there's not anything you can do except simply fail the entire
operation.

One of the nice things about exceptions is that you don't have to write
a bunch of intermediate error-handling code in this case. Something
very deep in the operation could throw an exception, due to bad user
input early on, and you still only need error-handling at the top level.

If there are objects in the middle that need cleaning up, you still need
some kind of handling there. But generally this is limited to the
using() statement, because otherwise you're dealing with an object that
would still be around at the top level and could be cleaned up there.

A very important point here is that this is not any different from the
architecture without exception handling, except that without exception
handling you need to check return values at each and every statement and
use that to control flow to deal with the necessary clean-up, if any.
In other words, exception handling does NOT add to your error handling;
all it does it REDUCE it.

If you have code that needs an exception handler in .NET, then in an
environment without exception handling, you instead need to be checking
return values. The only thing that's different is the form in which the
error checking exists, and because exceptions can skip over stack frames
that don't require notification, it actually simplifies the code.
[...]
There are hundreds of potential errors that I do not consider
exceptional cases and they all seem to be handled by throwing
exceptions.

IMHO, this is mainly because you are misinterpreting the word
"exception". The "exceptional" case is simply the flow of code that is
different from the normal, desired effect. "Exceptional" does not mean
"rare"; it just means "different from the typical case".

Basically: to know what's the exception case, write the code without any
error handling at all. Then, any place where you would add
error-handling, those errors are your exceptional cases.
If exception handling was used ONLY for exceptional cases,
it might not bother me as much. But it's not. It's used for pretty much
every type of error possible.

All errors are exceptional. That's what makes them errors. But more
importantly, you are required to handle errors one way or the other.
Even without exception handling, you need to check the return value. So
if it's true that in .NET you are forced to put exception handlers
everywhere, then in some other environment (unmanaged Win32 for example)
you are forced to put return-code checking everywhere.

The truth is you are not forced to put exception handlers everywhere in
..NET, but in unmanaged Win32 code you still need to put return-code
checking everywhere. Exceptions actually make error-handling _easier_,
not harder.

Pete
 
A

Arnshea

I'm trying to figure out the best way to handle errors in my code.

I understand try...catch...finally just fine. But I find that in practice
(in large part due to the lack of deterministic finalization), it's rarely
that simple.

Consider the following code. In order to ensure my writer and reader object
clean up in a timely manner no matter what, I've added two using blocks. But
do I need another using block for webResponse? For that matter, how about
webRequest?

This is what has always bothered me about .NET. Doesn't using add it's own
try...catch...finally blocks? In the end, it's really not clear where I need
them and where I don't, so I end up with tons of them. And that can't be
good for performance. Any suggestions?

try
{
// Get string to be posted
string post = PostString;

HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = PostString.Length;
using (StreamWriter writer = new
StreamWriter(webRequest.GetRequestStream()))
{
writer.Write(post);
writer.Close();
}
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
using (StreamReader reader = new
StreamReader(webResponse.GetResponseStream()))
{
_rawResult = reader.ReadToEnd();
reader.Close();
}
webResponse.Close();
}
catch (Exception e)
{
_message = e.Message;
}

Jonathan

I've generally settled on not using an Exception if the cause is
something the user can correct. In these cases you'll end up setting
the text of some label (or some similar mechanism) then branching out
of the call. This includes cases like input that not well-formed,
invalid, missing, etc... IMO using exceptions for these kinds of
conditions is unnecessarily expensive and becomes hard to maintain
once the code has been through a few refactorings. A test program
that throws a bunch of FileNotFoundException vs checking for file
existence in a loop bears this out on my machine.

For cases where there isn't anything the user can do then I would
handle these all with a top-level exception handler except in the case
where I might be able to provide information that can help with
troubleshooting. E.g., if your web app connects to several databases,
any 1 of which might be down, I would probably trap the SqlException,
wrap it in an ApplicationException and include a user friendly error
message with useful information (e.g., the name of the server/instance
that was down).
 
J

Jonathan Wood

Peter,
.NET has Asserts. And while it's true that other programmers can write
code so carelessly that you can crash the app and lose data in relatively
common scenarios, there's no reason you have to follow in their footsteps.

Yup, and I'll be using those Asserts if they're implemented "correctly." But
I still find it an up-hill battle with the way exceptions are used.

Jonathan
 
J

Jonathan Wood

Peter,
Sure it is.

Ever hear of defensive driving? The same technique can be applied to
programming. And for all practical purposes, it should be assumed that the
user will enter invalid filenames.
Well, obviously "all the time" is an exaggeration. More importantly, I
doubt that users even do it most of the time.

What percent of the time would they need to enter either invalid filenames
or files that cannot be used, for one reason or another, for the purpose it
was selected before you would decide that your application should handle
that case?
I disagree that you should check a filename for existence before trying to
use it. There's a lot of reasons that opening a file could fail, an
incorrect filename being but one of them. Even absent exception handling,
the correct thing to do is just try to open the file; if an error happens,
then you present the user with some specific information about the error,
based on the error code.

With an exception handler, I assume.
One of the nice things about exceptions is that you don't have to write a
bunch of intermediate error-handling code in this case. Something very
deep in the operation could throw an exception, due to bad user input
early on, and you still only need error-handling at the top level.

Yes, I understand the benefits of exception handling and I would use this
approach to an extent, but when taking this approach you are less likely to
get a meaningful error message as it won't be as clear which of the many sub
operations actually failed.
A very important point here is that this is not any different from the
architecture without exception handling, except that without exception
handling you need to check return values at each and every statement and
use that to control flow to deal with the necessary clean-up, if any. In
other words, exception handling does NOT add to your error handling; all
it does it REDUCE it.

The difference is what happens if you miss an error. It only takes one, and
your entire app blows up. That's the difference and I find it a substantial
one. So I tried to delete a file that doesn't exist. What is the side effect
of not reporting that error? Lost data if you missed the raised exception.
IMHO, this is mainly because you are misinterpreting the word "exception".
The "exceptional" case is simply the flow of code that is different from
the normal, desired effect. "Exceptional" does not mean "rare"; it just
means "different from the typical case".

We obviously have different opinions about what is normal when dealing with
user input and resources.

Jonathan
 
J

Jonathan Wood

Arnshea,
I've generally settled on not using an Exception if the cause is
something the user can correct. In these cases you'll end up setting
the text of some label (or some similar mechanism) then branching out
of the call. This includes cases like input that not well-formed,
invalid, missing, etc... IMO using exceptions for these kinds of
conditions is unnecessarily expensive and becomes hard to maintain
once the code has been through a few refactorings. A test program
that throws a bunch of FileNotFoundException vs checking for file
existence in a loop bears this out on my machine.

I'm not real sure I follow. In the code example in the post you're
responding to, there is no way to detect an error other than in an exception
handler. And if you don't implement an exception handler and an error
occurs, your app will shut down without giving your users an opportunity to
save data.

We agree that excessive exceptions are unnecessary and expensive. My
complaint is that the frameworks are throwing excessive exceptions.

Jonathan
 
P

Peter Duniho

Jonathan said:
Ever hear of defensive driving? The same technique can be applied to
programming. And for all practical purposes, it should be assumed that
the user will enter invalid filenames.

No one, least of all me, has suggested otherwise.
What percent of the time would they need to enter either invalid
filenames or files that cannot be used, for one reason or another, for
the purpose it was selected before you would decide that your
application should handle that case?

I don't think you have read what I have written very closely. I never
said you shouldn't handle the case. I said that the error case is
exceptional.

Your statement implies that you think that "exceptional" means
"shouldn't handle it". Which is an odd thing for you to think, since
this whole thread is about _handling_ exceptions.

There is NO "percent of time" that a user would have to enter invalid
data for me to think you shouldn't handle that case. The question of
_whether_ the error should be handled is not in disagreement here; it's
_how_ the error should be handled.
With an exception handler, I assume.

Again, you don't seem to be reading the words I wrote.. Look at the
quote you included. I specifically wrote "even absent exception
handling". So, no...NOT "with an exception handler". Your assumption
is exactly opposite of what I wrote.
Yes, I understand the benefits of exception handling and I would use
this approach to an extent, but when taking this approach you are less
likely to get a meaningful error message as it won't be as clear which
of the many sub operations actually failed.

That's not true. In fact, if anything it's much more clear, because a
single error is thrown from the point at which it actually occurred.
The user can easily be provided very specific information about what
went wrong.

Without exception handling, this has always been a basic dilemma in
handling errors. That is, if you are propagating errors back up the
call chain, you have to decide at what point do you actually let the
user know?

Occasionally you'll find an application that maintains an error stack
and allows the user to scroll through all of the errors. So for example
a user might, after providing an invalid filename, be presented with
errors informing him that "the file doesn't exist", and that "the
database couldn't be opened", and that "the application could not switch
to maintenance mode".

But this is rare (and easily implemented with exceptions in any case).
In the vast majority of cases, an application presents the user with a
single error. It's always a design problem to figure out at what level
of error propagation to notify the user. A common solution is to
present a single alert, combining the highest and lowest level errors.

Without exceptions, to implement this the application still needs to
maintain the lowest level error code. It may pass this error code up
through the call chain, as a parameter or return value, or put it in a
global, or do something else with it. But it has to pass the value some
how.

With exceptions, the top level simply receives the exception directly
from that lowest level. It adds its own message information regarding
the high-level operation to the information regarding the low-level
operation that failed. Done. No messing around with passing things
through functions that don't care about errors, trying to overload
return values, or providing by-reference parameters that can chain error
values back up the stack.

There is nothing you can do without exceptions that you cannot do with
exceptions, and vice a versa. The implementation is different, but the
functionality is identical.

More importantly, the scenario you describe -- needing to present a
clear message to the user describing what low-level operation
specifically caused the problem -- is _easier_ to deal with using
exceptions, not harder.
The difference is what happens if you miss an error. It only takes one,
and your entire app blows up. That's the difference and I find it a
substantial one. So I tried to delete a file that doesn't exist. What is
the side effect of not reporting that error? Lost data if you missed the
raised exception.

This is no different than for returned error values. If you don't
bother to check a returned error value and the function failed, your
application blows up. But again, exceptions make things _easier_ for
you, because you only need a single exception handler, at the
highest-level code performing the operation. None of the lower-level
code needs an exception handler except where you need to clean things up
(and you would still need error handling in that situation even without
exception handling).
We obviously have different opinions about what is normal when dealing
with user input and resources.

Again, you don't seem to be reading the words I'm writing. The issue
doesn't have to do with what is "normal when dealing with user input and
resources" (that is, the error handling itself). It has to do with a
philosophical view of what's normal with respect to what the user might
_do_.

The philosophy doesn't change what errors you handle. All of the
"normal" things you might do when dealing with user input, you still do
with exceptions. It simply changes how you view the flow of the code,
and _how_ you handle errors.

For what it's worth, I went through a similar mind-set to the one you
seem to hold now, when C++ exceptions started to become more popular in
the various programming teams I was working in. I already had a
negative view of exceptions, from using setjmp/dojmp in a previous
project; while in hindsight my negative view was entirely my own fault,
because I had failed to adjust my conceptualization of error handling (*
see below), at the time it was still a powerful motivation for me to
reject exceptions.

So when an even more-formalized version of that architecture came along,
in the form of structured exception handling in C++, I was simply not
prepared to embrace it. In spite of people around me trying to explain
the advantages.

I went years after that without really shifting my views. I continued
to write code that simply checked return values. And truth be told,
it's not that I even object to that style of programming today.

However, in .NET you _must_ learn and use exception handling; it is
fundamental to how the Framework works. There is really no point in
being so hostile toward exception handling in any case, but in the .NET
environment that sort of hostility is only going to impede your
productivity. The sooner you relax and open your mind to the benefits
of exception handling, instead of being so darned convinced that you
already know everything there is to know about what's the right and
wrong way to handle errors, the sooner you will be a much happier
programmer.

I apologize if all of this sounds like a new-age Zen sort of "be the
exception" kind of thing. But the truth is a lot of the issue here
really is about you accepting exceptions as a valid and useful paradigm.
Until you do that, you will always have this road-block preventing you
from writing the best .NET code you could.

Pete

(*) Regarding conceptualization of error handling: what I failed to
understand early on about the difference is that when I was using return
values to deal with errors, it made me focus on the function that might
fail. All of my thoughts about error handling were along the lines of
"this function here is what made me have to stop the code from doing
what it was trying to do and recover". When I was dealing with code
that threw exceptions, I failed to get away from this mindset, which
gave me tunnel vision, preventing me from focusing instead on what _my_
code was doing locally.

IMHO, when dealing with exceptions, it is practically always the wrong
thing to do to think about what method might actually fail. Any number
of things might fail. The reason you handle an exception isn't because
some particular method might fail; it's because you need to make sure
that what you're doing locally can recover from a failure.

At the highest level, where a user initiates an operation, this simply
means presenting the user with the error message. At lower levels, this
means cleaning up whatever intermediate steps had already been taken for
the operation. But in all cases, it's not about the thing that failed;
it's about the thing you're doing locally.

IMHO, that's one really nice thing about exceptions. It allows you to
stay focused on the _non-exceptional_ case. Even in the situation where
you are actually handling an exception (and as I've pointed out, one
other advantage of exceptions is that a lot of intermediate code need
not do _any_ error handling, because it has nothing to clean up or
recover from), you only consider the exception in-as-much as it affects
something that you've done in the non-exceptional case.
 
A

Arnshea

I'm not real sure I follow. In the code example in the post you're
responding to, there is no way to detect an error other than in an exception
handler. And if you don't implement an exception handler and an error
occurs, your app will shut down without giving your users an opportunity to
save data.
Right - I think what you're doing is fine. You have a top-level
exception handler that should catch any errors that the user (or you)
can't correct (you may want to add an app domain unhandled exception
error and unhandled thread exception error). I believe Anders
Heljburg (sp?) is on record saying something to the effect of most try/
catch blocks in a program can't do anything to fix the issue so they
shouldn't try (no pun intended) to. In practice I've found that this
means most catch blocks just log the error possibly massaging it first
to make it more concise.
We agree that excessive exceptions are unnecessary and expensive. My
complaint is that the frameworks are throwing excessive exceptions.

Heh, maybe. OTOH, I'll take troubleshooting a stack trace over "ERROR
- 10061" or, my personal favorite, "Segmentation Fault", any day.
 
J

Jonathan Wood

Peter,
I don't think you have read what I have written very closely. I never
said you shouldn't handle the case. I said that the error case is
exceptional.

It's not that important that this is hashed out. But I did read what you
wrote. What I'm saying is that, if you handle certain errors everytime you
write certain types of code, then I would consider that a normal and
expected part of your application. That's my personal opinion.
Again, you don't seem to be reading the words I wrote.. Look at the quote
you included. I specifically wrote "even absent exception handling". So,
no...NOT "with an exception handler". Your assumption is exactly opposite
of what I wrote.

Then you lost me. If you just try and open the file and an error happens, an
exception will be raised. That's how the file classes in the .NET frameworks
behave. So I don't get how you're going to detect that failure withon an
exception handler.
That's not true. In fact, if anything it's much more clear, because a
single error is thrown from the point at which it actually occurred. The
user can easily be provided very specific information about what went
wrong.

Well, I have personal experience with error messages that only make sense in
the context of the specific method call, and not in the context of the
overall task at hand. So, while you are free to disagree, I do not accept
the assertion that I am wrong.
There is nothing you can do without exceptions that you cannot do with
exceptions, and vice a versa. The implementation is different, but the
functionality is identical.

No, there is one thing you can do differently: without exceptions you can
safely ignore errors that your application is not concerned with. If an
exception is raised, then you cannot do this.
This is no different than for returned error values. If you don't bother
to check a returned error value and the function failed, your application
blows up.

Well, now I don't think you are reading what *I* wrote. I gave an example of
deleting a file. In my C++ applications, I generally do not check for
returned error values when deleting a file. And my app does not blow up. It
continues on because no exception is raised.
Again, you don't seem to be reading the words I'm writing. The issue
doesn't have to do with what is "normal when dealing with user input and
resources" (that is, the error handling itself). It has to do with a
philosophical view of what's normal with respect to what the user might
_do_.

You seem pretty set on me seeing this just as you do. That's probably a
waste of time. But, with respect to statements you've made about me not
reading what you wrote, I don't see where you've been correct about that,
although I do admit I didn't understand a couple of statements.
So when an even more-formalized version of that architecture came along,
in the form of structured exception handling in C++, I was simply not
prepared to embrace it. In spite of people around me trying to explain
the advantages.

For the record, I have used C++ exception handling for many years. But,
depending on the circumstances, I don't like it for everything.
However, in .NET you _must_ learn and use exception handling; it is
fundamental to how the Framework works. There is really no point in being
so hostile toward exception handling in any case, but in the .NET
environment that sort of hostility is only going to impede your
productivity. The sooner you relax and open your mind to the benefits of
exception handling, instead of being so darned convinced that you already
know everything there is to know about what's the right and wrong way to
handle errors, the sooner you will be a much happier programmer.

Resistance is futile. <g>

Jonathan
 
J

Jonathan Wood

Arnshea,
Right - I think what you're doing is fine. You have a top-level
exception handler that should catch any errors that the user (or you)
can't correct (you may want to add an app domain unhandled exception
error and unhandled thread exception error). I believe Anders
Heljburg (sp?) is on record saying something to the effect of most try/
catch blocks in a program can't do anything to fix the issue so they
shouldn't try (no pun intended) to. In practice I've found that this
means most catch blocks just log the error possibly massaging it first
to make it more concise.

Yes, I agree. Even if a global handler presented an error that warns users
that the program may now be in an unstable state and should be shut down, it
is far more likely that the user will have a chance to save their data.

I was trying to develop a little .NET database program. Even though I had
added some exception handlers, some were still getting through. I had to
retype the data about 6 times before I got sick of it.
Heh, maybe. OTOH, I'll take troubleshooting a stack trace over "ERROR
- 10061" or, my personal favorite, "Segmentation Fault", any day.

What the heck, just install a global handler that says "An error occurred"
and be done with it. <g>

Jonathan
 
P

Peter Duniho

Jonathan said:
It's not that important that this is hashed out. But I did read what you
wrote. What I'm saying is that, if you handle certain errors everytime
you write certain types of code, then I would consider that a normal and
expected part of your application. That's my personal opinion.

It's not even an opinion I disagree with. But the word "exception" here
does not refer to what is a "normal and expected part of your
application". It refers to what the user or code _does_, not to what
specific kinds of code exists.

Just because you have an exception handler, that doesn't mean it's
exceptional for the exception handler to exist.
Then you lost me. If you just try and open the file and an error
happens, an exception will be raised. That's how the file classes in the
.NET frameworks behave. So I don't get how you're going to detect that
failure withon an exception handler.

My statement was a comparison/contrast between using exception handling
and not using exception handling. You are right, in .NET you don't have
a choice. You have to use exception handling.

But in other environments you don't. And in those environments, you
still just try to open the file and then let the user know if that failed.

The only thing that is different is how the error is detected. You
still need to detect and report the error. That is the whole point of
the statement that you seem to have misunderstood.
Well, I have personal experience with error messages that only make
sense in the context of the specific method call, and not in the context
of the overall task at hand. So, while you are free to disagree, I do
not accept the assertion that I am wrong.

If the error doesn't make sense in the context of the user's operation,
then you don't report it to them. Exception handling doesn't require
that you report all errors to the user; it's my opinion that informing
the user of the low-level error is helpful, but if you disagree that's
fine. It doesn't change the usefulness of exception handling.
No, there is one thing you can do differently: without exceptions you
can safely ignore errors that your application is not concerned with. If
an exception is raised, then you cannot do this.

IMHO, there is no such thing as "safely ignore errors". You should
always check for error results, if for no other reason than to allow
feedback to the user regarding what's actually happened.

That said, exception handling doesn't change that. You are free to put
an exception handler around code for which you don't care about a
failure and then not report the error to the user. And with exception
handling, you need not -- as you've asserted -- add exception handling
in every method. Just a single exception handling block at the
highest-level of the code handling the operation is sufficient.

Even if you never report an error to the user and never conditionally
change the flow of your code according to error codes returned by
functions, exception handling does not impose anywhere near the enormous
overhead you seem to be saying that it does.
[...]
Well, now I don't think you are reading what *I* wrote. I gave an
example of deleting a file. In my C++ applications, I generally do not
check for returned error values when deleting a file. And my app does
not blow up. It continues on because no exception is raised.

But the user is never informed that the file deletion failed. Why is
your application deleting a file that it doesn't actually care whether
it gets deleted or not?

IMHO, that's an example of faulty design.

Now, it's true that there are cases when a failure is non-fatal, and in
fact where you may not even need to inform the user. But that doesn't
mean you shouldn't be checking for the failure. It just means that you
should be handling the failure in some specific way, perhaps transparent
to the user (an example would be attempting to parse a string as a
variety of types, until you find a type it can be successfully parsed from).

Yes, without exception handling you are free to ignore errors. But IMHO
that's not a good thing. If anything, I count that as yet another
benefit of exception handling: your code must deal with errors. You
don't get the class of subtle bugs in which you forgot to check for an
error, or thought you didn't need to check for an error, when it turns
out you should have.

Pete
 
J

Jonathan Wood

Peter,
Just because you have an exception handler, that doesn't mean it's
exceptional for the exception handler to exist.

This is becoming an issue of semantics. If it is normal practice for me to
place an exception handler in certain types of code, then I consider an
error normal and expected for those types of code. That's how I look at it.
You are free to disagree.
IMHO, there is no such thing as "safely ignore errors". You should always
check for error results, if for no other reason than to allow feedback to
the user regarding what's actually happened.

We'll have to agree to disagree on that point.
But the user is never informed that the file deletion failed. Why is your
application deleting a file that it doesn't actually care whether it gets
deleted or not?

IMHO, that's an example of faulty design.

If it seems I am trying to wrap things up more than I'm trying to draw them
out, it may in part be due to the fact that I'm dealing with major issues
right now. Some of your input has definitely been appreciated. But I'm just
not in a position to hash everything out with you. We've both been
programming many years, and we're going to have strong opinions about it.

If I have an app that creates some temporary file and starts by deleting the
previous temporary file, what do I care if the existing file does not exist?
I want to ignore that error. It is my opinion that it doesn't matter. And if
it does not throw an exception, then I *can* ignore it. I do not consider
that a faulty design. That's my approach, based on the many years I've been
doing this. Your own mileage may vary.

Jonathan
 
P

Peter Duniho

Jonathan said:
This is becoming an issue of semantics.

Becoming? IMHO it's always been a matter of semantics. The only
problem I see with the semantics is inasumuch as one's semantic view of
the issue colors their architectural and design view as well.

Your is a common complaint among people who object to exception
handling. They argue that because something isn't in their minds
"exceptional" they don't want to handle it via exceptions. But that
argument is a straw-man; it deliberately misinterprets "exception" in
the context of an exception handling paradigm and then uses that
misinterpretation as justification for rejecting exception handling as a
useful paradigm.

So, you're in good company with respect to your line of reasoning. But
that doesn't mean the conclusion is reasonable.
[...]
If I have an app that creates some temporary file and starts by deleting
the previous temporary file, what do I care if the existing file does
not exist?

Why are you deleting the temporary file? That's a waste of time.

For example, in .NET you'd use the FileMode.Create mode. In unmanaged
Win32 code, you could use the CreateFile() function with the
CREATE_ALWAYS disposition parameter.

So, that's not a good example of a file deletion in which you don't care
about the return code. Not that a single example like that would
support the claim that exception handling creates some significant
overhead anyway, but at the very least an example we're to talk about
should have some practical use.
I want to ignore that error. It is my opinion that it doesn't
matter. And if it does not throw an exception, then I *can* ignore it. I
do not consider that a faulty design. That's my approach, based on the
many years I've been doing this. Your own mileage may vary.

Indeed. The bottom line here is that "my mileage" shows me that an
exception-based error reporting system does not in fact incur any
significant overhead as compared to an error reporting system that
instead depends on return codes.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top