Blocks

A block type, also referred to as a delegate type on .NET, defines a method pointer that can be used to hold a reference to a Method or an Anonymous Method. Blocks are a safe way to dynamically invoke methods with a specific signature on unrelated classes.

Different from regular Function Pointers on native platforms (more on those below), block instance captures not only the implementation of the method in question, but also the Self pointer of the object instance that contains the method. This allows calls to blocks to execute in the context of a specific object instance, and access that object's members.

A block type is declared using the block keyword, followed by a regular Method signature. This signature can include parameters and a result type.

type
  MyBlock1 = public block(aParameter: Integer);
  MyBlock2 = public block: String;
  MyBlock3 = public block;

In addition to block, the delegate keyword can also be used to declare a block.

The two keywords are interchangeable, and delegate is mainly supported for backwards compatibility. We discourage the use of delegate, because, while commonly used on .NET, the term can be confusing with what the terminology "delegate" refers to many other platforms, especially Cocoa. We recommend to use the block keyword, exclusively.

Creating Block References

A block reference can be created by simply assigning a Method, Anonymous Method or Lambda Expression to a block variable.

To avoid ambiguity (e.g. as to whether to call the method and use its result, or assign the method itself), the method reference can be prefixed with the Address Of (@) Operator. But note that this is seldomly required, except in cases of ambiguity (e.g. if the method itself returns a compatible block), ot to levarage type inference.

var x: MyBlock1 := @MyClass.MyMethod; // use a method as block
var y: MyBlock2 := () -> "Hello";     // use a lambda as block
var z := method begin                 // use an anonymous method
           DoSomething;
         end;

Invoking a Block

Invoking a block reference is as easy as calling into the block as if it were a regular local method:

x(15);
var s: String := y();
z();

Note that different than in regular Method Calls, parenthesis are required to call the block. This is to avoid ambiguity between calling or referencing the block, e.g.:

var a := y;   // assigns the same block as `y` to `a`
var b := y(); // calls `y` and assigns the result to `a`.

Function Pointers

Function Pointers are a type similar to blocks, but more limited. They can be declared using the same syntax, but with the method keyword instead of block.

Different than blocks, function pointers do not capture a Self. As such, they can only refer to simple (global) functions, not to class methods. Anonymous methods or lambdas can be used as function pointers, as long as they do not access the surrounding scope or self.

Inline Block Types

Inline block types are blocks defined in a type reference, they use the same syntax as regular blocks, but without a name. On .NET and Java, these blocks must map to system-predefined generic delegates (System.Action*, and System.Func* on .NET and types in the Cooper Base Library for Java). Cocoa and Island support arbitrary inline blocks natively.

method DoSomething(aCallback: block(aStatus: String));
begin
  //...
  aCallBack("Done.");
end;

Type Visibility

The visibility of a block type can be controlled by applying a Visibility Modifier on the declaration. The default visibility is assembly.

Other Modifiers

Other modifiers do not apply to blocks.