I’m reading Kent Beck’s Smalltalk Best Practice Patterns and learning a lot about how control structures work in what’s probably the purest object-oriented language. For example, if isn’t used to manage conditionals. In Smalltalk, since all things are objects, including booleans, you can just send the message -ifTrue: and -ifFalse: , with blocks, to the True object.

Let’s try that out with Objective-C:

@implementation NSNumber ( IfTrue ) - ( BOOL ) isBoolean { return [ @ ([ self objCType ]) isEqualToString : @ ( @encode ( BOOL ))]; } - ( id ) ifTrue : ( void ( ^ )()) onTrue { if ([ self isBoolean ]) { if ([ self boolValue ]) { if ( onTrue ) onTrue (); } else { return self ; } } return nil ; } - ( id ) ifFalse : ( void ( ^ )()) onFalse { if ([ self isBoolean ]) { if ([ self boolValue ]) { return self ; } else { if ( onFalse ) onFalse (); } } return nil ; } @end

When the case is not satisfied (i.e., the NSNumber is @YES , but we messaged -ifFalse: ), we return self , so that the messages can be chained, like so:

[[@YES ifTrue:^{ NSLog(@"this code block is entered!"); }] ifFalse:^{ NSLog(@"this one is not"); }];

Pretty elegant! Smalltalk also allows us to ask an object to execute block if it’s nil. Hm. This actually presents a problem for us, since nil in Objective-C eats all messages and returns nil again. Our message would be swallowed and our block wouldn’t get executed. Fortunately, the runtime is here to save us! Let’s #import <objc/runtime.h> . Grab the whiskey.

Bill Bumgarner teaches us how to create our own nil object and tell the runtime that we’d like to use it instead of the built in nil . First, let’s make STNil . It eats all messages, just like good old regular nil :

@implementation STNil + ( BOOL ) resolveClassMethod :( SEL ) sel { return NO ; } + ( BOOL ) resolveInstanceMethod :( SEL ) sel { return NO ; } - ( NSMethodSignature * ) methodSignatureForSelector :( SEL ) aSelector { return [ NSObject instanceMethodSignatureForSelector : @selector ( description )]; } - ( void ) forwardInvocation :( NSInvocation * ) anInvocation { } - ( void ) ifNil :( void ( ^ )()) onNil { if ( onNil ) onNil (); } @end

And let’s add the -ifNil: message to NSObject as a category and make it a no-op:

@implementation NSObject ( IfNil ) - ( void ) ifNil :( void ( ^ )()) onNil { } @end

And then lets use _objc_setNilReceiver (which is private!) to set STNil as the nil receiver;

extern id _objc_setNilReceiver(id newNilReceiver); int main(int argc, const char **argv) { @autoreleasepool { id smalltalkyNil = [STNil new]; _objc_setNilReceiver(smalltalkyNil); NSString *nilString = nil; [nilString ifNil:^{ NSLog(@"this object is nil"); }]; _objc_setNilReceiver(nil); } return 0; }

This works! We can now message nil as easily as any other object.

Let’s take it even further. In Ruby on Rails, objects support something called presence . Presence makes truthiness behave in a more useful and consistent way. Nil, empty strings, and empty collections are “not present” (or “blank”), so you can call myArray.blank instead of the more convoluted myArray.count == 0 . Let’s bring that stuff over to this new block based model as well.

Let’s put some more stuff on NSObject :

@implementation NSObject ( Presence ) - ( BOOL ) present { return YES ; } - ( BOOL ) blank { return ! self . present ; } - ( void ) ifPresent : ( void ( ^ )()) onPresent { if ( self . present && onPresent ) onPresent (); } - ( void ) ifBlank : ( void ( ^ )()) onBlank { if ( self . blank && onBlank ) onBlank (); } @end

And then, all we have to do create a category on NSArray that overrides present (and optionally forward -ifEmpty: to -ifBlank: ):

@implementation NSArray ( Presence ) - ( BOOL ) present { return !! self . count ; } - ( void ) ifEmpty : ( void ( ^ )()) onEmpty { [ self ifBlank : onEmpty ]; } @end

Now, we can call -ifEmpty: exactly as we’d expect to:

[@[] ifEmpty:^{ NSLog(@"this array is empty!"); }];

Who knew Smalltalk could be so much fun?