--- alias: user-guide-automation-controller-workflow-controlflow-expressions render_macros: false tags: - automation - connect iot description: "How Control Flow tasks read the outputs of earlier tasks through MathJS expressions, when the expressions are evaluated, and which converter functions they can call" --- # Control Flow Expressions In a `Control Flow` workflow, tasks are not linked. A task reads the outputs of earlier tasks through expressions written between `{{` and `}}` in its input and output rows. The engine evaluates each expression with [MathJS](https://mathjs.org/), not JavaScript. ## Reading a Value An expression names a task with `$` and its block name, followed by the output: `{{ $. }}`. For an output name with spaces, write `{{ $[""] }}`. | Written | Reads | |---|---| | `$.` | An output of a task that already ran in the same branch or in an enclosing branch. | | `$this.` | In an output row, a value that the task itself emitted. | | `$scope.` | A value of an enclosing branch: the `For` iterator, the `Foreach` item, the `Try..Catch` error message, a function argument, or a value written by an output row named `$scope.`. | | `$global.` | A value written by an output row named `$global.`. The controller keeps it after the branch ends. | Table 1: Names an expression can read The name after `$` is the block name, stored in the workflow as the task `name`, not the block ID. The designer gives a new block a default name made of the task name, `_`, and four hexadecimal characters. A name that matches no task that already ran in the branch or in an enclosing branch fails the expression with `Undefined symbol $`, and the branch ends. An output that the task did not emit gives no value. A row that holds only one expression passes the value with its own type, and text around expressions makes the row a text, so `File {{ $onFile.FileName }}: {{ $onFile.Size }} bytes` needs no operator. ## When Expressions Are Evaluated - Settings - applied when the branch that holds the task is built, before any task of the branch runs. An expression in a setting reaches the task as text, unless the task evaluates that setting itself (Table 2). When a task has an input with the same name as a setting, write the expression in the input row. - Input rows - evaluated just before the task runs. When a row fails, the controller logs `Failed to emit values to task '' because ''` and the branch ends. - Output rows - evaluated just after the task emits. When a row fails, the controller logs `Failed to process outputs from task '' because ''`. | Task | Setting that the task evaluates when it runs | |---|---| | [[user-guide-automation-task-core-condition]] | `condition` of each branch | | [[user-guide-automation-task-core-try-catch]] | `variableName` of the `catch` branch | | [[user-guide-automation-task-core-throw]] | `Error Text` | | [[user-guide-automation-task-core-logmessage]] | `Default Message`, in `RawText` mode | Table 2: Settings that accept an expression ## Expression Language MathJS looks like JavaScript in places, but it is not: - Combine tests with `and`, `or`, and `not (...)`. `&&`, `||`, and `!` fail with `Failed to parse expression '': Value expected (char )`. - Compare with `==` and `!=`, and write text in double quotes, for example `"today's total"`. - Call a method on a value, for example `{{ $readFile.Content.split(",") }}`. MathJS has no `split` function, so `split(...)` fails with `Undefined function split`. - Build an object in a row, for example `{{ {"FileName": $onFile.FileName} }}`. - Count array positions from 0: `{{ $readList.Items[0] }}` is the first item. - Write the escape `"\n"` to split text into lines. A line break entered in a row reaches the evaluator as a space. A condition, and a row of type `Boolean`, convert the result to a Boolean: `true`, `t`, `yes`, `y`, and `1`, in any case, are true, and any other value is false. Compare the value, `{{ $onFile.Size > 0 }}`, instead of testing it bare. In `Control Flow`, the Condition task takes the place of [[user-guide-automation-task-core-switch]], which is available only in `Data Flow`. ## Row Types Each row has a data type, and the engine converts the result of the row to it: | Type | Conversion | |---|---| | `Any` | None. Text around expressions is joined with each value written as JSON, so a text value keeps its quotes. | | `String` | The value as text. An object becomes `[object Object]`; use `stringify` to write it as JSON. | | `Integer`, `Long`, `Decimal` | A number. Text that does not start with a number fails with `Unable to convert '' to integer` or `to decimal`. | | `DateTime` | A date, from a date text or from an epoch number in seconds or milliseconds. | | `Object` | An object or an array as it is. Text is parsed as JSON, so plain text such as `reading.csv` fails as not valid JSON. | Table 3: Conversion by row type ## Converter Functions A converter runs as a function inside an expression. When the controller prepares its first `Control Flow` workflow, it registers as functions the converters of its tasks libraries that declare an input type, an output type, and parameters, and logs each one as `Registering function: `. The core tasks package registers the following: | Function | Value and result | Parameters, in order | |---|---|---| | `stringify` | `object` to `string` | `spaces` | | `stringToBase64` | `string` to `string` | None | | `stringToEntityInstance` | `string` to `object` | `entityType`, `identifier`, `customType` | | `jsonata` | `any` to `any` | `expression` | | `isEmpty` | `any` to `any` | `resultType` | | `epochToDateTime` | `any` to `string` | None | | `now` | `any` to `string` | `format`, `timezone` | | `toTime` | `string` to `long` | None | Table 4: Converter functions Pass the value first and the parameters after it, for example `{{ jsonata($readFile.Content, "orders[0].id") }}`. The engine converts the value to the value type before the call, and the result to the result type after it. So `stringToBase64(42)` encodes the text `"42"`, and `stringify` parses a text value as JSON before writing it. Any other converter name fails with `Undefined function `. For the parameters, see [[user-guide-automation-converters-index]]. ## Common Mistakes - Block ID instead of block name - the expression fails with `Undefined symbol`, as it does after a block is renamed and the expressions that read it are not. - Reading a task placed later, in a sibling branch, or in a branch that has ended - write the value to `$global.` or `$scope.` instead. - A bare value as a condition - compare it, so that the expression gives a Boolean. - An expression in a setting that the task does not evaluate - the task receives the text as written. - Plain text in an `Object` row - type the row `String`. - `{{ }}` in the expression of the [[user-guide-automation-task-core-expressionevaluatorgeneric]] task - write that expression over the input names of the task, without `{{ }}` and without `$`.