Was this page helpful?

Parameters and State Variables

This page is showing examples in the target language CC++PythonTypeScriptRust. You can change the target language in the left sidebar.

Parameter Declaration

A reactor class definition can parameterized as follows:

reactor <class-name>(<param-name>:<type>(<expr>), ...) {
    ...
}

Each parameter has a type annotation, written :<type>, where <type> has one of the following forms:

  • An identifier, such as int, possibly followed by a type argument, e.g. vector<int>.
  • An array type type[] and type[integer].
  • The keyword time, which designates a time value.
  • A code block delimitted by {= ... =}, where the contents is any valid type in the target language.
  • A pointer type, such as int*.

Types ending with a * are treated specially by the C target. See the Target Language Details.

To use strings conveniently in the C target, the “type” string is an alias for {=const char*=}.

For example, {= int | null =} defines nullable integer type in TypeScript.

reactor <class-name>(<param-name>(<expr>), ... ) {
    ...
}

Each parameter must have a default value, written (<expr>). An expression may be a numeric contant, a string enclosed in quotation marks, a time value such as 10 msec, a list of values, or target-language code enclosed in {= ... =}, for example. See Expressions for full details on what expressions are valid.

For example, the Double reactor on the previous page can be replaced with a more general parameterized reactor Scale as follows:

target C;
reactor Scale(factor:int(2)) {
    input x:int;
    output y:int;
    reaction(x) -> y {=
        lf_set(y, x->value * self->factor);
    =}
}

target Cpp;

reactor Scale(factor:int(2)) {
    input x:int;
    output y:int;
    reaction(x) -> y {=
        y.set(factor * *x.get());
    =}
}

target Python;
reactor Scale(factor(2)) {
    input x;
    output y;
    reaction(x) -> y {=
        y.set(x.value * self.factor)
    =}
}
target TypeScript;
reactor Scale(factor:number(2)) {
    input x:number;
    output y:number;
    reaction(x) -> y {=
        if (x !== undefined) y = x * factor
    =}
}

target Rust;
reactor Scale(factor:u32(2)) {
    state factor(factor);
    input x:u32;
    output y:u32;
    reaction(x) -> y {=
        let x = ctx.get(x).unwrap();
        ctx.set(y, x * self.factor);
    =}
}

This reactor, given any input event x will produce an output y with value equal to the input scaled by the factor parameter. The default value of the factor parameter is 2, but this can be changed when the Scale reactor is instantiated.

Notice how, within the body of a reaction, the code accesses the parameter value. This is different for each target language. In the C target, a self struct is provided that contains the parameter values.

State Declaration

A reactor declares a state variable as follows:

    state <name>:<type>(<value>);

The type can any of the same forms as for a parameter.

    state <name>(<value>);

The <value> is an initial value and, like parameter values, can be given as an expression or target language code with delimiters {= ... =}. The initial value can also be given as a parameter name. The value can be accessed and modified in a target-language-dependent way as illustrated by the following example:

target C;
reactor Count {
    state count:int(0);
    output y:int;
    timer t(0, 100 msec);
    reaction(t) -> y {=
        lf_set(y, self->count++);
    =}
}

target Cpp;

reactor Count {
    state count:int(0);
    output y:int;
    timer t(0, 100ms);

    reaction(t) -> y {=
        y.set(count++);
    =}
}

target Python;
reactor Count {
    state count(0);
    output y;
    timer t(0, 100 msec);
    reaction(t) -> y {=
        y.set(self.count)
        self.count += 1
    =}
}

target TypeScript
reactor Count {
    state count:number(0)
    output y:number
    timer t(0, 100 msec)
    reaction(t) -> y {=
        y = count++
    =}
}

target Rust;
reactor Count {
    state count:u32(0);
    output y:u32;
    timer t(0, 100 msec);
    reaction(t) -> y {=
        ctx.set(y, self.count);
        self.count += 1;
    =}
}

This reactor has an integer state variable named count, and each time its reaction is invoked, it outputs the value of that state variable and increments it. The reaction is triggered by a timer, discussed in the next section.

Lingua Franca is an open source project. Help us improve these pages by sending a Pull Request

Contributors to this page:
Eeal  (25)
SBSoroush Bateni  (3)
ARAnirudh Rengarajan  (3)
MLMarten Lohstroh  (1)

Last updated: May 27, 2022