Skip to content

Use Template FUNCTION_BLOCKs

This guide covers writing a template FUNCTION_BLOCK<N: UINT>, instantiating it at different sizes, and wiring it into a parent block. It assumes you already know how to write plain FBs and how the WIRING block works.


Write a template FUNCTION_BLOCK

Add a <N: UINT> header after the FB name. Inside the body, use N wherever a concrete integer would appear:

FUNCTION_BLOCK Vec<N: UINT>
VAR_INPUT
    a : ARRAY[0..N-1] OF LREAL;
    b : ARRAY[0..N-1] OF LREAL;
END_VAR
VAR_OUTPUT
    dot : LREAL;
END_VAR
IMPLEMENTATION
    dot := SUM(k IN 0..N-1 : a[k] * b[k]);
END_IMPLEMENTATION
END_FUNCTION_BLOCK

Save as Vec.lola. The file still has exactly one top-level FUNCTION_BLOCK; the <N: UINT> makes it generic, not a special kind of file.


Declare multiple type parameters

Separate parameters with a comma. The nested-array syntax ARRAY[..] OF ARRAY[..] OF T works with template bounds, and the double-bracket index a[i][j] is fully supported:

FUNCTION_BLOCK Mat<M: UINT, N: UINT>
VAR_INPUT
    a : ARRAY[0..M-1] OF ARRAY[0..N-1] OF LREAL;
END_VAR
VAR_OUTPUT
    s : LREAL;
END_VAR
IMPLEMENTATION
    s := SUM(i IN 0..M-1 : SUM(j IN 0..N-1 : a[i][j]));
END_IMPLEMENTATION
END_FUNCTION_BLOCK

For flat row-major access the single-bracket form also works:

FUNCTION_BLOCK MatVec<M: UINT, K: UINT>
VAR_INPUT
    a : ARRAY[0..M*K-1] OF LREAL;   (* row-major: a[i*K+k] = row i, col k *)
    x : ARRAY[0..K-1]   OF LREAL;
END_VAR
VAR_OUTPUT
    y : ARRAY[0..M-1] OF LREAL;
END_VAR
IMPLEMENTATION
    y := ARRAY(i IN 0..M-1 : SUM(k IN 0..K-1 : a[i*K+k] * x[k]));
END_IMPLEMENTATION
END_FUNCTION_BLOCK

Bounds may use addition, subtraction, and multiplication over type parameters (N-1, M*K-1). Other arithmetic operators (/, MOD) also work when both operands are known at compile time.


Instantiate a template block

In the VAR block of any parent FB or PROGRAM, append the concrete UINT values in angle brackets:

FUNCTION_BLOCK Dot3
VAR_INPUT
    p : ARRAY[0..2] OF LREAL;
    q : ARRAY[0..2] OF LREAL;
END_VAR
VAR_OUTPUT
    result : LREAL;
END_VAR
VAR
    v : Vec<3>;          (* N is substituted with 3 *)
END_VAR
WIRING
    v(a := p, b := q);
    result := v.dot;
END_WIRING
END_FUNCTION_BLOCK

The compiler resolves Vec.lola, substitutes N = 3, and compiles the resulting Vec<3> FB as an ordinary sub-instance.


Wire template instances

Template instances use exactly the same WIRING syntax as plain instances (§10.2a in the Language Reference):

WIRING
    inst(InputPort := expr, …);   (* bind child inputs *)
    parent_output := inst.OutputPort;  (* forward child output *)
END_WIRING

Dot-assignment inst.Port := expr is not accepted. Use the parenthesis form for inputs.


Use two instantiations of the same template at different sizes

Each argument tuple produces an independent concrete type:

VAR
    v3 : Vec<3>;
    v4 : Vec<4>;
END_VAR
WIRING
    v3(a := p3, b := q3);
    v4(a := p4, b := q4);
    d3 := v3.dot;
    d4 := v4.dot;
END_WIRING

Vec<3> and Vec<4> are distinct types; each has its own proof context, its own generated array sizes, and its own hidden locals after flattening.


Verify a parent that uses templates

No special flags are needed:

lola Dot3.lola --target check

The resolver finds Vec.lola on the search path, monomorphizes Vec<3>, and verifies the full composite program. If Vec.lola is absent, the compiler reports a structure error on the instance declaration line.


Common mistakes

v.a := p in WIRING is rejected. Use v(a := p, b := q); instead.

Wrong number of type arguments. Vec<3, 4> when the template declares <N: UINT> (one parameter) is a compile error: the compiler reports how many arguments were expected.

Template bound references a non-parameter name. ARRAY[0..X-1] when X is a VAR_INPUT (not a type parameter) is rejected. Only type parameters and literals are allowed in template-dep bounds.

Type parameter in wrong position. The <N: UINT> header must appear directly after the FB name; FUNCTION_BLOCK Vec <N: UINT> (with a space) is accepted but <N: UINT> elsewhere in the block is a syntax error.