Google's Go & Exceptions
Justin Johansson
no at spam.com
Tue Jan 26 13:53:41 PST 2010
dsimcha wrote:
> == Quote from Justin Johansson (no at spam.com)'s article
>> 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
>
> Nice.
Thanks.
> This is probably a good idea in situations where it **always** makes sense
> for the immediate caller to handle the error.
Yes, like any tool you would use it when it is appropriate for the task
at hand.
AAMOF, I use it as a static function in a class wrapping the constructor
to prevalidate arguments passed to the constructor.
Now
(1) For some reason (possibly valid only in an historic context), I have
this great aversion to throwing exceptions from inside C++ constructors.
From memory, I once threw an exception from inside a constructor
with an early C++ compiler and wound up with stack corruption or
something like that, and consequently I developed the practice of
forever more avoiding throwing from inside a C++ constructor.
(2) Also, and this might be urban myth, I'm of the belief that a try
block does not come for free at runtime even if an exception is not
thrown (i.e. there's a cost to establishing the try block itself),
that for performance critical code the old fashion return and check
error code idiom is faster.
I wonder if our resident C++ compiler writer can shine any truth on (1).
With (2), can people either confirm (A) that it is true that try{}
is not completely and absolutely free, or (B) that (2) is urban myth.
> Only problem is that Go! doesn't have asserts either.
I'm sure there must be a spoken language somewhere in the universe
in which the word "Go" translates to "joke" in English. I tried it
for a few days when it was first announced and no matter how much I
tried to give Go a "fair go", as we say in Australia, the experience
felt like going back 30 years in terms of it's language maturity.
Cheers
Justin Johansson
More information about the Digitalmars-d
mailing list