Saturday, November 3, 2012

Sometimes when programming, we encounter impossible situations. Unfortunately, the compiler isn’t as smart as we are. It can’t identify impossible situations like we can. For these situations, we can help the compiler by instructing it that a code path is impossible. For this we use __builtin_unreachable().

Let’s say we have an enum as follows:

typedefNS_ENUM(NSInteger, MyEnum) {

MyEnumA,

MyEnumB,

MyEnumC,

MyEnumD,

};

Now let’s say we have a switch statement that uses two of the four enum values, but the other two are impossible in this situation. Not including them in the switch will generate a compiler warning. However, including them doesn’t make sense. We can use __builtin_unreachable() to get rid of the warnings.

MyEnumvalue = // some value.

switch(value) {

caseMyEnumA:

// Handle case A

break;

caseMyEnumB:

// Handle case B

break;

default:

NSLog(@"Cases C and D are impossible");

__builtin_unreachable();

}

We can also make a macro that we can use to mark a method as not implemented like the following:

- (NSString*)someMethod {

NOT_IMPLEMENTED;

}

By using __builtin_unreachable(), this macro also makes it so we don’t need to return a bogus value to suppress the no return value warning. The macro looks like this:

Another perk of this macro is that it prints an error to the console including the name of the method that is not implemented.

Related to __builtin_unreachable() is the ‘noreturn’ attribute. This allows us to mark any function or method that once called, it will never return. This attribute is great for abort methods. We can mark methods like so:

- (void)gracefulAbort __attribute__((noreturn));

Let’s say our app encounters a terminal Core Data error and we need to gracefully terminate the app. We can encapsulate this into a method. This method obviously will never return since it will cause the app to close. By marking it with the noreturn attribute, we will gain the same benefits as if we did the following:

[selfgracefulAbort];

__builtin_unreachable();

The above cases I described are few and far between, but when they come up, __builtin_unreachable() is useful. To learn more about this and other Clang language extensions, check out the clang docs.