We describe here two of the most commonly utilized information flow reflexes,
Fork
and Star
. They are by no means the only
such, however they demonstrate the spirit of designing information flow
control primitives. We encourage the reader to eventually review their short
implementations to realize the huge variety of other possible designs.
The star is the simplest flow reflex. It accepts any number of connected valves and ignores their specific names.
When a value is received on any one of its connected valves, the star reflex forwards that value to all other connected valves.
Every forwarded value is emitted (i.e. sent) to its respective valve on a dedicated goroutine. Therefore the star reflex never blocks.
An example usage:
{ star *Star one 1 star:X = one: star:Y = *Show star:Z = *Show star:W = *Show }
When this circuit is materialized, the constant 1
will be emitted from gate one
to valve X
of gate star
. The star
gate will then forward the value
to each of the valves Y
, Z
and W
in parallel. Consequently
it will be printed on the standard output three times by the receiving *Show
reflexes.
In our experience, the fork is the most commonly used synchronization primitive in Escher. It requires that the distinguished empty-string valve be connected, as well as one or more freely-named (string or integer) other valves.
Fork can be described as two entirely independent reflexes, let us call them merge and split, embodied in one.
Whenever a value W is received on the empty string valve of a fork, the reflex will process it using the split logic. The received value must be of type circuit. For every valve whose name N is not the empty string, fork will send the value of the gate named N from circuit W to that valve.
Take for instance this program:
{ f *Fork f: = { x "Hello" y "World" z "Foo" } f:x = *Show f:y = *Show }
The values "Hello"
and "World"
will be sent
to and printed by the connected *Show
reflexes. Whereas the value "Foo"
will be ignored.
Fork will wait until one value is received on each of its non-empty-string valves. When this condition is met, it will merge all such values as the gates of a single circuit, wherein gate names follow respective valve names, and will send this circuit out to its empty string valve.
Note that in the merge direction fork reflexes act as powerful synchronization primitives. They effectively wait, blocking any other receptions on the non-empty-string valves, until one value is available on each such valve. Subsequently these values are packed into a single circuit and sent out.
Consider the following program, for instance:
{ f *Fork f: = *Show f:x = "New" f:y = "York" }
Fork will wait until "New"
and "York"
are received
on valves x
and y
, respectively. Then the value
{ x "New" y "York" }
will be sent to and printed by the *Show
reflex.