# Tuple

## Overview

A lightweight sequence type mainly for use as keys in a map or as elements of a set.

Examples of usage:

```> tuple = sano.makers.tuple
> t = tuple(1,2,3); print(t)
(1, 2, 3)
> print(t == tuple(1, 2, 3))
true
> print(t == tuple(1, 2))
false
> for e in t:iter() do print(e) end
1
2
3
> a, b, c = t:unpack() -- built-in unpack(t) has same effect
> print(a, b, c)
123
> hashset = sano.makers.hashset
> tuples = hashset(t, tuple(8,7,6))
> print(tuples:contains(tuple(8, 7, 6)))
true```

It's possible to give any table tuple-like powers simply by setting its metatable to be Tuple, for instance:

```> t = {1,2,3,4}
> print(t)
table: 0x82cb810
> setmetatable(t, Tuple)
> print(t)
(1, 2, 3, 4)
> h = hashset{tuple(1,2,3,4)}
> print(h:contains(t))
true
> setmetatable(t, nil) -- restore back to normal
> print(h:contains(t))
false```

Tuples are ordered lexicographically in the obvious way, for example:

`(1,1) <= (1,1), (1,2,2) < (1,2,3), () < (1), (1,2,1) < (1,3), etc.`

More precisely, if a = (a1, a2, ..., aN) and b = (b1, b2, ..., bN), then a < b if:

```b1 > a1
OR
b1 == a1, b2 == a2, ..., bK == aK, bK+1 > aK+1 (b is greater than a)```

If a and b have different sizes, the smaller Tuple will be ordered before the larger if pairwise comparisons do not reveal an ordering.

## Summary

 `make` Identical behavior to Tuple:new(), except that if just one argument is passed, it is assumed to be *iterable* and the elements of the iteration are added to the Tuple. `new` Returns a newly constructed Tuple containing all elements passed as arguments to this method. `__eq` Returns true if both Tuples have the same size and contain the same elements in the same order. `__hash` Returns a number that will be used as the hash code when this Tuple is stored in a HashMap or HashSet. `__lt` Returns true if this Tuple is lexicographically less than other. `iter` Returns an iterator over the elements in this Tuple. `rehash` Recompute and return the hash value for this Tuple. `size` Returns the number of elements in this tuple. `test` Unit test. `unpack` Wrapper around built-in unpack method.

## Detail

### `Tuple:make(...)`

Identical behavior to Tuple:new(), except that if just one argument is passed, it is assumed to be iterable and the elements of the iteration are added to the Tuple.

Example: Tuple:make(iter.count(3)) == Tuple:make{1,2,3} == Tuple:make(1,2,3)

### `Tuple:new(...)`

Returns a newly constructed Tuple containing all elements passed as arguments to this method.

It is perfectly fine to pass zero arguments (this creates an empty tuple) or one argument (this creates a tuple containing just that argument)

Examples:

```> print( Tuple:new(1,2,3) )
(1, 2, 3)
> print( Tuple:new(1) )
(1)
> print( Tuple:new() )
()```

### `Tuple:__eq(other)`

Returns true if both Tuples have the same size and contain the same elements in the same order.

### `Tuple:__hash()`

Returns a number that will be used as the hash code when this Tuple is stored in a HashMap or HashSet.

The value is cached in the field self.hash. Tuples are intended to be used as immutable objects (otherwise, use Vector). Although there is nothing stopping a determined soul from modifying a Tuple, if it is being used as a key in a map, this will result in the Tuple being stored in the wrong bucket.

See HashMap and SkipMap for more information on using Tuples or other composite objects as keys.

In keeping with the contract of the __hash metamethod Tuple objects that are equal return the same hash value.

### `Tuple:__lt(other)`

Returns true if this Tuple is lexicographically less than other.

If a = (a1, a2, ..., aN) and b = (b1, b2, ..., bN), then a < b iff:

```b1 > a1
OR
b1 == a1, b2 == a2, ..., bK == aK, bK+1 > aK+1 (b is greater than a)```

If a and b have different sizes, the smaller Tuple will be ordered before the larger if pairwise comparisons do not reveal an ordering.

Examples: (1,1) <= (1,1), () <= (1), (1,2,1) <= (1,3)

The evaluation is 'short-circuit' and halts as soon as there is enough information to determine the ordering.

Also see ordering.lexicographical.

### `Tuple:__tostring()`

Returns a string of the form "(e1, e2, ..., eN)"

### `Tuple:iter()`

Returns an iterator over the elements in this Tuple.

### `Tuple:rehash()`

Recompute and return the hash value for this Tuple.

Since Tuples are intended mostly to be used as immutable objects, this method shouldn't normally be called (once the hash value is computed once, it shouldn't need to be computed again).

### `Tuple:size()`

Returns the number of elements in this tuple.

If the tuple, t, has no holes, then #t will return the same result as t:size().

Unit test.

### `Tuple:unpack()`

Wrapper around built-in unpack method.

Given a Tuple, t, t:unpack() and unpack(t) are equivalent, since t is just a table with a few convenience methods.