View all results

Control Flow

Control flow describes how an FQL script determines which expressions are evaluated, how many times they are evaluated, and when evaluation proceeds.

Most FQL code is evaluated in the order it is written. Control-flow constructs change that linear execution model by introducing branching, iteration, delegation to host values, or suspension until a condition is met.

FQL is expression-oriented, so most control-flow constructs produce values. Their results can be returned, assigned to variables, passed to functions, or composed with other expressions.

Branching with MATCH

A MATCH expression selects one branch from a set of alternatives. Only the selected branch is evaluated.

example.fql
read-only
MATCH status ( "active" => "online", "inactive" => "offline", _ => "unknown", )

Use MATCH when a value should be derived from a known set of cases or conditions.

See Match Expressions.

Iteration with FOR

A FOR expression evaluates its body once for each item in a source collection. It is the primary construct for iterating over arrays, query results, and other iterable values.

example.fql
read-only
FOR n IN [1, 2, 3] RETURN n * 2

The result of a FOR expression is the collection of values returned by its body.

See For Loops.

Composition with subqueries

A subquery wraps a FOR expression in parentheses, allowing its result to be used as a regular value.

example.fql
read-only
LET doubled = (FOR n IN [1, 2, 3] RETURN n * 2)

Subqueries are useful when an intermediate collection needs to be assigned, returned, passed to a function, or embedded inside another expression.

See Subquery Expressions.

Delegation with QUERY

A QUERY expression delegates query execution to a value that supports a query capability. The query itself may use another language or selector syntax, such as CSS.

example.fql
read-only
QUERY `.product .title` IN doc USING css

The runtime does not interpret the query payload directly. Instead, it passes the query to the target value and returns the result produced by that value.

See Query Expressions.

Coordination with DISPATCH and WAITFOR

DISPATCH sends an event or action to a target value. WAITFOR suspends evaluation until an event is observed, a value becomes available, or a condition becomes true.

example.fql
read-only
button <- "click" WAITFOR EVENT "navigation" IN page TIMEOUT 5s

These constructs are commonly used when FQL interacts with external systems, such as browser pages, dynamic documents, or event-driven runtimes.

See Dispatch Expressions and Waitfor Expressions.

Recovering from errors

A recovery tail attaches to an expression and tells the runtime what to do when it fails — return a fallback value, retry the operation, or propagate the error explicitly. The optional chaining operator (?.) handles the common case of accessing a member on a value that may be NONE.

example.fql
read-only
LET title = QUERY ONE `.title` IN doc ON ERROR RETURN "untitled" LET name = user?.name

Recovery tails work on function calls, QUERY, DISPATCH, WAITFOR, and grouped expressions. WAITFOR additionally supports ON TIMEOUT for timeout-specific recovery.

See Error Handling.

Language constructs and host capabilities

Some control-flow constructs are part of the language itself. MATCH, FOR, and subqueries are always available and operate on ordinary FQL values.

Other constructs depend on host capabilities. QUERY, DISPATCH, and WAITFOR EVENT require the target value to provide the corresponding runtime behavior. For example, a document may support querying, a browser element may support dispatching events, and a page may support observing navigation or network events.

WAITFOR condition mode is different: it evaluates an ordinary expression repeatedly until the condition succeeds or the timeout is reached. It does not require the target value to provide an event capability.

If a value does not support the capability required by a control-flow construct, evaluation fails at runtime.

See Value Capabilities and Host Values.

Next steps