Google's Go & Exceptions

Justin Johansson no at spam.com
Tue Jan 26 16:57:13 PST 2010


Ary Borenszweig wrote:
> Walter Bright wrote:
>> Justin Johansson wrote:
>>> (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.
>>
>> I'm a believer in the methodology that a constructor should be 
>> "trivial" in that it cannot fail (i.e. cannot throw). I'm probably in 
>> the minority with that view, but you shouldn't feel like you're doing 
>> the wrong thing when you stick to such a style.
> 
> auto x = new BigInt(someString);
> 
> How do you implement BigInt's constructor without being able to throw an 
> exception? Or would you do it like:
> 
> auto x = BigInt.fromString(someString);
> 
> to be able to throw? (just to obey the "no throw in constructors"... but 
> that's not as trivial as the previous form)

A factory method is the way to go.  Different languages give you
different means for achieving this design pattern but nevertheless
all such means make for the better factoring of code.

In C++ there are three means :-

(1) Use of static class member, so your example would like like this:

BigInt x = BitInt::fromString( someString);

(2) Use of () function call operator overload on a factory class
so your example would now look like this

BigIntFactory bigIntFactory;	// may be statically declared
BigInt x = bigIntFactory( someString);

(3) Global function, which I won't discuss any futher for obvious reasons.

In D, similar to C++, though function call () operator overload is 
effected in much cleaner fashion with D's absolutely wonderful
static opCall.  So your example would look something like this
(as said earlier I haven't done D for 6 months so pls forgive
any error in detail) :

class BigInt
{
   static BigInt opCall( someString)
   {
      if (!validate( someString))
         throw someError;

      // extract data for BitInt instance somehow
      // from string .. maybe tied into validate function

      byte[] bigIntData = ...

     return new BigInt( bigIntData);
   }

   this( byte[] bigIntData)
   {
     this.bigIntData = bigIntData;
   }

   private: byte[] bigIntData;

   // other BigInt methods ...

}

Now in D,

BigInt x = BigInt( someString);



In Java, well, let's not discuss that here. :-)

In Scala you have "companion classes" that go hand-in-hand with
the regular class.  Scala uses companion classes to reduce the
noise that the static class members introduce in other languages.

(Example anybody?)


Summary for D:

It really isn't that much work to use D's static opCall() to
good effect and, IMHO, complex designs do end up a lot cleaner.
As they say, necessity is the mother of invention.  It seems to
me that both Scala and D have been driven by necessity in the
design of companion classes and static opCall respectively.

Cheers
Justin Johansson



More information about the Digitalmars-d mailing list