开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜