Re: I keep running into long term c++ programmers who refuse to use exceptions
Seungbeom Kim <musiphil@bawi.org> wrote:
Daniel T. wrote:
When designing a program, one of the cases we have to consider is what
to do if something goes wrong and a shutdown/reset is required. Whatever
procedure is decided on goes in catch block(s). In other words, you put
in catch blocks because you realize you need to do something special
before shutdown/reset when something goes wrong, you do *not* put them
in simply because a particular function might throw or because that
function threw during QA testing. In the simplest case, you don't need
to do anything before shutdown/reset and in that case there wouldn't be
any catches in the program at all, no matter how many throws might exist.
I agree that adding exception handlers is not a mere preventive measure
or a quick cure to existing problems that should be fixed.
However, when functions advertised as being able to throw exceptions are
called, you certainly can choose to catch them in appropriate places.
You may not need to catch all exceptions, and you may just choose to
have no exception handlers because they can do very little anyway, but
in other cases not catching some exceptions may be considered as an
error and should be "fixed" by adding exception handlers.
Whenever reasonable, one should stick to the "exception handling is
error handling" view. When this is done, code is clearly separated
into two categories: ordinary code and error-handling code. This
makes code more comprehensible. -- Stroustrup
So we have two different scenarios on the table:
A) The program tries to open a file that is necessary for correct
function. This file is provided with the program and put in the correct
place during program installation.
B) The program tries to open a file that would be useful but isn't
necessary for correct function. A file name is provided by the user.
I don't think we have a clear line between the two.
Those were the two presented so far, others can certainly be
envisioned...
* What is the exact definition of "necessary for correct function"?
"Useful but unnecessary" seems to me like quite rare a condition, though
it certainly exists (e.g. for cache files).
* If a file is put in the correct place during program installation, is
it always necessary for correct function? If a help file was installed
but later deleted or somehow became inaccessible, is it necessary for
correct function and should its nonexistence cause the program to abort
when the user requests the help function?
That's up to the design of the program. In the scenario portrayed, the
file is necessary and it's nonexistence should cause the program to
abort.
* If a file name is provided by the user, is the file unnecessary for
correct function? Is the input file for "sort" or "gcc" unnecessary for
its correct function just because its filename is provided by the user?
Should the program do something different when it suffers an
unrecoverable error than when it can't find the file? I suspect the
answer is "yes."
I'm arguing that your definition of "necessary for correct function"
is vague, and that whether the filename is determined internally to the
program or comes from the user is not a useful criterion for deciding
whether "necessary for correct function" or whether to throw.
"Necessary for correct function" means that, if it fails your program
cannot correctly function, it must shutdown/reset.
For scenario A, use the OP's FileOpen function and if it throws, your
regular error handling and shutdown/reset system will deal with it. As I
said before, you should *not* add a catch just because FileOpen might
throw.
It's not always and automatically "just because it might throw". You
may have a reasonable need to cope with exceptions. You may reasonably
choose to catch the exception, let the corresponding part of the program
fail with an error message and let the rest continue. That's what happens
when any decent program should do when the user chooses Help but it can't
open the help file; it is simply unacceptable to just unwind the stack
all the way up to main() and lose the open documents.
"If an exception is expected and caught so that it has no bad effects on
the behavior of the program, then how can it be an error?" -- Stroustrup
By the way, what is your "regular error handling and shutdown/reset
system"?
The stuff inside the catch clauses.
For scenario B, don't use the OP's FileOpen function. In this case, the
program is not in error, the user is in error. Your program should
expect users to make errors like that, and their errors should not cause
your program to shutdown/reset.
You're arguing that exceptions should not be used to cope with user
errors. Why not?
Exception handling is a less structured mechanism than local control
structures such as if and for and is often less efficient when an
exception is actually thrown. Therefore, exceptions should be used
only where the more traditional control structures are inelegant or
impossible to use. Note that the standard library offers a queue of
arbitrary elements without using exceptions. -- Stroustrup
Because "user errors" should not be unrecoverable.
As I said before, a good indicator of a poorly planned/programmed system
is if there are a bunch of empty catch blocks lying around or if they
catch errors and "fix" them without re-throwing the exception (of course
the top level catch block need not re-throw.) Such code generally means
that the programmer was *expecting* the exception and using it for
normal program flow. Of course the real world is sometimes messy and
sometimes we don't have any choice, but such code is best avoided. A
thrown exception represents an unrecoverable error.
That depends on the exact meaning of "(un)recoverable" error. If you
failed to open a file, you may never be able to "fix" the error so that
the file can be opened, but you may be (and should be, in many cases)
able to "recover from" the failure and let the rest of the world continue.
Now I have to ask you, how does your program recover from an
unrecoverable error? The answer is that it doesn't. If the program can
(and must) recover from the "error", it isn't really an error, it's part
of the normal flow of the program.
You seem to have a very narrow understanding of what can/should be done
in exception handlers. You almost seem to argue (or you may actually be
arguing), "Writing exception handlers means the exceptions are expected,
but exceptions are only for 'unexpected' cases, and thus you should try
not to write exception handlers at all."
That's not what I'm arguing... If I had to distill it in one sentence, I
might say something like, "all thrown exceptions should cause the
program to shutdown/reset, possibly saving/cleaning up issues along the
way."
I agree that abusing exceptions is bad, but your notion of the abuse
looks much wider than mine and leaves very little outside.
There's always a little on the outside. Real life is messy and sometimes
that is reflected in software, but we shouldn't strive for making our
programs messy.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]