why the type of `nil` is not `id` but `void *`

前端 未结 3 751
终归单人心
终归单人心 2021-01-17 23:49

In this code

id (^block)(void) = ^(void) {
    return nil;
};

I have this error

Incompatible block pointer types ini

3条回答
  •  旧巷少年郎
    2021-01-18 00:43

    When a block omits it's return type, it now becomes the job of the compiler to infer the type of the block based on the returns in its body. But, unfortunately, CLANG searches for the fully decayed forms of it's returned types, which leads to strange inconsistencies.

    The most accessible example is sorting an array. The type of the comparator block is NSComparisonResult(^)(id obj, id obj2), but if you choose to omit the NSComparisonResult return type, the compiler gets whiny:

    NSArray *sortedArray = [array sortedArrayUsingComparator: ^(id obj, id obj2) {
        if (//...) return NSOrderedAscending;
        return NSOrderedDescending;
    }];
    

    This block decays into a block of type int(^)(id obj, id obj2), which the compiler sees as incompatible (arguably, enums are just named ints, so this should compile).

    In the same way, id decays into objc_object* which decays on and on and on until it reaches void*, or "any generic pointer" (according to the C language spec). void* and id are most certainly not the same type. To get around this, you have to promise the compiler that the returned type truly is what it is, and the only way to do that is to cast.

    LLVM 5.0 fixes this by making the compiler's inferences much smarter.

提交回复
热议问题