Statically Typed

because Hindley-Milner rocks

Pragmatic Programmer: Immutable C++ Script, take 3


When I wrote my script I had been dealing with objects and not pointers.  Now that I’ve taken a closer look at it I see that it has one large, glaring flaw.  If I were to pass in a pointer, the Accessors would return a pointer to a private variable.  That breaks encapsulation completely and destroys all guarantees of immutability.  I can’t let that happen.  Onward to the next iteration!

To solve the issue of pointers I’ll turn to good ol’ and trusty Boost.  I’ll need to pass out a Boost::weak_ptr with const condition so that I have access to it, don’t maintain it if the scripted object goes out of scope, and can’t modify it.  Adding the following four (three) functions to my script to handle pointers saves the day:

weak_ptr = lambda x: "weak_ptr<const " + x.strip("*") + ">"
type_return = lambda x: weak_ptr(x) if x.find("*") > 0 else x
type_convert = lambda x,y: weak_ptr(x) + "( m_" + y + ".get() )" if x.find("*") > 0 else "m_" + y
type_store = lambda x: weak_ptr(x) if x.find("*") > 0 else "const " + x

Secondly, I’ve also skirted the issue of the copy constructor.  If I add in an auto-generated copy constructor, what do I do with the pointers?  Should I share them with a Boost::shared_ptr or make it a deep copy by supplying a new object to an std::auto_ptr?  I want reference counting which removes Boost::weak_ptr from consideration.  Obviously I can’t make the assumption that an object implements a copy constructor nor could I even consider std::auto_ptr if I’m going to return a const pointer through my functions.

How about thinking of thread safety when looking at that copy constructor?  Normally we’d use C++’s preference for RAII but if the object can’t change and won’t be changed then we’re fine until you look at the implementation of Boost::shared_ptr.  Boost::shared_ptr is not thread safe in the manner I’d use it here.  It silently increments the reference count, that is it performs a read-update-write statement.  Those 3 actions need to be guarded by a lock or else I run the risk of missing a reference count increment.  This fact removes any thought of a copy constructor being auto-created.

Thirdly I haven’t even though about cyclic dependence.  My argument is that I don’t need to even think about it as this script shouldn’t need to read my mind.  If I want to screw something up like this in the future I’ll have no one to blame but me.  That’s the way I like it, blame on me.  Then again, I should really fight all the blame that does get dumped onto me (slash my schedule in half?  Leave no time for testing?  Expect no bugs? Ha ha ha…)

def CreateImmutable( _className, _typePairs ):
    weak_ptr = lambda x: "weak_ptr<const " + x.strip("*") + ">"
    type_return = lambda x: weak_ptr(x) if x.find("*") > 0 else x
    type_convert = lambda x,y: weak_ptr(x) + "( m_" + y + ".get() )" if x.find("*") > 0 else "m_" + y
    type_store = lambda x: weak_ptr(x) if x.find("*") > 0 else "const " + x
    print "class " + _className.capitalize()
    print "{"
    print "public:"
    print "\t" + _className.capitalize() + "(" + reduce( lambda x,y: x + ", " + y, (value + " " + key for key, value in _typePairs.iteritems() ) ) + ") :"
    print reduce( lambda x,y: x + ",\n" + y, ("\t\tm_" + key + "(_" + key + ")" for key in _typePairs.keys() ) ) + "{}"
    print reduce( lambda x,y: x + "\n" + y, ("\t" + type_return(value) + "\tGet" + key + "() const { return " + type_convert(value,key) + "; }" for key, value in _typePairs.iteritems() ) )
    print "protected:"
    print "private:"
    print reduce( lambda x,y: x + "\n" + y, ("\t" + type_store(value) + "\tm_" + key + ";" for key, value in _typePairs.iteritems() ) )
    print "};"

My script is up to 15 lines of code (which is a horrible measure to judge quality except in extenuating circumstances) but handles both pointers and objects.  Some of you might point out that it can’t handle pointers of pointers or some of the very objects it utilizes, Boost::shared_ptr and Boost::weak_ptr.  Let me first say that I’m a big proponent of RAII when writing C++ so I won’t be passing in the Boost types.  As to the pointers of pointers, that’s a whole new dimension of pain which I’m not going to tackle.  I’d need to know if the pointer was an array or if it were a pointer to an object.  I don’t expect it to read my mind so I’m not going to add in this logic.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Information

This entry was posted on February 17, 2010 by in Pragmatic Programmer.
%d bloggers like this: