Google's Go & Exceptions

Justin Johansson no at spam.com
Tue Jan 26 07:41:14 PST 2010


dsimcha wrote:
> 
> Multiple return values are a horrible substitute for exceptions, because they
> require the programmer to explicitly check the return value.  (When's the last
> time you checked the return value of printf, or even malloc?)  IMHO the best thing
> about exceptions is that they provide a sane default for error handling:  If you
> don't handle them then you've effectively asserted that they can't happen in your
> situation.  If this "assertion" fails, then our program fails fast and with an
> error message that massively narrows down where the problem is.  I flat-out refuse
> to program in a language where the default is for errors to be ignored and I have
> to constantly write explicit error-checking boilerplate even if I don't care about
> handling the error.

Well, back in C++ land, as an occasional alternative to using 
exceptions, I use a templated "checked_value" structure for returning an 
error code / function result pair.

The C++ templated structure is shown below.  A function returning
a "checked_value" uses the first constructor form to return a
valid result and the second form to return an erroneous result
(using an enum to designate the error condition).

If client code tries to access the value (via the
overloaded cast operator, or you could have a getter
function for the value instead), and an error is in effect
that you didn't check for, then shit (an assert or other
severity) happens.

I'm sure there will be lots of religious comments about
this idiom, but it works well for me by forcing a
check for an error result before otherwise using the
return value.  Of course, this idiom only works if the
function in question "returns something", a value, that
the client code would by necessity have to use. It wouldn't
(and couldn't) work if ValueType is "void".
In the exceptional case (pun intended) of functions returning
void, one may have to resort to throwing an exception instead
to signal an error.

So to counter the dsimcha's point, my solution does
not assume a default situation of ignoring errors. The thrust
of my argument is that exceptions are not an all-or-nothing
approach in sane dealing in errors.


template <typename ValueType>
struct checked_value
{
public:
     checked_value( ValueType value)
     :   _value( value),
         _rcode( RC_OK)
     {}

     checked_value( resultCode_t rcode)
     :   _value( ValueType::PROP_INIT),
         _rcode( rcode)
     {}

     operator ValueType() const
     {
	// The value should not be accessible if the function failed.
	// Choose your poison with either assert or something
	// more severe in release compile if you don't like asserts
	// being preprocessed out.
         assert(!failed());
         return _value;
     }

     int failed() const
     {
         return (_rcode < RC_OK);
     }

     resultCode rcode() const
     {
         return _rcode;
     }

private:
     ValueType    const _value;
     ResultCode   const _rcode;

};


Cheers
Justin Johansson



More information about the Digitalmars-d mailing list