diff options
Diffstat (limited to 'docs/BlockLanguageSpec.rst')
-rw-r--r-- | docs/BlockLanguageSpec.rst | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/docs/BlockLanguageSpec.rst b/docs/BlockLanguageSpec.rst new file mode 100644 index 0000000..3632d56 --- /dev/null +++ b/docs/BlockLanguageSpec.rst @@ -0,0 +1,361 @@ + +.. 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. |