Wednesday July 24, 2013

Objective C Generics Implemented Entirely At Compile Time

Tomer Shiri came up with a fascinating way to do generics in Objective C. Just drop a single .h file in your project, then declare your objects like so:

GENERICSABLE(SearchResult)

@interface SearchResult : NSObject<SearchResult>
@property (nonatomic, strong) NSString* description;
// ...
@end

That GENERICSABLE(...) preprocessor macro does some crazy magic to define categories on all the built in Foundation collection classes (NSArray, NSSet, etc.). Now, you can declare a collection for your objects like so:

SearchResult *found = [[SearchResult alloc] init];
NSMutableArray<SearchResult> *results = [NSMutableArray array];
[results addObject:found];
NSString *aString = results[0];  // Gives a warning

That last line shows a warning because the results array is expecting to return a SearchResult object and not an NSString. (Cue all the Java and C# developers and their chuckling at us for discovering something so…novel.) It’s not completely airtight since you can still add any object to the collection without a warning, but getting objects out and creating new collections based on other collections are protected as you’d expect.

The real kicker, however, is that these categories are just the interfaces. There’s not a bit of implementation code linked in to make it work. It’s purely a preprocessed compile time trick.

The usual disclaimer: Be careful. I’ve built a successful career cultivating my fear of the C preprocessor. Still, I can’t help but smile at the technique.