Having trouble with BOOL return type in Objective-C blocks
I stumbled over a curious problem with BOOL
return type in blocks. Having the following definition:
typedef BOOL (^BoolBlock)(void);
…this code passes:
BoolBlock foo = ^{ return YES; };
…but this fails to compile:
BoolBlock bar = ^{ return YES || NO; };
With the follow开发者_开发问答ing error message:
Incompatible block pointer types initializing 'BoolBlock' (aka 'BOOL (^)(void)') with an expression of type 'int (^)(void)'
I can solve the issue using an explicit cast, but shouldn’t this work without it? Is there a better solution?
|| operator returns int type as Chuck said.
BoolBlock bar = ^{ return (BOOL)(YES || NO); };
or
BoolBlock bar = ^BOOL (void){ return YES || NO; };
BoolBlock bar = ^BOOL (){ return YES || NO; }; // warns in gcc, ok with clang
You're probably thinking the ||
operator works in languages like Ruby and Python, where it returns in the first operand that is truthy. In C, it returns 1 if either operand is truthy and 0 otherwise — that's why it thinks you're returning an integer.
As others have stated, the reason you’re getting the error is that e0 || e1
returns an int
regardless of the types of e0
and e1
. Since the compiler infers the block return type based upon the return
statement(s), you have a block that returns int
and you’re trying to assign it to a block variable whose block return type is BOOL
.
I personally prefer this syntax:
BoolBlock bar = ^BOOL { return YES || NO };
to avoid the error, making it clear that the block return type is BOOL
. The rvalue, a block literal, is understood as a block whose return type is BOOL
and the compiler applies the usual C conversions.
As to why this happens, it’s a design decision, although it doesn’t seem to be explicitly documented.1 Blocks are a new language feature. The compiler designers2 have decided that they should have tighter semantics on blocks — namely, the assignment of block pointer types must have strictly matching types — and they enforce these tighter semantics when assigning a block to a block variable regardless of the rvalue being a block pointer or a block literal.
Since there’s no ISO/IEC standard covering blocks in C or C++ yet, compiler designers are free to make these decisions. Apple have submitted blocks to ISO/IEC JTC1/SC22/WG14 as WG14/N1370 and WG14/N1451 and, if they accept it, this behaviour (or some variant of it) should be standardised and documented.
1Clang’s source code does have a comment stating that assignment of block pointers is more strict than assignment of function pointers.
2I’ve personally asked them about this.
精彩评论