Basic Data Flow

Description

A Dinamica EGO model is, at its core, a graph: functors connected through their input and output ports. This is true no matter how the model was authored — built visually in the GUI, or written by hand in EGO Script. Both are just different notations for describing the same underlying graph, and the execution engine schedules functors from that graph, not from the notation used to write it. This page describes how that scheduling works, independently of any particular notation.

Functors and connections

A functor is a processing unit with a fixed set of typed input and output ports. A connection links one functor's output port to another's input port, carrying a value from the first to the second.

In EGO Script, a connection is expressed by giving an output a variable name and reusing that same name as an input elsewhere — see Functors, variables, and binding. In the GUI, the same connection is drawn as a wire between two functor boxes. Either way, what the engine sees is a connection between two ports; the variable name or the wire is only how that connection happens to be written down.

Data dependencies drive execution order

A functor cannot run until every input port it requires has received a value from the functor that produces it. This creates a dependency: whenever functor A's output feeds functor B's input — directly, or through a chain of intermediate connections — B depends on A and cannot start before A finishes.

Two functors that share no such chain have no ordering relationship at all. They may run in any order, or at the same time; nothing about where they sit in a script, or where they're placed on a canvas, has any bearing on this. Execution order is entirely a property of the connection graph, not of the notation used to describe it.

Containers: the second ordering source

Container functors group a nested set of functors so that they execute as a single unit — the container starts, its contents run, then it finishes. This has a consequence beyond simple grouping: a dependency on anything produced *inside* a container is really a dependency on the *whole container*. If functor B consumes a value from something inside container A, B will not start until every functor inside A has finished — not just the specific one that produced the value. See Container functors for how this is expressed in EGO Script.

This makes containers useful even when nothing inside them shares data with anything outside: wrapping two otherwise-independent functors in a container guarantees they run together, in the order the container defines — an ordering that a plain data dependency could never enforce on its own.

Ordering without data: sequence connections

Sometimes two functors, or two containers, need to run in a specific order even though neither produces a value the other needs. For this, some functors expose sequencing-only ports that carry no data of their own — a connection between them exists purely to force an order. This is the same graph mechanism as an ordinary connection; it simply carries nothing. See Sequence ports for the EGO Script syntax.

The one exception: feedback in loops

A loop's running state is usually carried by a mux — a functor with two inputs, an initial value and a feedback value, and one output. The feedback input is deliberately exempt from the rule above: the mux does not wait for the functor that produces the feedback value to run first. Instead, it emits whatever that functor produced on the *previous* iteration. See Carrying and selecting values across iterations for a worked example.

This exemption is what makes loops possible at all. Without it, the functor that computes a loop's next state and the mux that carries it forward would depend on each other in a cycle, and neither could ever be scheduled. By treating the feedback connection as “last iteration's value” rather than “this iteration's value,” the engine breaks the cycle — the same trick a register or flip-flop uses in a clocked circuit to let a signal feed back into its own computation.