7.5. Tuples

A tuple is a way of grouping multiple values with potentially different types into an aggregate data structure. Tuples are similar to structs, except that a tuple’s fields are indexed instead of named. Tuples are often used to return multiple values from a function or procedure. Any type may be stored within tuples except :ref:`streams`<sec:streams> and other tuples.

7.5.1. Declaration

A tuple value is declared with the keyword tuple followed by a parentheses-surrounded, comma-separated list of types. The list must contain at least two elements. Tuples are mutable. For example:

tuple(integer, real, integer[10]) t1;
tuple(character, real, character[256], real) t2;

Note that while each tuple declaration defines a new type, the tuple type is not named explcitly. Rather, it has a type signature (T1, T2, ...), where T1, T2 are the types of its members. The number of fields in a tuple must be known at compile time. This includes instances of type inference, where a variable is declared without an explicit type signature using var or const . In this case, the variable must be initialised immediately with a literal whose type is known at compile time.

7.5.2. Access

The elements in a tuple are accessed using dot notation. Dot notation can only be applied to tuple variables and not tuple literals. Dot notation means an identifier followed by a period and then a literal integer. Spaces are not allowed between elements in dot notation. Field indices start at one, not zero. For example:

t1.1
t2.4

Tuple access can be used either to retrieve the element value for an expression or to assign a new value to the element.

y = x + t1.1;     // Allowed
t1.1 = type-expr; // Allowed

7.5.3. Literals

A tuple literal is constructed by grouping values together between parentheses in a comma separated list. For example:

tuple(integer, character[5], integer[3])  my_tuple = (x, "hello", [1, 2, 3]);
var my_tuple = (x, "hello", [1, 2, 3]);
const your_tuple = (x, "hello", [1, 2, 3]);
tuple(integer, real, integer[10]) tuple_var = (1, 2.1, [i in 1..10 | i]);

7.5.4. Operations

The following operations are defined on tuple values. In all of the usage examples tuple-expr means some expression yielding tuples with the same type signature, while int_lit is an integer literal as defined in Integer Literals and tuple-inst is the name of tuple instance as defined in Identifiers.

Class

Operation

Symbol

Usage

Associativity

Access

dot

.

tuple-inst.int_lit

left

Comparison

equals

==

tuple-expr == tuple-expr

left

not equals

!=

tuple-expr != tuple-expr

left

Note that in the above table tuple-expr may refer to a variable for access. Accessing a literal could be replaced immediately with the scalar inside the tuple literal, however, tuple-expr may refer to a literal in comparison operations to enable shorthand like this:

if ((a, b) == (c, d)) { }

Comparisons are performed pairwise. Two tuples are equal when for every expression pair, the equality operator returns true. Two tuples are unequal when one or more expression pairs are unequal or the types mismatch. This table describes how the comparisons are completed, where t1 and t2 are tuple yielding expressions including literals:

Operation

Meaning

t1 == t2

t1.1 == t2.1 and ... and t1.n == t2.n

t1 != t2

t1.1 != t2.1 or ... or t1.n != t2.n

7.5.5. Type Casting and Type Promotion

To see the types that tuple may be cast and/or promoted to, see the sections on Type Casting and Type Promotion, respectively.