[snip]
Exercise left to the student. Suffice it to say that
real code does return an indication either via a return
value from a function or by setting state in the object
that can be subsequently interrogated.
Of course, not all such errors are fatal to the
application, or even of concern to the caller.
Point taken. I think that it is difficult to decide whether errors
should be propagated via return values or exceptions. Especially when
the code is put into some library, so that one doesn't know how the user
is going to use it.
Take the following example: You are writing a library that deals with
linear algebra. You'll certainly implement some matrix class which also
offers a function to compute the inverse of a matrix. How should this
function look like? There are two possible solutions:
class Matrix
{
public:
// Version that throws exceptions:
class MatrixIsSingularException;
class MatrixIsNonQuatraticException;
Matrix getInverted () throw (MatrixIsSingularException,
MatrixIsNonQuatraticException);
// or using error code
enum MatrixInversionErrorCode
{
MatrixIsSingular,
MatrixIsNonQuadratic,
InversionSucceeded
};
MatrixInversionErrorCode getInverted (Matrix& target) throw ();
Matrix getInverted (MatrixInversionErrorCode& target) throw ();
};
Now if somebody wants to use this code, he can either use the version
with exceptions or the version with error codes:
double foo (const Matrix& r, const Vector& v)
{
// r should be a rotation matrix, so there is no
// need to check for error codes (if r should
// be no rotation matrix, there is nothing sensible
// we can do here with the error code anyway).
return (r.getInverse () * v).getAngle ();
}
whereas the following code is faster with the error code version:
int main ()
{
std::cout << "Please enter a 3x3 matrix: ";
Matrix m;
std::cin >> m; // Error handling omitted.
// Now m is quite likely to be singular, so we better check for
// error codes (the version with exceptions would produce slower
// code).
MatrixInversionErrorCode e;
Matrix inverted = m.getInverted (e);
if (e == MatrixIsSingular)
{
std::cout << "Entered matrix is singular";
return 0;
}
std::cout << inverted;
}
Now everyone can decide whether to use the version with exceptions or
the version with error objects.
Of course, having to prove both versions of such functions is a PITA.
When I had to do some Microsoft COM programming, I wrote my own code
generator which provided exception aware versions for my COM objects
(automation compatible COM objects have to use error codes).
Regards,
Stuart