2.13. BlockΒΆ

Block is a nameless function which captures local context by reference. Blocks offer significant performance advantage over lambda (see Lambda).

Block type can be declared with a function-like syntax:

block_type ::= block { optional_block_type }
optional_block_type ::= < { optional_block_arguments } { : return_type } >
optional_block_arguments := ( block_argument_list )
block_argument_list := argument_name : type | block_argument_list ; argument_name : type

block < (arg1:int;arg2:float&):bool >

Blocks capture current stack so block can be passed, but never returned. Block variables can only be passed as arguments. Global or local block variables are prohibited, returning block type is prohibited:

def goo ( b : block )
    ...

def foo ( b : block < (arg1:int; arg2:float&) : bool >
    ...

Blocks can be called via invoke:

def radd(var ext:int&;b:block<(var arg:int&):int>):int
    return invoke(b,ext)

Typeless blocks are typically declared via pipe syntax:

goo() <|                                // block without arguments
    print("inside goo")

Similarly typed blocks are typically declared via pipe syntax:

var v1 = 1                              // block with arguments
res = radd(v1) <| $(var a:int&):int
    return a++

Blocks can also be declared via inline syntax:

res = radd(v1, $(var a:int&) : int { return a++; }) // equivalent to example above

There is simplified syntax for the blocks containing return expression only:

res = radd(v1, $(var a:int&) : int => a++ )         // equivalent to example above

If block is sufficiently specified in the generic or function, block types will be automatically inferred:

res = radd(v1, $(a) => a++ )                        // equivalent to example above

Nested blocks are allowed:

def passthroughFoo(a:Foo; blk:block<(b:Foo):void>)
    invoke(blk,a)

passthrough(1) <| $ ( a )
    assert(a==1)
    passthrough(2) <| $ ( b )
        assert(a==1 && b==2)
        passthrough(3) <| $ ( c )
            assert(a==1 && b==2 && c==3)

Loop control expressions are not allowed to cross block boundaries:

while true
    take_any() <|
        break               // 30801, captured block can't break outside the block

Blocks can have annotations:

def queryOne(dt:float=1.0f)
    testProfile::queryEs() <| $ [es] (var pos:float3&;vel:float3 const)  // [es] is annotation
        pos += vel * dt

Block annotations can be implemented via appropriate macro (see Macro).