A circuit in Escher is a generic data abstraction much like a structure is in JavaScript or Go. When thinking and programming in Escher, circuits will have a meaning dependent on context and/or content. A circuit interpretation will usually utilize a subset of the representational freedoms of a circuit, and will have an intuitive graphical representation.
Here we introduce four basic circuit interpretations — or specializations, if you will — that will also serve us as a vocabulary when discussing Escher in following chapters.
Circuit gate names, recall, can be integers or strings. If a circuit has no links and the gate names are the integers 0, 1, …, K (for some integer K), we call the circuit a series. Series are equivalent to arrays and/or slices in other programming languages, like C and Go. Gate names are slice indices; gate values are slice element values.
For instance, the circuit
Singer { 0 "Dolly" 1 "Rebecca" 2 "Parton" }is analogous (in meaning) to the Go slice:
var Singer = []interface{}{ "Dolly", "Rebecca", "Parton", }
Since series will be frequently input by the programmer, as explained in the syntax section, we have dedicated a shorthand syntax for series circuits that omits the gate names:
Singer { "Dolly" "Rebecca" "Parton" }
More generally than series, when a circuit has no valves/links, we call it a map (previously index), and we view it as a mapping from integers and/or strings to anything else. In this respect, a map is akin in purpose to structures, dictionaries, hash tables and maps in other languages.
ImplicitIntMap { *fully.qualified.Name 123 3.14 } ExplicitIntMap { 3 *fully.qualified.Name 6 @fully.qualified.Name 1 123 } StringMap { directive *fully.qualified.Name integral 123 floating 3.14 }
The gate values of map circuit are analogously called children, and they can be of primitive types (integers, floats, etc.) as well as recursively, they can be other circuits or maps.
TreeCircuit { Trunk { Branches { "Johnny" "Katie" } } Root { Tentacles { "Grandpa" "Grandma" } } }
Such recursive structures of maps, or just trees for short, serve the same purpose as file-systems, namespaces, trees and others: To organize their internal and leaf values in a hierarchical manner, so that each node (internal or leaf) is identifiable by a unique path.
An Escher index is basically a tree circuit, which we interpret as a an absolute (and in future releases also relative) tree containing all circuits/gates. This also associates a unique path to each gate, which we shall call address of a value relative to a given index.
For instance, the address of "Grandma"
relative to the index
Tree
would be
{ Root Tentacles 1 }(Note that addresses are represented by series circuits.)
Directives are a key building block of circuit programs (described next and in following sections). A directive is a pair of a string-valued verb and a target address. Directives are represented as a single circuit, wherein the empty-string gate holds the verb, while the number gates hold the components of the address. For instance,
{ "" "*" 0 Root 1 Tentacles 2 1 }
This circuit holds the verb value "*"
and the address whose components
are Root
, Tentacles
and 1
, in that order.
There are only two types of verbs, signified by the verb values "*"
and "@"
, whose meaning is explained in later sections.
We call these verbs materialize and recall, respectively, while their
single-characters values, "*"
and "@"
, are a design
choice of expediency.
Due to the ubiquitous use of directives in circuit programs, directives can be written using the dedicated syntactic sugar:
*Root.Tentacles.1
Programs are circuits that describe executable systems. Their meaning and use is explained in a dedicated section. Here we describe their circuit structure.
The gates of program circuits ultimately represent independently executing services, which are interconnected according to the link pattern of the circuit.
Gate values designate the processing logic — i.e. they codify the service type — while gate names are used solely as identifiers, needed in the description of the circuit links.
Gate values can be of any kind: integer, float, complex, string or circuit. Often gate values will be directive circuits, in which case they can be written using the abbreviated syntax described earlier.
Circuit links are allowed only between gate names, defined within the circuit or the empty-string gate name.
The empty-string gate name represents an implicit “enclosing” or “parent” circuit we call super gate. In particular, program circuits are not allowed to use a vector with the empty-string name.
Links whose endpoints are connected to the same gate name are allowed, as long as they connect into different valve names.
Here is an example of a valid program circuit:
{ tkr *time.Ticker sum *math.Sum interval 1e9 tkr:Duration = interval: tkr: = sum:Sum sum:X = :Phase sum:Y = *e.Show }
And the corresponding symbolism: