CornPuff
CornPuff

Reputation: 1924

When does Objective-C implicitly cast to BOOL?

I read Mike Ash's Objective-C pitfalls page, and now I'm paranoid about implicitly casting variables of type id to BOOL.

Assume I have a 'dangerous' pointer with the lower bits zeroed out, so that casting it to a BOOL would produce NO even though it points to a valid object. Let's call this 'dangerous' pointer foo.

How do simple if statements work? Does the if statement cast foo to a BOOL when it evaluates the condition? Or does it cast to a pure boolean?

if( foo )
{
  [myArray addObject:foo];
}

Does it work the same way in ternary expressions?

// Does this break when foo is 'dangerous'?
self.titleLabel.hidden = foo ? YES : NO ; 

Or will the ternary only break if I do this:

// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO ; 

I feel like I'm missing something basic about logical operations in C, and how they relate to BOOL. Please help enlighten me.

Upvotes: 3

Views: 4546

Answers (2)

user529758
user529758

Reputation:

When does Objective-C implicitly cast to BOOL?

Never, since this phrase is semantically incorrect. A cast is, by definition, explicit. What you're asking about is called an "implicit type conversion" (coercion - thanks, Josh!).

Also, strictly speaking, the conditionals in Objective-C are not special: they're inherited from C. So expressions, when needed to evaluated as booleans, aren't treated as BOOL, but as int.

// Does this break when foo is 'dangerous'?`
self.titleLabel.hidden = foo ? YES : NO;

No, it doesn't. (expr) when used as a "boolean" expression, is equivalent to (expr != 0). No risks here.

// I'm pretty sure it breaks now
self.titleLabel.hidden = ((BOOL)foo) ? YES : NO;

Now this can break, since BOOL is just typedeffed to signed char, which is 8 bit on iOS. Thus, if foo, which is a (32-bit) pointer, gets truncated to 8 bits, and the lower 8 bits of the pointer were all zero, but the pointer itself wasn't nil, this will incorrectly report false. You don't want to do this superfluous, ugly and dangerous cast. If you want to be more explicit, write

var = (obj != nil) ? valueOne : valueTwo;

instead.

Upvotes: 8

Stephane Delcroix
Stephane Delcroix

Reputation: 16232

There's no casting in your first two samples. Writing if(expr) is equal to writing if(expr == 0).

Your third example might indeed break in some cases, as described in the article you refer to.

Upvotes: 1

Related Questions