Tuples
A tuple is a sequence of attributes, and an attribute is a named value.
For example, the tuple { sym="Fe", no=26 }
consists
of two attributes sym="Fe"
and no=26
.
The type for this tuple is tuple<rstring sym, int32 no>
.
Tuples are similar to database rows in that they have a sequence of
named and typed attributes. Tuples differ from objects in Java™ or C++ in that they do not have methods.
You can access the attributes of a tuple with dot notation. For example,
given a tuple t
of type tuple<rstring
sym, int32 no>
, the expression t.sym
yields
the sym
attribute.
Attributes within a tuple
are ordered: tuple<int32 x, int32 y>
and tuple<int32
y, int32 x>
are two different types. But this ordering is
hidden at the language level, and can be changed by the runtime implementation
for optimization. The only way a program can depend on the declaration
order of attributes is in source operators that read from a text file formatted
as comma-separated values (csv).
Tuple types can extend other tuple types, by adding more attributes. For example:
type Loc2d = tuple<int32 x, int32 y>;
type Loc3d = Loc2d, tuple<int32 z>;
The resulting type Loc3d
is equivalent
to tuple<int32 x, int32 y, int32 z>
. In tuple
extension, if the tuples have an attribute with the same name and
type, the resulting tuple contains that attribute once, in the position
of its leftmost occurrence. It is an error for the tuples in tuple
extension to have attributes with the same name but different types.
In tuple extension, the identifier can also be the name of a stream as a shorthand for the type of the tuples in that stream. For example:
composite Main {
type LocWithId = LocStream, tuple<rstring id>;
graph stream<int32 x, int32 y> LocStream = Beacon() {}
}
The resulting type LocWithId
is
equivalent to tuple<int32 x, int32 y, rstring id>
.
The syntax for tuple types is:
tupleType ::= ‘tuple' ‘<' tupleBody ‘>'
tupleBody ::= attributeDecl+, # attributes
| ( ID | tupleType )+, # tuple type extension
attributeDecl ::= type ID
In other words, the body of the tuple type either consists of a comma-separated list of attribute declarations, or a comma-separated list of tuple types, either by name or written in-place. This extension syntax deviates from the inheritance syntax in object-oriented languages like Java™ because it needs to be light weight and nestable. Tuple types can be arbitrarily nested. In other words, their attributes can be of any type, including other composite types, even other tuple types. For example:
type Loc2d = tuple<int32 x, int32 y>;
type Sensor = tuple<rstring color, tuple<Loc2d, tuple<int32 z>> loc>;
After the type is extended, Loc2d
with
a z
attribute, and using the whole thing as a loc
attribute,
the resulting type Sensor
is tuple<rstring
color, tuple<int32 x, int32 y, int32 z> loc>
. For example,
given a variable Sensor s
, the expression s.loc.z
accesses
the z-coordinate.
The explicit tuple<...>
type constructor
can be omitted at the top level of a type definition. For more information,
see Type definitions. That means that the previous example can also
be written like:
type Loc2d = int32 x , int32 y ;
type Sensor = rstring color, tuple<Loc2d, tuple<int32 z>> loc;
The literal syntax for tuple values is as follows:
tupleLiteral ::= ‘{' ( ID ‘=' expr)*, ‘}' # e.g. { x=1, y=2 }
The
empty tuple literal, {}
, is only valid in casts or
initialization. For example, mutable Loc3d myLocation = {};
zero-initializes myLocation
,
equivalent to mutable Loc3d myLocation = {x=0, y=0, z=0};
.