8. Types
Type names appear in lower case as code (string, vector,
integer); section titles use ordinary title capitalization.
8.11. Storable Types, Nesting, and Recursion
A storable type is any type whose values may be stored in a variable, passed as an argument, returned, or held as a member of an aggregate. Every type in Gazprea is storable except streams, which name I/O endpoints rather than values.
Aggregates may be nested to any depth. An array of any
rank (a matrix is the rank-2 case), a
vector, a
tuple, and a struct may each hold
any storable element or field type, including one another. For example a
vector<S> (for a struct type S), a struct with a tuple field,
and a tuple(S, integer[3][3]) are all well-formed.
Nesting must be acyclic through value types. A
struct or tuple whose fields, directly or transitively, contain a value
of its own type has no finite size and is ill-formed; the compiler must
emit a TypeError (see Errors). A type may, however, refer to
itself through a vector, because a vector is dynamically
sized and stored by indirection:
struct Tree (integer value, vector<Tree> children); // well-formed
struct Bad (integer value, Bad next); // TypeError: infinite size
Note
Implementation. Nested aggregates are laid out and accessed
structurally (a chain of getelementptr in the LLVM dialect); the
vector at a recursion boundary is the sole point of indirection. Flat,
non-nested sequences continue to lower through the tensor/linalg path,
and should be implemented as contiguous blobs of memory, not lists of
lists or structs of arrays pointing to arrays.