Wherever an item type can be used (for example, in the type signature of a function or variable,
or in an
instance of expression), Saxon allows a tuple type to appear. The syntax is:
"tuple" "(" fieldName (":" sequenceType)? ("," fieldName (":" sequenceType)? )* ")"
fieldName is an NCName. Whitespace is advisable before or after the colon.
tuple(ssn: xs:string, emp: element(employee))
A tuple type is essentially a way of defining a more
precise type for maps. The first example will be satisfied by any map that has an entry whose key is "ssn" and whose
value is a string, plus an entry whose key is "emp" and whose value is an
employee element. The second
example matches any map with entries having the keys "ssn" and "emp", regardless of the types of the values.
More formally, a value
M is an instance of a tuple type
tuple(N1:T1, N2:T2, ...) (where
Tn defaults to
item()* if not specified) if
and only if:
M is a map
For every (
T) pair in the tuple definition, the expression
map:contains(M, N) and map:get(M, N) instance of Treturns true.
That is, for every field defined in the tuple definition, the map must contain an entry whose key matches the field name and whose value matches the corresponding type. If the allowed type for an entry allows an empty sequence, the entry must still be present in the map.
Using tuples makes stronger type checking possible. With a general-purpose map, any atomic value can be
supplied as a key, and the
map:get() function (or a dynamic call on the map as a function) returns
an empty sequence if the entry is not present. With tuples, however, supplying a key value that is not a string,
or that is not one of the known field names, results in a static type error if it can be detected at compile time.
$T is known to be a tuple type, then the type of an expression such as
can be statically inferred, which again enables better error detection and better optimization.
Tuple types are useful where maps are used to hold information with a regular structure; for example when a function accepts maps as input or returns maps as output, declaring the argument or result type as a tuple type often gives better information about the expected contents of the map.
A map that contains additional entries beyond those defined in the tuple type still conforms to the type (so if the expected
type of a function argument is
tuple(a: xs:integer, b: xs:integer), then you can supply any
map that contains these two fields, even if it also contains others); however,
static references to such entries will result in a type error.
Saxon does not currently attempt to make subtyping inferences about tuple types, so for the time being it is best to avoid using them within the signatures of higher-order functions.