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