Sunday, September 12, 2010

Case for Objective-C++

Forget Objective-C. I mean it. For iOS development, the ideal language is Objective-C++.

I expect plenty of pitch-fork bearing purists who tend to align themselves with the crowd of goto is bad, and overloaded operators are bad to not like what I'm about to suggest. But; as with goto and overloaded operators, like certain medicines, too much can be fatal. I believe programmers can make reasonable decisions to the use of these constructs.

With Objective-C 2.0 came properties. These allowed for easy integration with key-value coding; but there's one problem with it - all properties are public. All methods are public as well. I believe this is bad programming style.

Here's a key to my solution; simple and elegant:
template<class T>
class Auto
{
private:
T m_o;
public:
inlineoperator=(T in_o)
{
if (in_o) [in_o retain];
if (m_o) [m_o release];
m_o = in_o;
return m_o;
}
inline T noRetain(T in_o)
{
if (m_o) [m_o release];
m_o = in_o;
return m_o;
}
inlineoperator()() const
{
return m_o;
}
inline Auto(T in_o = NULL)
: m_o(NULL)
{ (*this) = in_o; }
inline Auto(const TNS<T> &in_cpy)
: m_o(NULL)
{
(*this) = in_cpy();
}
inline ~Auto()
{
if (m_o) [m_o release];
}
};

Consider how this code nicely takes an an Objective-C object and wraps it in a smart-pointer.  Ensuring that objects get retained and released becomes much more trivial - and a lot less typing.  No need to define a parameter, synthesize, and double-check that it exists in the dealloc.  Why?  Objective-C++ automagically calls the destructor for C++ objects.

Using this is quite simple: Auto<NSString*> m_something; creates your string.  Assign an auto-release string to it (or use the noRetain method) and off you go forgetting about this object.  Assign a new string?  The old one gets automatically released.  Need to call a method?  [m_something() UTF8String]; is a good example.

The good thing?  minimal overhead - the compiler should inline out most, if not all, of the Auto object.  What you're left with are the retains and releases that you'd have normally put in.

A note of caution: only use this object in places where you'd normally ensure an object gets a retain or release.  Do not enthusiastically put it everywhere.  Recall: good things in great quantities might not be that good.  They can even be fatal!

On the up-side, if you want properties, you'll need to actually write the methods behind to translate from the C++ wrapper.  This is good, you'll see, since it makes it harder to make objects publicly accessible, always a good design decision.

Before I wrap up this post; for private methods, I suggest using C static functions in your implementation files.  Can't get more private than that!

For protected functions - useful with polymorphism - I'd avoid them.  Once a function is declared, it can easily be reflected and used.  No matter how hidden/private it is (unfortunately).  I believe that this poses interesting software design constraints though.

No comments:

Post a Comment