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.