|
Boost : |
Subject: Re: [boost] [boost.ublas] [gsoc'15]
From: Mikael Persson (mikael.s.persson_at_[hidden])
Date: 2015-03-15 16:59:42
> Should we use exceptions or return codes ?
I agree with all that you've said on this. It's very true that one of the
nice benefits of exceptions is that they allow you to retain the nice
functional / expression syntax, that is, instead of having to do each
operation on its own line, grabbing the error-code and checking it.
For the purposes of operator overloads, I'm not really sure what kind of
error could come out of those except for mismatching dimensions. I think
that mismatching dimensions are the types of errors for which assert()
exists, or similarly, the current check macro. I think that if there are
certain multiplications that lead to NaN / INF values, I think that those
can just remain like that, as it matches the behaviour of scalar
operations. So, I think that the current error reporting strategy for the
matrix / vector operator overloads is perfectly acceptable (i.e., catch
mismatching dimensions with an assert(), leave the rest unchecked, as it is
with scalar operators).
I think that if people want to have checked operations (to prevent NaN /
INF, or overflow / underflow problems), then they can use a library similar
to Boost.Safe-Numerics for the value-types in the matrix-vector classes
from uBlas.
For the decomposition algorithms or solutions for inversion / eigen /
Riccati / etc., I agree that there's no point in trying to retain too much
of the "functional" style, as many of them are algorithms that have
multiple (and optional) outputs, and can often be done in-place. Generally,
that does mean that most outputs would be in the form of by-reference
parameters (either as pure output parameters, or as input-output for
in-place algorithms), which leaves the return-value free to be an
error-code of some kind. And this is why I see this as a viable solution.
However, after thinking about this more, I think that the best option might
be to use a strategy similar to Boost.Asio. The idea there is to provide
two overloads, one that takes an error-code by reference (which would be
set to an error code value if an error occurred), and one that does not
have the parameter (and throws an exception if an error occurs). The
exception-throwing version simply wraps a call to the error-code version,
and throws if the error-code is non-zero. And the beauty of that is that
this overload can be disabled when compiling without exceptions
(-fno-exceptions option) as per the BOOST_NO_EXCEPTIONS macro. This would
allow those who prefer exceptions (like me) to use exceptions by simply not
providing the error-code parameter. And anyone who disables exceptions is
forced to collect the error-code for each algorithm called, and thus, is
less likely to ignore those error conditions. It seems to me like it's
really the best of both worlds, and it seems to work very well for
Boost.Asio. The archetype for the implementation would be something like
this:
void some_algorithm(/* params */, system::error_code& err) {
// primary implementation of some-algorithm here..
if( error occurred ) {
err.assign(/* something */);
return;
};
};
#ifndef BOOST_NO_EXCEPTIONS
void some_algorithm(/* params */) {
system::error_code err;
some_algorithm(/* forward params */, err);
if(err)
throw something(err);
};
#endif
There are a few other ways to achieve something similar to this. Boost.Asio
does something slightly different (i.e., my version removes the
exception-throwing version completely, while Boost.Asio retains it, but
triggers an error later at link-time, which I don't really like). There are
a number of trade-offs involved here. And, of course, you might have
noticed that this does introduce the run-time overhead associated with
using error-codes even when using the exception-throwing version, that's a
bit annoying (as usually, using exceptions doesn't have this run-time
overhead that error-codes have), but I think it's an acceptable trade-off
here, as it's the only way to support disabling exceptions.
What say you?
Cheers,
Mikael.
-- Sven Mikael Persson, M.Sc.(Tech.) PhD Candidate and Vanier CGS Scholar, Department of Mechanical Engineering, McGill University,
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk