On Mar 24, 2022, at 8:16 PM, Mouse <mo...@rodents-montreal.org> wrote:

> Nested functions are not closures, or at least not what I know as
> closures.  A nested function pointer (conceptually) goes invalid as
> soon as anything it refers to goes out of scope, or at the latest as
> soon as its smallest enclosing block exits (or possibly when its
> smallest enclosing function returns).  The thing I know as a closure
> would preserve the referred-to objects as long as the closure is
> potentially callable.  This requires more reference tracking than C
> typically makes possible.

Closures can easily be used as nested functions, and the blocks feature that 
was created by Apple explicitly addresses this by including runtime functions.

1. You can just declare and use a block if it's not going to go out of scope, 
as if it were a nested function, with just slightly different syntax than 
nested functions. (You do this by declaring a block-typed variable and 
immediately assigning the block to it, then calling through the variable. It 
behaves like a function pointer.)

2. If you have a variable in the outer scope that you want to modify in the 
block, you have to annotate the variable with __block, so the block context 
(activation record) created for the bock can find it. Otherwise everything in 
the enclosing scope is effectively immutable (though one must of course be 
aware that an immutable pointer is not the same as a pointer to immutable data).

3. If you're passing the block to another function or block, whatever you pass 
it to should *either* annotate its block argument as non-escaping via the right 
__attribute__(()) to indicate it doesn't need any memory management, or it 
should Block_copy() the block it's handed and work only with the copy. That 
ensures the block context is hoisted to the heap. Following Apple's general 
patterns, a Block_copy() of a heap block is identical to a BlocK_retain() so 
the latter should really never be called.

4. If something calls Block_copy() because it wants to hold onto a block, it 
needs to call Block_release() to eventually dispose of the block.

Here are the language and runtime specs. They're a great language addition and 
used pervasively on Apple platforms as a result.

Language: https://clang.llvm.org/docs/BlockLanguageSpec.html 
<https://clang.llvm.org/docs/BlockLanguageSpec.html>
Runtime/ABI: https://clang.llvm.org/docs/Block-ABI-Apple.html 
<https://clang.llvm.org/docs/Block-ABI-Apple.html>

  -- Chris

Reply via email to