Referrals
FreeAgent Small Business Online Accounting
I can honestly recommend Freeagent for painless small business bookkeeping. I can also honestly say that I get a referral bonus every time someone signs up using this link

Entries in Objective-C (4)

Friday
May272011

Unit Testing in C++ and Objective-C just got ridiculously easier still

Spider web in morning sun

'Spider Web in Morning Sun' by Rob van Hilten

In my previous post I introduced Catch - my unit testing framework for C++ and Objective-C.

The response was overwhelming. Thanks to all who commented, offered support - and even contributed to the code with fixes and features.

It certainly gave me the motivation to continue active development and a lot has changed since that post. I'm going to cover some highlights, but first I want to focus on what has been one of the most distinguishing features of Catch that has attracted so much attention - and how I have not rested but made that even better!

How easy is easy enough?

Back in April I gave a five minute lightning talk on Catch at the ACCU conference in Oxford (I highly recommend the conference). With just five minutes to talk about what makes Catch special what was I going to cover? The natural operator-based comparison syntax? The use of Sections instead of class-based fixtures? Data generators?

Well I did touch on the first point. But I decided to use the short amount of time to drive home just how quickly and easily you can get up and running with Catch. So after a 30 second intro I went to the GitHub page for Catch (now aliased as catch-test.net), downloaded the zip of the source (over a 3G connection), unzipped and copied to a central location, fired up XCode, started a fresh C++ project, added the path to Catch's headers, #include'd "catch_with_main.hpp", wrote an anonymous test case, compiled and ran it, demonstrated how it caught a bug, fixed the bug and finally recompiled and re-ran to see the bug go away.

Phew! Not bad for five minutes, I thought. And from the feedback I got afterwards it really did drive the point home.

Compare that with my first experience of using Google Test. It took me over an hour to get it downloaded and building in XCode (the XCode projects don't seem to have been maintained recently - so perhaps that is a little unfair). There are other frameworks that I've tried where I have just run out of patience and never got them going.

Of course I'm biased. But I have had several people tell me that they tried Catch and found it to be the easiest C++ Unit Test framework they have used.

But still I wasn't completely satisfied with the initial experience and ease of incorporating Catch into your own projects.

In particular, if you maintain your own open source project and want to bundle it with a set of unit tests (and why wouldn't you?) then it starts to get fiddly. Do you list Catch as an external dependency that the user must install on their own? (no matter how easy they are to install external dependencies are one or my least favourite things). Do you include all the source to Catch directly in your project tree? That can get awkward to maintain and makes it look like your project is much bigger than it is. If you host your project on GitHub too (or some other Git based repository) you could include Catch as a submodule. That's still not ideal, has some of the problems of the first two options, and is not possible for everyone.

There can be only one

Since Catch, as a library, is fully header-only I decided provided a single header version that is ideal for direction inclusion in third-party projects.

How did I do this?

Go on guess.

Did you guess that I wrote a simple Python script to partially preprocess the headers so that the #includes within the library are expanded out (just once, of course), leaving the rest untouched?

If you did you're not far off. Fortunately some of the conventions I have used within the source meant I could drastically simplify the script. It doesn't need to be a full C preprocessor. It only needs to understand #include and #ifndef/#endif for include guards. Even those are simplified. The whole script is just 42 lines of code. 42 always seems to be the answer.

The result is https://github.com/philsquared/Catch/blob/master/single_include/catch.hpp

I see no reason why this should not be the default way to use Catch - unless you are developing Catch itself. So I'm now providing this file as a separate download from within GitHub. Think of it as the "compiled" header. The lib file of the header-only world.

Licence To Catch

But Open Source is a quagmire of licensing issues, isn't it?

Well it certainly can be. Those familiar with GPL and similar open source licences may be very wary of embedding one open source library (Catch) within another (their own).

IANAL but my understanding is that, contrary to what might seem intuitive, source code with no license at all can be more dangerous, legally speaking, than if it does have one (and if you thought that sentence was difficult to parse you should try reading a software license).

So Catch is licensed. I've used the Boost license. For a number of reasons:

  • It is very permissive. In particular it is not viral. It explicitly allows the case of including the source of Catch along with the distribution of your own source code with no requirements on your own code
  • It's been around for a while now - long enough, I think, that most people are comfortable with it. I work with banks, who can be very nervous about software licensing issues - especially open source. But every one I have worked at has already got Boost through it's compliance process. I'm hoping that will ease any barriers to adoption.
  • I'm familiar with Boost, know many of it's contributors personally, and generally trust the spirit of the licence. Boost itself is a very well known and highly respected set of libraries - with very widespread adoption. A large part of Boost is in header-only libraries and people are already comfortable including them in their own projects.

So what's the Catch? The catch is that I retain the right to keep using that joke - well beyond it's humorous lifetime.

The important bit:

In short: any open source author who wants to use Catch to write unit tests for their own projects should feel very free to do so and to include the single-header (or full) version of the library in their own repository and along with their distribution.

That fully applies to commercial projects too, of course.

What else?

Here's a quick run down of some of the other changes and features that have gone in:
  • Single evaluation of test expressions. The original implementation evaluated the expression being tested twice - once to get the result, and then again to get the component values. There were some obstacles to getting this to work whilst only evaluating the expression once. But we got there in the end. This is critical if you want to write test expressions that have side-effects.
  • Anonymous test cases. A little thing, but I find them really handy when starting a new project or component and I'm just exploring the space. The idea is that you don't need to think of a name and description for your test - you can just dive straight in and write code. If you end up with something more like a test case it's trivial to go back and name it.
  • Generators. These are in but not fully tested yet. Consider them experimental - but they are very cool and very powerful.
  • Custom exception handlers. (C++) Supply handlers for your own exception types - even those that don't derive from std::exception, so you can report as much detail as you like when an exception is caught within Catch. I'm especially pleased this went in - given the name of the library!
  • Low build time overhead. I've been aggressive at keeping the compile-time footprint to a minimum. This is one of the concerns when using header only libraries - especially those with a lot of C++ templates. Catch uses a fair bit of templates, but nothing too deeply recursive. I've also organised the code so that as much as the implementation as possible is included in only one translation unit (the one with main() or the test runner). I think you'll be pushed to notice any build-time overhead due to Catch.
  • Many fixes, refactorings and minor improvements. What project doesn't have them? This is where a lot of the effort - possibly the majority - has gone, though. I've wanted to keep the code clean, well factored, and the overhead low. I've also wanted it to be possible to compile at high warning levels without any noise from Catch. This has been challenging at times - especially after the Single Evaluation work. If you see any Catch-related warnings please let me know.

Are we there yet?

As well as my own projects I've been using Catch on a large scale project for a bank. I believe it is already more than just a viable alternative to other frameworks.

Of course it will continue to be refined. There are still bugs being found and fixed.

But there are also more features to be added! I need to finish the work on generators. I'd like to add the tagging system I've mentioned before. I need to look at Matchers. Whether Catch provides its own, or whether I just provide the hooks for a third-party library to be integrated, I think Matchers are an important aspect to unit testing.

I also have a stub project for an iPhone test runner - for testing code on an iOS device. Several people have expressed an interest in this so that is also on my list.

And, yes, I will fill out the documentation!

Tuesday
Dec282010

Unit Testing in C++ and Objective-C just got easier

Day 133-365 : Catching the bokeh.jpg

Back in May I hinted that I was working on a unit testing framework for C++. Since then I've incorporated the technique that Kevlin Henney proposed and a whole lot more. I think it's about time I introduced it to the world:

Introducing CATCH

CATCH is a brand new unit testing framework for C, C++ and Objective-C. It stands for 'C++ Adaptive Test Cases in Headers', although that shouldn't downplay the Objective-C bindings. In fact my initial motivation for starting it was dissatisfaction with OCUnit.

Why do we need another Unit Testing framework for C++ or Objective-C?

There are plenty of unit test frameworks for C++. Not so many for Objective-C - which primarily has OCUnit (although you could also coerce a C or C++ framework to do the job).

They all have their strengths and weaknesses. But most suffer from one or more of the following problems:

  • Most take their cues from JUnit, which is unfortunate as JUnit is very much a product of Java. The idiom-mismatch in C++ is, I believe, one of the reasons for the slow uptake of unit testing and TDD in C++.
  • Most require you to build libraries. This can be a turn off to anyone who wants to get up and running quickly - especially if you just want to try something out. This is especially true of exploratory TDD coding.
  • There is typically a certain amount of ceremony or boilerplate involved. Ironically the frameworks that try to be faithful to C++ idioms are often the worst culprits. Eschewing macros for the sake of purity is a great and noble goal - in application development. For a DSL for testing application code, especially since preprocessor information (e.g. file and line number) are required anyway) the extra verbosity seems too high a price to pay to me.
  • Some pull in external dependencies
  • Some involve a code generation step

The list goes on, but these are the criteria that really had me disappointed in what was out there, and I'm not the only one. But can these be overcome? Can we do even better if we start again without being shackled to the ghost of JUnit?

What's the CATCH?

You may well ask!

Well, to start, here's my three step process for getting up and running with CATCH:

  1. Download the headers from github into subfolder of your project
  2. #include "catch.hpp"
  3. There is no step 3!

Ok, you might need to actually write some tests as well. Let's have a look at how you might do that:

[Update: Since my original post I have made some small, interface breaking, changes - for example the name of the header included below. I have updated this post to reflect these changes - in case you were wondering]

#include "catch_with_main.hpp"

TEST_CASE( "stupid/1=2", "Prove that one equals 2" )
{
    int one = 2;
    REQUIRE( one == 2 );
}

Short and to the point, but this snippet already shows a lot of what's different about CATCH:

  • The assertion macro is REQUIRE( expression ), rather than the, now traditional, REQUIRE_EQUALS( lhs, rhs ), or similar. Don't worry - lhs and rhs are captured anyway - more on this later.
  • The test case is in the form of a free function. We could have made it a method, but we don't need to
  • We didn't name the function. We named the test case. This frees us from couching our names in legal C++ identifiers. We also provide a longer form description that serves as an active comment
  • Note, too, that the name is hierarchical (as would be more obvious with more test cases). The convention is, as you might expect, "root/branch1/branch2/.../leaf". This allows us to easily group test cases without having to explicitly create suites (although this can be done too).
  • There is no test context being passed in here (although it could have been hidden by the macro - it's not). This means that you can freely call helper functions that, themselves, contain REQUIRE() assertions, with no additional overhead. Even better - you can call into application code that calls back into test code. This is perfect for mocks and fakes.
  • We have not had to explicity register our test function anywhere. And by default, if no tests are specified on the command line, all (automatically registered) test cases are executed.
  • We even have a main() defined for us by virtue of #including "catch_with_main.hpp". If we just #include that in one dedicated cpp file we would #include "catch.hpp' in our test case files instead. We could also write our own main that drives things differently.

That's a lot of interesting stuff packed into just a few lines of test code. It's also got more wordy than I wanted. Let's take a bit more of a tour by example.

Information is power

Here's another contrived example:

TEST_CASE( "example/less than 7", "The number is less than 7" )
{
    int notThisOne = 7;

    for( int i=0; i < 7; ++i )
    {
        REQUIRE( notThisOne > i+1  );
    }
}

In this case the bug is in the test code - but that's just to make it self contained. Clearly the requirement will be broken for the last iteration of i. What information do we get when this test fails?

    notThisOne > i+1 failed for: 7 > 7

(We also get the file and line number, but they have been elided here for brevity). Note we get the original expression and the values of the lhs and rhs as they were at the point of failure. That's not bad, considering we wrote it as a complete expression. This is achieved through the magic of expression templates, which we won't go into the details of here (but feel free to look at the source - it's probably simpler than you think).

Most of the time this level of information is exactly what you need. However, to keep the use of expression templates to a minimum we only decompose the lhs and rhs. We don't decompose the value of i in this expression, for example. There may also be other relevant values that are not captured as part of the test expression.

In these cases it can be useful to log additional information. But then you only want to see that information in the event of a test failure. For this purpose we have the INFO() macro. Let's see how that would improve things:

TEST_CASE( "example/less than 7", "The number is less than 7" )
{
    int notThisOne = 7;

    for( int i=0; i < 7; ++i )
    {
        INFO( "i=" << i );
        REQUIRE( notThisOne > i+1  );
    }
}

This gives us:

    info: 'i=6'
    notThisOne > i+1 failed for: 7 > 7

But if we fix the test, say by making the for loop go to i < 6, we now see no output for this test case (although we can, optionally, see the output of successful tests too).

A SECTION on specifications

There are different approaches to unit testing that influence the way the tests are written. Each approach requires a subtle shift in features, terminology and emphasis. One approach is often associated with Behaviour Driven Development (BDD). This aims to present test code in a language neutral form - encouraging a style that reads more like a specification for the code under test.

While CATCH is not a dedicated BDD framework it offers a several features that make it attractive from a BDD perspective:

  • The hiding of function and method names, writing test names and descriptions in natural language
  • The automatic test registration and default main implementation eliminate boilerplate code that would otherwise be noise
  • Test data generators can be written in a language neutral way (not fully implemented at time of writing)
  • Test cases can be divided and subdivided into SECTIONs, which also take natural language names and descriptions.

We'll look at the test data generators another time. For now we'll look at the SECTION macro.

Here's an example (from the unit tests for CATCH itself):

TEST_CASE( "succeeding/Misc/Sections/nested", "nested SECTION tests" )
{
    int a = 1;
    int b = 2;
    
    SECTION( "s1", "doesn't equal" )
    {
        REQUIRE( a != b );
        REQUIRE( b != a );

        SECTION( "s2", "not equal" )
        {
            REQUIRE_FALSE( a == b);
        }
    }
}

Again, this is not a great example and it doesn't really show the BDD aspects. The important point here is that you can divide your test case up in a way that mirrors how you might divide a specification document up into sections with different headings. From a BDD point of view your SECTION descriptions would probably be your "should" statements.

There is more planned in this area. For example I'm considering offering a GIVEN() macro for defining instances of test data, which can then be logged.

In Kevlin Henney's LHR framework, mentioned in the opening link, he used SPECIFICATION where I have used TEST_CASE, and PROPOSITION for my top level SECTIONs. His equivalent of my nested SECTIONs are (or were) called DIVIDERs. All of the CATCH macro names are actually aliases for internal names and are defined in one file (catch.hpp). If it aids utility for BDD or other purposes, the names can be aliased differently simply by creating a new mapping file and using that.

CATCH up

There is much more to cover but I wanted to keep this short. I'll follow up with more. For now here's a (yet another) list of some of the key features I haven't already covered:

  • Entirely in headers
  • No external dependencies
  • Even test fixture classes and methods are self registering
  • Full Objective-C bindings
  • Failures (optionally) break into the interactive debugger, if available
  • Floating point tolerances supported in an easy to use way
  • Several reporter classes included - including a JUnit compatible xml reporter. More can be supplied

Are there any features that you feel are missing from other frameworks that you'd like to see in CATCH? Let me know - it's not too late. There are some limiting design goals - but within those there are lots of possibilities!

Friday
Aug132010

OCPtr - a Smart Pointer for Objective C

In my last post I covered why we might want Garbage Collection on the iPhone, some reasons why we don't have it, and how the same problem is solved in C++. I then hinted that we might be able to bring the same C++ goodness to Objective-C - if we allow ourselves to use Objective-C++.

In this post I'm going to introduce my own solution.

Say hello to OCPtr

Rather than dive into the implementation, let's look at usage - and how it addresses our memory management needs. Let's start with our first example - allocating an NSString. Here's how it looks using OCPtr:

OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

// ...

The first thing to notice here is that instead of declaring our type as NSString* we declare it as OCPtr<NSString>. This is how smart pointers work. C++'s power is with types - especially when mixed with templates. OCPtr<NSString> is a complete type. Furthermore it is a value type. At the end of the scope it will be destroyed. In its destructor we call release on its NSString* member - which brings us to the second thing to notice - we have omitted the [str release] step!

Let's think about that for a moment. On the face of it we have saved ourselves 14 characters - but at the cost of six characters in the declaration - a net saving of eight characters. Woohoo! Obviously if this was all there was to it I wouldn't be writing this blog post. I'm not that obsessed with removing redundancy!

What is more significant is the reduction in the mental overhead of tracking when you need to call release - and the debugging overhead when it goes wrong - not to mention the potential for financial overhead if it only goes wrong when your users are using it.

In this simple example it doesn't seem to have given us much - but think about this again next time you're trying to track down a particularly elusive leak or over-release.

Of course real code is more complex than this, and OCPtr will need to be more than this to function as a stand-in for raw pointers. Years of C++ smart pointer experience tells us we need to overload the assignment operator, provide copy constructors (allowing us to create one OCPtr from another), and ideally overload a few other operators too. Technically a true smart pointer would overload the -> and & operators to behave like raw pointers - but these are not used with Objective-C types, so I haven't provided them. Other than that OCPtr provides all of this, so simple assignments result in retain counts being updated appropriately, and objects are released as their OCPtr wrappers leave the scope.

Some smart pointers also overload the conversion operator (this is invoked when you try to cast an object - whether explicitly or implicitly) to convert to the underlying raw point. This is a controversial practice, and can lead to ambiguities. However in the constrained environment of Objective-C code it seems safe enough - and gives us one key advantage: it allows us to send messages to the underlying object without additional syntax. Here's some more code illustrating this as well as some of the other preceding points:

{
  OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

  OCPtr<NSString> str2;
  {
    OCPtr<NSString> str3 = str; // retain count == 2
    str2 = str3; // retain count == 3

  } // retain count == 2

  // ...

} // retain count == 0 - dealloc called

Not just Smart - it smells nice too

So what else can we do with OCPtr?

Well it wouldn't be so useful if it couldn't also manage instance variables. OCPtr does that too - as long as you have the project setting enabled for: "Call C++ Default Ctors/Dtors in Objective-C". This setting seems to be enabled by default now, but it's worth checking. Now if all your ivars are held as OCPtrs you don't even need to write a dealloc method. The compiler will effectively write it for you - and all your OCPtr destructors will be called - releasing all their managed objects.

What about properties?

To some extent there is an overlap between the functionality of synthesised properties and what we are doing here. That is, if you declare a property for an Objective-C object with the 'retain' attribute then the synthesised code will include the retain-release code necessary to do the right thing. This does relieve the programmer of some work - so is OCPtr buying us anything?

Well, using properties still places two responsibilities on the caller: First they must remember to use the property syntax (whether the dot-syntax or the direct messaging passing) everywhere (including within the implementing class - except at the point of allocation). Secondly they must still remember to set the properties to nil in dealloc - which is really no improvement over just releasing them.

So retain properties do help with change of ownership - but at the cost of having two ways to do so - one which is automatic - the other still manual.

But can we declare properties for OCPtr ivars - and what happens with the retain counts?

Well recall that you can write a property for any Objective-C type - which includes all C types - primitives and structs. In the latter case you will use the assign attribute instead of retain (and assign is the default - so even easier). In this case no retain-release code will be generated - values will just be assigned directly. But OCPtr overloads assignment to provide retained change of ownership semantics. This gives us exactly what we want!

@property OCPtr<NSString> str;

So, in short, use assign properties to provide external access to OCPtr ivars. Internally you can use either form of access but they work the same way. In either case assignment works as it should and references will be cleaned up in dealloc. This is surely an improvement.

Transfer of ownership

How does OCPtr work with autoreleased objects? If you initialise an OCPtr with an autoreleased object you do still have to tell it to take ownership. This is no different to a raw Objective-C pointer. In both cases to take ownership you must call retain. E.g:

OCPtr<NSString> str = [[NSString stringWithFormat: @"One: %d", 1] retain];

It niggles me a bit that we still have to make a distinction between autoreleased and non-autoreleased objects - but that's a property of the autorelease mechanism itself, rather than a limitation of OCPtr (I could imagine a scheme where OCPtr detected that the pointer being passed was in the autorelease pool - but there would be no way to know for sure if that related to this assignment - and would probably be taking things to far anyway).

But take a step back for a moment. What is the problem that autorelease solves in the first place? autorelease's raison d'ĂȘtre is to provide transfer of ownership semantics. If a method creates an object but does not own it (typically a factory method) - it just returns it. In order to return it with a valid retain count, without requiring that the caller release it, it adds it to the autorelease pool to be released some time later. This works, but adds extra rules and syntax, and can result in objects living longer than they need to.

But smart pointers already solve this problem. By returning an OCPtr, the retain count will remain valid until after the assignment operator of the caller's OCPtr has retained it. The returned OCPtr then immediately goes out of scope (it is a temporary object). The net result is that you can freely create and return OCPtrs just as you can primitive types - no need to worry about retain counts or autorelease pools.

-(OCPtr<NSString>) someMethod
{
    OCPtr str = [[NSString alloc] initWithFormat: @"created here"];
    return str;

} // str will be released here but caller already has it

// ...

-(void) someOtherMethod
{
    OCPtr<NSString> str = [self someMethod];

} // str will be released here, retain will go to 0 and dealloc called

Of course if you're working with third-party APIs (including the SDK frameworks) you will still need to work with autoreleased objects at times, so it's worth remembering that you still need to retain them before putting them in an OCPtr.

But wait - there's more

What we have discussed so far covers our memory management needs. But if we've accepted a general purpose object wrapper into our code we have opportunity for further, aspect-oriented, benefits:

id type checking

One of the great things about Objective-C is that it is a dynamic language (albeit with static underpinnings).

One of the biggest problems with Objective-C is that it is a dynamic language (fortunately with static underpinnings).

While it is nice that we can choose to use typed, untyped (id) or partially typed (NSObject) objects, sometimes we are forced to go untyped when we'd like the benefit of type checking. The consequences of getting the types wrong are usually crashes, with not so helpful error messages - and at a different point in the code. We can check types at runtime, of course, with the isKindOfClass: method, to which you have to pass a class object - obtained by passing the class message. This can clutter the code up with mechanics.

OCPtr provides a conversion constructor from both id and NSObject, which will test the types (using the class and isKindOfClass: methods) before casting internally. As a result if we do this:

OCPtr<NSArray> str = [[NSString alloc] initWithFormat: @"hello"];

... we will get an exception that tells us exactly what happened.

If we had used a raw NSArray* pointer here the assignment would have worked - but we'd get errors further down the line if we tried to call array methods on it. These can be difficult to track down.

Don't want to pay for the check? Just cast to the target type before you assign (but lose the benefit of the type checking - so the principle is "correct by default, fast where necessary").

Release early

By eliminating your memory management bugs you will be able to release your apps earlier - but actually I was referring to releasing objects early.

Sometimes you're done with an object in the middle of a scope and you want to release it there and then. If you do this you are strongly advised to then set it to nil - to avoid the chance of anyone trying to use no longer valid memory. With an OCPtr you need only set it to nil and you get both advantages. You've been able to do this for a while with properties, but now you can do it directly with ivars, and even with local variables:

{
	OCPtr<NSString> str = [[NSString alloc] initWithFormat: @"One: %d", 1];

	// ...

	str = nil; // release is called here, and the underlying pointer set to nil

	// ...
}

Logging hooks

A powerful, but easily abused, feature of C++ templates is a concept known as specialisation (unfortunately a rather overloaded term in OO languages). A template is specialised when you write specific code for the case where a template's type argument(s) are of specific types. If that doesn't make things any clearer I'll explain how this relates to OCPtr and logging and hopefully it will click.

OCPtr comes with another template class: OCPtrHooks. OCPtrHooks declares a set of empty methods and nothing else. Each method represents a state change in OCPtr (e.g. onAssign) and OCPtr uses an OCPtrHooks class, parameterised with the same Objective-C type, calling the appropriate hook method as things happen. Because all the methods are empty the compiler is able to optimise these calls away completely.

So if the methods do nothing and they are not even compiled in what use is this? Well, due to the magic of template specialisation we can write a version of OCPtrHooks specialised for a particular type - or even partially specialised for a base type. Then, for those specialised types only, your custom versions will be called.

You can implement your specialisations to do anything - but a useful implementation for us is to log the events. Enabling logging for a particular type is as easy as declaring a specialisation that derives from a logging base class, like this:

template<> class OCPtrHooks<NSString> : public OCPtrLogHooks{};

Don't worry about trying to follow that if you're not a C++ programmer. The important bits are the template type parameter (NSString, here) and the base class (OCPtrLogHooks). Just substitute the NSString for any type you want to log and it will start working - with no overhead (not even an if) in all other cases.

While this is powerful, and useful, it does make use of, and expose, some tricky template syntax - If you're not already familiar enough with C++ to know how this works you may choose not to take advantage of this facility (I might try and make it friendlier in the future - even if that involves the use of a wrapper macro).

The dark side

So we've eliminated the mental overhead of manual retain counts, without introducing any runtime overhead, added transparent runtime type checking to dynamic types, along with several other benefits. With all this goodness everyone will want to use OCPtr, right? They'd be mad not to?

Well, that's generally true of C++ smart pointers in the C++ world. But because we're intruding the world of C++ into the world of Objective-C, and using a hybrid language to do so, there are some drawbacks to consider. These are the ones I think are relevant:

  1. OCPtr is a C++ template. This means it must be #included or #imported - so all your implementation files will need to be .mm files (or you can set the filetype in the file info dialog).
  2. C++ syntax intrudes into your application code in the form of the OCPtr<MyClass> syntax.
  3. The idea of custom value types may be unfamiliar to people reading the code. The fact that assignments handle retain counts for you may be a surprise, for example.
  4. If you use an OCPtr in an untyped context, e.g. as an argument to NSLog, the compiler cannot deduce that it needs to return the raw pointer out. So you'll need to explicitly access it - either calling a C++ method, such as get(), or casting to the underlying type.

Issues 1 & 2 are the most likely to put someone off - and they become especially significant if you are writing code for a client, or as part of a team in a larger company - especially if you are not already using any Objective-C++ on the project.

So I wouldn't necessarily recommend that everyone just start using OCPtr everywhere - but if you are just writing for yourself - or as a small, open-minded, team - I'd encourage you to at least give it a try and see if it can make your life easier.

But at the end of the day, even if you decide the trade-offs are not worth it for you, you can at least rest easy knowing that manual referencing counting is a choice. And you can tell all your gloating friends who use other languages, "I don't need no stinking garbage collection!"

Give me the codez

So where can you get OCPtr. I'll shortly be putting it up on GitHub. When I do so I'll update here with a link.

Friday
Aug132010

We Don't Need No Stinking Garbage Collection

iPhone developers are sometimes called names or excluded from polite circles for not having Garbage Collection. Recently I gave a presentation at the London iPhone Developers Group meeting which covered this matter from a few angles - including some techniques of my own. There was enough interest that I thought I should write it up in a more widely distributed format - where I could also expand on some points I glossed over due to time constraints (it was 20 minute slot).

Koviks avfallsdeponi.jpg

What's that Smell?

So what's the stink about? Well, if you develop for the iPhone you're going to have to use Objective-C (at least for some of your code - e.g. the UI). Until recently Objective-C has not had any form of Garbage Collection. Memory must be managed manually (although helped by a reference counting system). As of Objective-C 2.0 there is now a GC facility but this is only available on Mac OSX - from Snow Leopard on.

Most languages in common use today have Garbage Collection. There are three stand-out exceptions: Objective-C (on the iPhone), C and C++. As it happens this is precisely the same trio that are sanctified for use on the iPhone (I'm deliberately avoiding the issue of front-end languages/ platforms such as Monotouch - especially while their status with respect to the developer licence remains in doubt)!

So why no GC on the iPhone? Before we look at that I think it's worth a quick review of why anyone would think it was needed in the first place.

Remembering to forget your memory usage

Consider this typical snippet of Objective-C code:

NSString* str = [[NSString alloc] initWithFormat: @"One: %d", 1];

// ...

[str release];

The use of NSString here is not that interesting. What we're looking at is that, because we used alloc to get the string we need to remember to call release when we're done. Note that release doesn't necessarily deallocate the memory for the string there and then. The Objective-C runtime uses a reference counting (or retain counting, in Obj-C parlance) system to track when the last reference is released - at which point dealloc will be called - giving the object a chance to clean up its own resources.

This is hardly rocket science, and already has many advantages over the raw C way of doing things where ownership can be passed around like a hot potato and often it is difficult to know if you should be responsible for freeing or not (yes - conventions exist to mitigate this - but they are not standardised).

But when you start putting stretches of code in the middle, maybe with multiple exit points (unless you're a SESE fanatic - and eschew exceptions) it already starts to add mental overhead. Not much, maybe, especially to an experienced developer - but spread across thousands of instances it adds up. When you're writing code you want to focus as much as possible close to the domain level of abstraction - and these language mechanics issues can detract from that.

As well as the pattern shown in the example above there are other variations to consider. If the object is an instance variable you have to put the release in the dealloc method (or set it to nil via a property if you prefer). If the object is obtained from a static convenience constructor (such as [NSString stringWithFormat:]), or if you send it the autorelease message, then you should not call release yourself - but you do need to be aware the the object will live beyond its last use - which may be significant.

If you are given an object, but not passed ownership, and need to keep hold of it then you will need to send it the retain message (then later remember to call release again).

Whichever case it may be, doing it wrong has consequences. Failing to call release will result in leaks (which may lead to a crash - but much later). Failing to call retain could mean that you are using an object that may have been deallocated. This will likely lead to a crash sooner. If you're really lucky it will crash close enough to the source of the problem to help you find it - unless your users find it first.

Leaks and crashes are serious problems. Even if 99% of your code is correct in its memory management, just one or two such bugs can ruin your user experience (not to mention your app store ratings).

Deodorant

There are some tools that can help. For leaks we now have the LLVM static analyser integrated with XCode. This will work with the compiler to analyse your code paths, looking for misplaced releases or retains. It does a pretty good job and I highly recommend using it regularly. But its not perfect. It misses quite a few cases - especially if the code paths get complex. It can also give false negatives.

At runtime we can also use the Leaks instrument, which will track your references and see when objects are still alive after their last use. I suspect that internally it implements garbage collection, or something like it, to do the reference tracking. Instruments itself has got very good lately - making it much easier to filter out all the noise and see just your bits of the code. Again I highly recommend using this tool. But again it won't catch everything. In particular it will only test the code paths you use while its running.

For over releases, or releasing too early, we can check stack dumps. This may help us to track down the source of a crash - if it's not too far from the suspect code. A better tool, though, is NSZombies - enabled with the NSZombiesEnabled environment variable. With this in operation objects that would normally be dealloc'ed get transmuted into zombie objects instead. These will detect if you send any messages to them and log the fact. There are also a handful of other tools and techniques for tracking down leaks and over releases after the event.

So we can cover up the smell to some extent - but just as with real smells, masking is not the same as removing. We have additional mental overhead distracting you from your task - and extra tools and techniques required to apply after the event.

That's rubbish

So why is Garbage Collection not provided for iOS, given that it's been available on the Mac for about three years?

The short answer is: performance. The slightly longer answer is that GC has an overhead. It's an overhead that you pay every time you run your app. Much of the time the overhead may be invisible, or at least barely noticeable. Sometimes, though, it becomes very noticeable. Common tasks such as scrolling through long lists are famously smooth user experiences on iOS devices. Not so on other platforms, which can tend to be glitchy and jerky.

While bad code is something that can plague any platform (and there are other factors, such as hardware acceleration)- at least it is something you control. Issues caused by GC, though, are outside your immediate control. Depending on the GC implementation you may have access to an API that allows you some degree of control - but this is usually in the form of hints.

Whether you are willing to pay the cost or not, whether you think it's an issue or not, others clearly do have issues with it (and they may be your users). So Apple, as platform provider, has taken the design decision to hold back on providing garbage collection.

This leaves us with managing memory in our own apps. Notice I didn't say "manually managing memory" there. Any good developer - faced with implementing the same patterns of code over and over - even small snippets of code - but especially where missing them is easy and dangerous - find ways to factor out the duplication.

This is a problem that was solved years ago in C++, employing a concept known as RAII.

RAII of light

What is RAII, and how can it help us in Objective-C?

RAII stands for Resource Acquisition Is Initialisation - which is a long and complicated sounding name for a simple but powerful concept. It's also an unfortunate name as it sounds like the focus is on "acquisition" and "initialisation", yet the most interesting part is at the end of the lifetime. To explain what I mean let me cast it in Objective-C terms (if you're familiar with C++ and this concept feel free to skip ahead):

An Objective-C class has one or more initialisers, and a dealloc method. We use these methods to manage our resources (usually pointers to other objects).

In our init method (or designated initialiser) we typically either allocate other objects, or retain objects passed in. Either way we own references to them that we must release later, in our dealloc method.

Of course, we never call dealloc directly - it is called by release once the last retain count has gone.

In C++ the equivalent of init methods are called constructors and the analog to dealloc is the destructor. Where C++ differs is that instead of all objects being reference counted heap objects we have either plain heap objects or value types (which typically live on the stack or, if they are member (instance) variables they are scoped by the lifetime of the object they are a member of).

The nice thing about value types is that they are destroyed immediately, and predictably, at the end of their scope. This feature is so important it has its own name: Deterministic Destruction.

{
	MyClass myObject;

	// ...

} // destructor will be called here

Now because the the destructor is called automatically at the end of the scope - regardless of how it leaves that scope (so it allows for early returns or exceptions), and we can write arbitrary code in the destructor, this gives us a hook. We can use this mechanism to write code that will be be called as the execution leaves a scope. In fact this technique, along with templates and a bit of operator overloading, has been used for years to implement wrapper classes for raw C++ pointers that look and feel like pointers but have some sort of automatic memory management mixed in. These classes are known, collectively, as smart pointers. Reference counting smart pointers are just one possibility but there are many smart pointer traits that can be captured this way - such is the flexibility (and complexity) of C++.

This is all well and good - but we don't have custom value types, templates or operator overloading in Objective-C. So what use has this discussion been?

Objective C++

Apple's officially sanctioned languages for iPhone development are Objective-C, C and C++. But actually there is a fourth language, not listed there because it's a hybrid. That "language" is Objective-C++. I use the word language lightly here because Objective-C++ is a more of a glue language than a language you would use in its own right. Typically it is used to bridge the worlds between pure Objective-C and pure C++ in order to keep them at arms length (pun intended) from each other.

But there is no technical reason that you couldn't write an entire application, top-to-bottom, in Objective-C++. The reason you wouldn't typically do so is that they have very different syntaxes, strengths and weaknesses, and design trade-offs. Mixing the two just doesn't look like code written in a single language. C++ is oil to Objective-C's water (and we'll resist the temptation to point out how big the leaks can get if you mix oil and water!).

We're going carve out a new niche here. We're not going to freely mix the languages without constraint. But we're not going to keep them siloed either. Instead we're going to use some judicious helpers from the C++ side to assist our otherwise pure Objective-C. I don't suggest this lightly. There are certainly some that would take issue with this approach. We'll discuss these trade-offs later.

In the follow-on article I'm going to put this all together and show you my Objective-C++ solution: OCPtr.