Re: Necessity of multi-level error propogation
On Mar 15, 2:42 pm, Jeff Schwab <j...@schwabcenter.com> wrote:
James Kanze wrote:
Jeff Schwab <j...@schwabcenter.com> wrote:
James Kanze wrote:
Jeff Schwab <j...@schwabcenter.com> wrote:
It would be my preference to wrap strtol in a function that
throws exceptions on error, to avoid the need for little
if-statements everywhere it is called.
I don't know. I think in this case, a lot of the time, you
could (and probably would want to) handle the error
immediately in the calling code.
Then the caller can use a try/catch block. That isn't much
more syntax than an if-statement,
Oh yes it is, since it implies creating a scope for the call
(and not just for the error handling).
Not so; the call already has its own scope. If you find
yourself with a try/catch in the middle of a function body,
it's probably time to refactor.
Usually, but not always.
Which in turn may mean either moving the error handling down
further in the function, or declaring the variable before
initializing it.
Neither of those is implied, either. Remember, we're
replacing an explicit clear of errno before the function call,
and a check afterward. The non-exception code would have to
look something like this:
long parse(std::string s, long default_, int base) {
typedef char** end_pointer;
errno = 0;
long const value = strtol(s.data(), end_pointer( ), base);
if (errno) {
// log the error, or do other special-case handling...
return default_;
}
return value;
}
Yuck. If my::strtol instead throws an exception, we can write:
long parse(std::string s, int base, long default_) try {
typedef char** end_pointer;
return my::strtol(s.data(), end_pointer( ), base);} catch (std::exce=
ption const&) {
// log the error, or do other special-case handling...
return default_;
}
I'm not sure I like that better. If strtol returned a Fallible,
I could simply write:
long pars( std::string s, int base, long default_ )
{
return strtol( s, base ).elseDefaultTo( default_ ) ;
}
(except that I probably wouldn't bother).
[...]
it allows the compiler to favor the case in which an error
does not happen,
It can do this in any case.
It could, if it knew which case to favor.
That's an easy one. It favors which ever path the profiling
data tells it to favor. (Of course, if you generate your
profiling data with a test set which has more error cases than
normal cases...)
GCC has extensions to let you specify which case should be
favored, but I'm not aware of anything in standard C++ that
serves the same purpose.
Most compilers have options to exploit profiling data when
optimizing.
and it keeps the error-handling code separate from the main
logic.
Which isn't necessarily an advantage, for errors which have to
be handled immediately.
I disagree. If it belongs in the main logic, then by
definition, it's part of that logic, and we're no longer
discussing error-handling. If it's semantically separate from
normal operation, then it ought to be lexically separate, as
well.
OK. So we're really arguing about whether incorrect input
should be called an "error", or whether it should receive some
other name. Handling incorrect input is certainly part of the
"normal operation" of my programs.
[...]
So an exception really isn't appropriate. In a new design,
I'd probably use Fallible.
To me, that means: "This isn't really an error. It's
something I expect to happen in the course of normal
operation,
That's also true. Although that's not really my argument. But
I don't think you can consider any format error in input
"exceptional". Just the opposite, you're almost certain to see
it from time to time.
Who said anything about "any format error in input?" Anyway,
as long as we're calling it an error, I still think it ought
to have a corresponding exception.
It sounds to me like there's some circular logic involved there.
You're saying that the reason it should use an exception is
because we call it an error, and the reason we call it an error
is because it should use an exception. If calling it an error
implies using an exception, then you've just changed the
definition of error that I was using, and I'd have to argue that
it isn't an error.
Despite some of the older wisdom, I'm not convinced that
"exceptions" should only be for really exceptional situations.
IMO, they're best reserved for errors, and used consistently.
and I want to be able to check for it at my leisure."
That's not Fallible;
Really? So what was that elseDefaultTo method you just showed?
A member function of Fallible. But I don't see any relationship
to "check for it at my leisure", since elseDefaultTo checks
immediately. (It provides one type of simple error handling,
appropriate in a few situations.)
that's the idiom used by std::istream
By default.
Yes.
It's also useful---in the case of output (std::ostream) and
floating point, it's probably the preferred idiom.
"The" preferred idiom. Wow.
Based on the code I've seen.
(Typically, I'll output an entire file, and only check
the status and generate an error return after close.)
Once the first error occurs, are subsquent operations
guaranteed not to clear it, or to otherwise do any harm?
Yes. That's an essential part of the idiom. Anytime a stream
is in failed state (failbit or badbit set), all operations on it
(except things like clear, of course) are guaranteed to be
no-ops.
[...]
Fair enough. The disagreement may be more terminological than
technical.
I'm beginning to suspect that too, at least partially. (I do
suspect that you'd choose exceptions in some cases I'd choose
return codes. But those cases would probably be judgement
calls.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34