Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing block parameter that doesn't match signature

I'm working with a block-based API and stumbled across a scenario where I was passing in a block parameter that had a signature that didn't match the typedef'd parameter the method was expecting. To my surprise, the compiler didn't seem to care about this, and the app didn't crash. Is this expected behavior? Example:

typedef void(^MyBlock)();
typedef void(^MyBlockWithParam)(id param);

- (void)doWork {
    MyBlockWithParam block1 = ^(id param) {
        NSLog(@"block1: %@", param);
    };

    MyBlock block2 = ^{
        NSLog(@"block2");
    };

    [self loadData:block1];
    [self loadData:block2];
}

- (void)loadData:(MyBlockWithParam)block {
    block(@"foo");
}
like image 586
chinabuffet Avatar asked Aug 09 '13 17:08

chinabuffet


People also ask

Why are my parameters not visible in the block editor?

Report ‎08-01-201709:09 AM Parameters are part of layer 0. If layer 0 is set invisible the parameters also won't be vsisible in the block editor. Kind regards

What is the effect of pass by name in a procedure?

In general, the effect of pass-by-name is to textually substitute the argument in a procedure call for the corresponding parameter in the body of the procedure. The argument expression is re-evaluated each time the formal parameter is passed.

What are the parameter passing techniques in C++?

Parameter Passing Techniques in C/C++. There are different ways in which parameter data can be passed into and out of methods and functions. Let us assume that a function B() is called from another function A(). In this case A is called the “caller function” and B is called the “called function or callee function”.

How do you pass parameter data from one method to another?

There are different ways in which parameter data can be passed into and out of methods and functions. Let us assume that a function B () is called from another function A (). In this case A is called the “caller function” and B is called the “called function or callee function”.


2 Answers

Providing an empty arguments specification as in

typedef void(^MyBlock)();

means "unspecified" arguments. So the two types are compatible as written. Changing the first declaration to

typedef void(^MyBlock)(void);

specifies that the block takes no arguments and you'll get an error.

K&R C specifies that an empty argument list means "unspecified". The C blocks spec says this is not true for block type declarations (cf. http://clang.llvm.org/docs/BlockLanguageSpec.html#block-variable-declarations) but: both GCC and Clang implement the K&R behavior as a language extension.

like image 116
nielsbot Avatar answered Oct 27 '22 17:10

nielsbot


From the Clang Blocks specification:

Variadic ... arguments are supported. [variadic.c] A Block that takes no arguments must specify void in the argument list [voidarg.c]. An empty parameter list does not represent, as K&R provide, an unspecified argument list. Note: both gcc and clang support K&R style as a convenience.

Basically, this is an ancient quirk of C syntax. In olden times, C function declaration syntax was rather different, and empty parentheses indicated that the function could be passed any number of arguments. For backwards compatibility, compilers have generally allowed the old-style function declaration syntax. And for some reason, Apple decided to simultaneously reject this syntax in the block standard while actually allowing it to be used with blocks in both GCC and Clang.

So, long story short: To declare that a block takes no arguments, you need to explicitly type it as void(^MyBlock)(void)

like image 38
Chuck Avatar answered Oct 27 '22 17:10

Chuck