New Objective-C Features in LLVM 3.1
Unlike C and C++, Objective-C isn't governed by a standards body; it's controlled by a single entity that owns the trademark for the language name—originally Stepstone, then NeXT, and now Apple.
This individual ownership can be an advantage and a disadvantage. For example, the new version of the C++ specification, C++11, took 13 years to finalize, and it now embodies an abstract machine model that represents the state of the art in modern microprocessors, circa 2005. In contrast, Objective-C can evolve very quickly, without the problem of design by committee. The downside is that there's no oversight in the design, so you're sometimes left wondering what—or, indeed, if—the designers were thinking. An example is the dot notation for property accessors, a completely pointless syntactic addition that does nothing more than obfuscate code. At the opposite end of the spectrum is Automatic Reference Counting (ARC), which finally adds a sane memory model to the language, with a clear separation between object memory and C memory.
LLVM 3.1 brings several enhancements to Objective-C, which we'll look at in this article.
NSNumber Constants
I'll begin with something that people have been asking for in Objective-C for about 25 years: syntax for creating constant number objects. Objective-C has had syntax for creating string literals for a long time, but they were the only objects that you can create as literals.
The syntax is no surprise, either; it's exactly the syntax that was proposed decades ago by the original designers of Objective-C, but never implemented. C number literals are just prefixed with @. Unfortunately, once you get past the syntax, you see it start to break down. Consider the following code:
id str = @"This is a string";
This example works fine—it creates a statically allocated instance of NSConstantString (or equivalent) and initializes this variable with a pointer to it. Now what about this one?
int x = 42;
This line stores the constant value 42 in the data section of the executable. Again, as you'd expect. Therefore, this version should work too:
id x = @42;
Let's see what clang says:
lit.m:3:8: error: initializer element is not a compile-time constant id x = @42; ^~~
Why isn't this a compile-time constant? Because it isn't implemented in the same way as Objective-C string literals; it's just some syntactic sugar for creating new autoreleased NSNumber objects. In Objective-C11, you can actually do this fairly trivially in a macro, something like this abridged form:
#define N(x) _Generic((x), \ int: [NSNumber numberWithInt: x], \ float: [NSNumber numberWithFloat: x], \ double: [NSNumber numberWithDouble: x])
This example takes a numeric argument and returns a new NSNumber created from it. The following pairs of assignments are all equivalent:
x = N(12); x = @12; x = N(42.5); x = @42.5; x = N(42.5f); x = @42.5f;
You can trivially extend the macro to support long longs, long doubles, and so on. You could even extend it to support complex numbers, although they'd have to be boxed in NSValue instances.
The macro form has two advantages. The first is that it works with any expression, not just with literals. The second is that it conveys, in the syntax, the fact that this isn't a constant value. Consider the previous examples again. What happens if x is a global? If you're using ARC mode, everything works fine; they'll be turned onto calls to something like objc_storeStrong(), and the retain counts will be updated correctly. If you're not in ARC mode, you'll assign a temporary autoreleased object to a global, and you'll end up with a dangling pointer. Does @42 look like a short-lived temporary to you?
This situation is especially irritating because there's no reason to implement it like this. Both the OS X 10.7 and GNUstep Objective-C runtimes support hiding number objects inside pointers, so it's entirely possible to make them static. Similarly, even the old GCC runtime has supported static instances of arbitrary objects. Implemented properly, it would actually be a useful feature. Unfortunately, it looks like this was just rushed out in a semi-finished state. Hopefully that problem will be addressed in a future release.