Escher A language for connecting technologies using pure metaphors

Information flow reflexes

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.

Star reflex

(The implementation can be found in pkg/faculty/basic/star.go.)

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 Go routine. Therefore, the star reflex never blocks.

An example usage:

{
	star *e.Star
	one 1

	star:X = one:
	star:Y = *e.Show
	star:Z = *e.Show
	star:W = *e.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 *e.Show reflexes.

Fork reflex

(The implementation can be found in pkg/be/union.go.)

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.

Split direction

Whenever a value W (must be of type Circuit) is received on the empty string valve of a fork, the reflex will process it using the split logic. 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 *e.Fork
	f: = {
		x "Hello"
		y "World"
		z "Foo"
	}
	f:x = *e.Show
	f:y = *e.Show
}

The values "Hello" and "World" will be sent to and printed by the connected *e.Show reflexes. Whereas the value "Foo" will be ignored.

Merge direction

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 *e.Fork
	f: = *e.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 *e.Show reflex.