362 lines
13 KiB
ReStructuredText
362 lines
13 KiB
ReStructuredText
|
|
||
|
.. role:: block-term
|
||
|
|
||
|
=================================
|
||
|
Language Specification for Blocks
|
||
|
=================================
|
||
|
|
||
|
.. contents::
|
||
|
:local:
|
||
|
|
||
|
Revisions
|
||
|
=========
|
||
|
|
||
|
- 2008/2/25 --- created
|
||
|
- 2008/7/28 --- revised, ``__block`` syntax
|
||
|
- 2008/8/13 --- revised, Block globals
|
||
|
- 2008/8/21 --- revised, C++ elaboration
|
||
|
- 2008/11/1 --- revised, ``__weak`` support
|
||
|
- 2009/1/12 --- revised, explicit return types
|
||
|
- 2009/2/10 --- revised, ``__block`` objects need retain
|
||
|
|
||
|
Overview
|
||
|
========
|
||
|
|
||
|
A new derived type is introduced to C and, by extension, Objective-C,
|
||
|
C++, and Objective-C++
|
||
|
|
||
|
The Block Type
|
||
|
==============
|
||
|
|
||
|
Like function types, the :block-term:`Block type` is a pair consisting
|
||
|
of a result value type and a list of parameter types very similar to a
|
||
|
function type. Blocks are intended to be used much like functions with
|
||
|
the key distinction being that in addition to executable code they
|
||
|
also contain various variable bindings to automatic (stack) or managed
|
||
|
(heap) memory.
|
||
|
|
||
|
The abstract declarator,
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
int (^)(char, float)
|
||
|
|
||
|
describes a reference to a Block that, when invoked, takes two
|
||
|
parameters, the first of type char and the second of type float, and
|
||
|
returns a value of type int. The Block referenced is of opaque data
|
||
|
that may reside in automatic (stack) memory, global memory, or heap
|
||
|
memory.
|
||
|
|
||
|
Block Variable Declarations
|
||
|
===========================
|
||
|
|
||
|
A :block-term:`variable with Block type` is declared using function
|
||
|
pointer style notation substituting ``^`` for ``*``. The following are
|
||
|
valid Block variable declarations:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
void (^blockReturningVoidWithVoidArgument)(void);
|
||
|
int (^blockReturningIntWithIntAndCharArguments)(int, char);
|
||
|
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
|
||
|
|
||
|
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.
|
||
|
|
||
|
A Block reference may be cast to a pointer of arbitrary type and vice
|
||
|
versa. [cast.c] A Block reference may not be dereferenced via the
|
||
|
pointer dereference operator ``*``, and thus a Block's size may not be
|
||
|
computed at compile time. [sizeof.c]
|
||
|
|
||
|
Block Literal Expressions
|
||
|
=========================
|
||
|
|
||
|
A :block-term:`Block literal expression` produces a reference to a
|
||
|
Block. It is introduced by the use of the ``^`` token as a unary
|
||
|
operator.
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
Block_literal_expression ::= ^ block_decl compound_statement_body
|
||
|
block_decl ::=
|
||
|
block_decl ::= parameter_list
|
||
|
block_decl ::= type_expression
|
||
|
|
||
|
where type expression is extended to allow ``^`` as a Block reference
|
||
|
(pointer) where ``*`` is allowed as a function reference (pointer).
|
||
|
|
||
|
The following Block literal:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
^ void (void) { printf("hello world\n"); }
|
||
|
|
||
|
produces a reference to a Block with no arguments with no return value.
|
||
|
|
||
|
The return type is optional and is inferred from the return
|
||
|
statements. If the return statements return a value, they all must
|
||
|
return a value of the same type. If there is no value returned the
|
||
|
inferred type of the Block is void; otherwise it is the type of the
|
||
|
return statement value.
|
||
|
|
||
|
If the return type is omitted and the argument list is ``( void )``,
|
||
|
the ``( void )`` argument list may also be omitted.
|
||
|
|
||
|
So:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
^ ( void ) { printf("hello world\n"); }
|
||
|
|
||
|
and:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
^ { printf("hello world\n"); }
|
||
|
|
||
|
are exactly equivalent constructs for the same expression.
|
||
|
|
||
|
The type_expression extends C expression parsing to accommodate Block
|
||
|
reference declarations as it accommodates function pointer
|
||
|
declarations.
|
||
|
|
||
|
Given:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
typedef int (*pointerToFunctionThatReturnsIntWithCharArg)(char);
|
||
|
pointerToFunctionThatReturnsIntWithCharArg functionPointer;
|
||
|
^ pointerToFunctionThatReturnsIntWithCharArg (float x) { return functionPointer; }
|
||
|
|
||
|
and:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
^ int ((*)(float x))(char) { return functionPointer; }
|
||
|
|
||
|
are equivalent expressions, as is:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
^(float x) { return functionPointer; }
|
||
|
|
||
|
[returnfunctionptr.c]
|
||
|
|
||
|
The compound statement body establishes a new lexical scope within
|
||
|
that of its parent. Variables used within the scope of the compound
|
||
|
statement are bound to the Block in the normal manner with the
|
||
|
exception of those in automatic (stack) storage. Thus one may access
|
||
|
functions and global variables as one would expect, as well as static
|
||
|
local variables. [testme]
|
||
|
|
||
|
Local automatic (stack) variables referenced within the compound
|
||
|
statement of a Block are imported and captured by the Block as const
|
||
|
copies. The capture (binding) is performed at the time of the Block
|
||
|
literal expression evaluation.
|
||
|
|
||
|
The compiler is not required to capture a variable if it can prove
|
||
|
that no references to the variable will actually be evaluated.
|
||
|
Programmers can force a variable to be captured by referencing it in a
|
||
|
statement at the beginning of the Block, like so:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
(void) foo;
|
||
|
|
||
|
This matters when capturing the variable has side-effects, as it can
|
||
|
in Objective-C or C++.
|
||
|
|
||
|
The lifetime of variables declared in a Block is that of a function;
|
||
|
each activation frame contains a new copy of variables declared within
|
||
|
the local scope of the Block. Such variable declarations should be
|
||
|
allowed anywhere [testme] rather than only when C99 parsing is
|
||
|
requested, including for statements. [testme]
|
||
|
|
||
|
Block literal expressions may occur within Block literal expressions
|
||
|
(nest) and all variables captured by any nested blocks are implicitly
|
||
|
also captured in the scopes of their enclosing Blocks.
|
||
|
|
||
|
A Block literal expression may be used as the initialization value for
|
||
|
Block variables at global or local static scope.
|
||
|
|
||
|
The Invoke Operator
|
||
|
===================
|
||
|
|
||
|
Blocks are :block-term:`invoked` using function call syntax with a
|
||
|
list of expression parameters of types corresponding to the
|
||
|
declaration and returning a result type also according to the
|
||
|
declaration. Given:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
int (^x)(char);
|
||
|
void (^z)(void);
|
||
|
int (^(*y))(char) = &x;
|
||
|
|
||
|
the following are all legal Block invocations:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
x('a');
|
||
|
(*y)('a');
|
||
|
(true ? x : *y)('a')
|
||
|
|
||
|
The Copy and Release Operations
|
||
|
===============================
|
||
|
|
||
|
The compiler and runtime provide :block-term:`copy` and
|
||
|
:block-term:`release` operations for Block references that create and,
|
||
|
in matched use, release allocated storage for referenced Blocks.
|
||
|
|
||
|
The copy operation ``Block_copy()`` is styled as a function that takes
|
||
|
an arbitrary Block reference and returns a Block reference of the same
|
||
|
type. The release operation, ``Block_release()``, is styled as a
|
||
|
function that takes an arbitrary Block reference and, if dynamically
|
||
|
matched to a Block copy operation, allows recovery of the referenced
|
||
|
allocated memory.
|
||
|
|
||
|
|
||
|
The ``__block`` Storage Qualifier
|
||
|
=================================
|
||
|
|
||
|
In addition to the new Block type we also introduce a new storage
|
||
|
qualifier, :block-term:`__block`, for local variables. [testme: a
|
||
|
__block declaration within a block literal] The ``__block`` storage
|
||
|
qualifier is mutually exclusive to the existing local storage
|
||
|
qualifiers auto, register, and static. [testme] Variables qualified by
|
||
|
``__block`` act as if they were in allocated storage and this storage
|
||
|
is automatically recovered after last use of said variable. An
|
||
|
implementation may choose an optimization where the storage is
|
||
|
initially automatic and only "moved" to allocated (heap) storage upon
|
||
|
a Block_copy of a referencing Block. Such variables may be mutated as
|
||
|
normal variables are.
|
||
|
|
||
|
In the case where a ``__block`` variable is a Block one must assume
|
||
|
that the ``__block`` variable resides in allocated storage and as such
|
||
|
is assumed to reference a Block that is also in allocated storage
|
||
|
(that it is the result of a ``Block_copy`` operation). Despite this
|
||
|
there is no provision to do a ``Block_copy`` or a ``Block_release`` if
|
||
|
an implementation provides initial automatic storage for Blocks. This
|
||
|
is due to the inherent race condition of potentially several threads
|
||
|
trying to update the shared variable and the need for synchronization
|
||
|
around disposing of older values and copying new ones. Such
|
||
|
synchronization is beyond the scope of this language specification.
|
||
|
|
||
|
|
||
|
Control Flow
|
||
|
============
|
||
|
|
||
|
The compound statement of a Block is treated much like a function body
|
||
|
with respect to control flow in that goto, break, and continue do not
|
||
|
escape the Block. Exceptions are treated *normally* in that when
|
||
|
thrown they pop stack frames until a catch clause is found.
|
||
|
|
||
|
|
||
|
Objective-C Extensions
|
||
|
======================
|
||
|
|
||
|
Objective-C extends the definition of a Block reference type to be
|
||
|
that also of id. A variable or expression of Block type may be
|
||
|
messaged or used as a parameter wherever an id may be. The converse is
|
||
|
also true. Block references may thus appear as properties and are
|
||
|
subject to the assign, retain, and copy attribute logic that is
|
||
|
reserved for objects.
|
||
|
|
||
|
All Blocks are constructed to be Objective-C objects regardless of
|
||
|
whether the Objective-C runtime is operational in the program or
|
||
|
not. Blocks using automatic (stack) memory are objects and may be
|
||
|
messaged, although they may not be assigned into ``__weak`` locations
|
||
|
if garbage collection is enabled.
|
||
|
|
||
|
Within a Block literal expression within a method definition
|
||
|
references to instance variables are also imported into the lexical
|
||
|
scope of the compound statement. These variables are implicitly
|
||
|
qualified as references from self, and so self is imported as a const
|
||
|
copy. The net effect is that instance variables can be mutated.
|
||
|
|
||
|
The :block-term:`Block_copy` operator retains all objects held in
|
||
|
variables of automatic storage referenced within the Block expression
|
||
|
(or form strong references if running under garbage collection).
|
||
|
Object variables of ``__block`` storage type are assumed to hold
|
||
|
normal pointers with no provision for retain and release messages.
|
||
|
|
||
|
Foundation defines (and supplies) ``-copy`` and ``-release`` methods for
|
||
|
Blocks.
|
||
|
|
||
|
In the Objective-C and Objective-C++ languages, we allow the
|
||
|
``__weak`` specifier for ``__block`` variables of object type. If
|
||
|
garbage collection is not enabled, this qualifier causes these
|
||
|
variables to be kept without retain messages being sent. This
|
||
|
knowingly leads to dangling pointers if the Block (or a copy) outlives
|
||
|
the lifetime of this object.
|
||
|
|
||
|
In garbage collected environments, the ``__weak`` variable is set to
|
||
|
nil when the object it references is collected, as long as the
|
||
|
``__block`` variable resides in the heap (either by default or via
|
||
|
``Block_copy()``). The initial Apple implementation does in fact
|
||
|
start ``__block`` variables on the stack and migrate them to the heap
|
||
|
only as a result of a ``Block_copy()`` operation.
|
||
|
|
||
|
It is a runtime error to attempt to assign a reference to a
|
||
|
stack-based Block into any storage marked ``__weak``, including
|
||
|
``__weak`` ``__block`` variables.
|
||
|
|
||
|
|
||
|
C++ Extensions
|
||
|
==============
|
||
|
|
||
|
Block literal expressions within functions are extended to allow const
|
||
|
use of C++ objects, pointers, or references held in automatic storage.
|
||
|
|
||
|
As usual, within the block, references to captured variables become
|
||
|
const-qualified, as if they were references to members of a const
|
||
|
object. Note that this does not change the type of a variable of
|
||
|
reference type.
|
||
|
|
||
|
For example, given a class Foo:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
Foo foo;
|
||
|
Foo &fooRef = foo;
|
||
|
Foo *fooPtr = &foo;
|
||
|
|
||
|
A Block that referenced these variables would import the variables as
|
||
|
const variations:
|
||
|
|
||
|
.. code-block:: c
|
||
|
|
||
|
const Foo block_foo = foo;
|
||
|
Foo &block_fooRef = fooRef;
|
||
|
Foo *const block_fooPtr = fooPtr;
|
||
|
|
||
|
Captured variables are copied into the Block at the instant of
|
||
|
evaluating the Block literal expression. They are also copied when
|
||
|
calling ``Block_copy()`` on a Block allocated on the stack. In both
|
||
|
cases, they are copied as if the variable were const-qualified, and
|
||
|
it's an error if there's no such constructor.
|
||
|
|
||
|
Captured variables in Blocks on the stack are destroyed when control
|
||
|
leaves the compound statement that contains the Block literal
|
||
|
expression. Captured variables in Blocks on the heap are destroyed
|
||
|
when the reference count of the Block drops to zero.
|
||
|
|
||
|
Variables declared as residing in ``__block`` storage may be initially
|
||
|
allocated in the heap or may first appear on the stack and be copied
|
||
|
to the heap as a result of a ``Block_copy()`` operation. When copied
|
||
|
from the stack, ``__block`` variables are copied using their normal
|
||
|
qualification (i.e. without adding const). In C++11, ``__block``
|
||
|
variables are copied as x-values if that is possible, then as l-values
|
||
|
if not; if both fail, it's an error. The destructor for any initial
|
||
|
stack-based version is called at the variable's normal end of scope.
|
||
|
|
||
|
References to ``this``, as well as references to non-static members of
|
||
|
any enclosing class, are evaluated by capturing ``this`` just like a
|
||
|
normal variable of C pointer type.
|
||
|
|
||
|
Member variables that are Blocks may not be overloaded by the types of
|
||
|
their arguments.
|