Tuple(*T) - Crystal 1.20.1

# struct Tuple(*T)

- Tuple(*T)
- Value
- Object

##
Overview

A tuple is a fixed-size, immutable, stack-allocated sequence of values of possibly different types.

You can think of a `Tuple` as an immutable `Array` whose types for each position are known at compile time.

A tuple can be created with the usual `.new` method or with a tuple literal:

    tuple = {1, "hello", 'x'} # Tuple(Int32, String, Char)
    tuple[0]                  # => 1
    tuple[1]                  # => "hello"
    tuple[2]                  # => 'x'

See `Tuple` literals in the language reference.

The compiler knows what types are in each position, so when indexing a tuple with an integer literal the compiler will return the value in that index and with the expected type, like in the above snippet. Indexing with an integer literal outside the bounds of the tuple will give a compile-time error.

Indexing with an integer value that is only known at runtime will return a value whose type is the union of all the types in the tuple, and might raise `IndexError`.

Indexing with `#[]?` does not make the return value nilable if the index is known to be within bounds:

    tuple = {1, "hello", 'x'}
    tuple[0]?         # => 1
    typeof(tuple[0]?) # => Int32

Indexing with a range literal known at compile-time is also allowed, and the returned value will have the correct sub-tuple type:

    tuple = {1, "hello", 'x'} # Tuple(Int32, String, Char)
    sub = tuple[0..1]         # => {1, "hello"}
    typeof(sub)               # => Tuple(Int32, String)

`Tuple`'s own instance classes may also be indexed in a similar manner, returning their element types instead:

    tuple = Tuple(Int32, String, Char)
    tuple[0]   # => Int32
    tuple[3]?  # => nil
    tuple[1..] # => Tuple(String, Char)

Tuples are the preferred way to return fixed-size multiple return values because no memory is needed to be allocated for them:

    def one_and_hello
      {1, "hello"}
    end

    one, hello = one_and_hello
    one   # => 1
    hello # => "hello"

Good examples of the above are `Number#divmod` and `Enumerable#minmax`.

Tuples can be splat with the `*` operator and passed to methods:

    def multiply(string, value)
      string * value
    end

    tuple = {"hey", 2}
    value = multiply(*tuple) # same as multiply tuple[0], tuple[1]
    value                    # => "heyhey"

Finally, when using a splat argument in a method definition its type will be a tuple of the call arguments:

    def splat_test(*args)
      args
    end

    tuple = splat_test 1, "hello", 'x'
    tuple.class # => Tuple(Int32, String, Char)
    tuple       # => {1, "hello", 'x'}

##
Included Modules

- Comparable(Tuple(*T))
- Indexable(Union(*T))

##
Defined in:

json/to_json.cr
tuple.cr
yaml/to_yaml.cr

##
Constructors

- .from(array : Array) : self

  Creates a tuple from the given array, with elements casted to the given types.

- .new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
- .new(pull : JSON::PullParser)
- .new(*args : *T)

  Creates a tuple that will contain the given values.

##
Class Method Summary

- .[](index : Int)

  Returns the element type at the given index.

- .[](range : Range)

  Returns all element types that are within the given range.

- .[]?(index : Int)

  Returns the element type at the given index or `nil` if out of bounds.

- .types

  Returns the types of this tuple type.

##
Instance Method Summary

- #+(other : Tuple)

  Returns a tuple that contains `self`'s elements followed by other's elements.

- #<=>(other : self)

  The comparison operator.

- #<=>(other : Tuple)

  The comparison operator.

- #==(other : self)

  Returns `true` if this tuple has the same size as the other tuple and their elements are equal to each other when compared with `#==`.

- #==(other : Tuple)

  Returns `true` if this tuple has the same size as the other tuple and their elements are equal to each other when compared with `#==`.

- #==(other)

  Returns `false`.

- #===(other : self)

  Returns `true` if case equality holds for the elements in `self` and other.

- #===(other : Tuple)

  Returns `true` if `self` and other have the same size and case equality holds for the elements in `self` and other.

- #[](index : Int)

  Returns the element at the given index.

- #[](range : Range)

  Returns all elements that are within the given range.

- #[]?(index : Int)

  Returns the element at the given index or `nil` if out of bounds.

- #at(index : Int)

  Returns the element at the given index or raises IndexError if out of bounds.

- #at(index : Int, &)

  Returns the element at the given index or the value returned by the block if out of bounds.

- #clone

  Returns a tuple containing cloned elements of this tuple using the `#clone` method.

- #each(& : Union(*T) -> ) : Nil

  Yields each of the elements in this tuple.

- #first

  Returns the first element of this tuple.

- #first?

  Returns the first element of this tuple, or `nil` if this is the empty tuple.

- #from(array : Array)

  Expects to be called on a tuple of types, creates a tuple from the given array, with types casted appropriately.

- #hash(hasher)

  See `Object#hash(hasher)`

- #inspect : String

  Same as `#to_s`.

- #last

  Returns the last element of this tuple.

- #last?

  Returns the last element of this tuple, or `nil` if this is the empty tuple.

- #map(& : Union(*T) -> )

  Returns a new tuple where elements are mapped by the given block.

- #map_with_index(offset = 0, &)

  Like `#map`, but the block gets passed both the element and its index.

- #pretty_print(pp) : Nil
- #reduce(memo, &)

  Just like the other variant, but you can set the initial value of the accumulator.

- #reduce(&)

  Combines all elements in the collection by applying a binary operation, specified by a block, so as to reduce them to a single value.

- #reduce?(&)

  Similar to `#reduce`, but instead of raising when the input is empty, return `nil`

- #reverse

  Returns a new tuple where the elements are in reverse order.

- #reverse_each(& : Union(*T) -> )

  Yields each of the elements in this tuple in reverse order.

- #size

  Returns the number of elements in this tuple.

- #to_a : Array(Union(*T))

  Returns an `Array` with all the elements in the tuple.

- #to_a(& : Union(*T) -> U) forall U

  Returns an `Array` with the results of running block against each element of the tuple.

- #to_json(json : JSON::Builder) : Nil
- #to_s(io : IO) : Nil

  Appends a string representation of this tuple to the given `IO`.

- #to_static_array : StaticArray

  Returns a `StaticArray` with the same elements.

- #to_yaml(yaml : YAML::Nodes::Builder) : Nil
- #unsafe_fetch(index : Int)

  Returns the element at the given index, without doing any bounds check.

### Instance methods inherited from module `Comparable(Tuple(*T))`

<(other : T) : Bool <, <=(other : T) <=, <=>(other : T) <=>, ==(other : T) ==, >(other : T) : Bool >, >=(other : T) >=, clamp(min, max)
clamp(range : Range) clamp

### Instance methods inherited from module `Indexable(Union(*T))`

[](index : Int) [], []?(index : Int) []?, bsearch(& : Union(T) -> _) bsearch, bsearch_index(& : Union(T), Int32 -> _) bsearch_index, cartesian_product(*others : Indexable) cartesian_product, combinations(size : Int = self.size) combinations, dig(index : Int, *subindexes) dig, dig?(index : Int, *subindexes) dig?, each(& : Union(T) -> )
each
each(*, start : Int, count : Int, & : Union(T) -> )
each(*, within range : Range, & : Union(T) -> ) each, each_cartesian(*others : Indexable, &)
each_cartesian(*others : Indexable) each_cartesian, each_combination(size : Int = self.size, reuse = false, &) : Nil
each_combination(size : Int = self.size, reuse = false) each_combination, each_index(& : Int32 -> ) : Nil
each_index
each_index(*, start : Int, count : Int, &) each_index, each_permutation(size : Int = self.size, reuse = false, &) : Nil
each_permutation(size : Int = self.size, reuse = false) each_permutation, each_repeated_combination(size : Int = self.size, reuse = false, &) : Nil
each_repeated_combination(size : Int = self.size, reuse = false) each_repeated_combination, empty? : Bool empty?, equals?(other : Indexable, &) : Bool
equals?(other, &) equals?, fetch(index : Int, &)
fetch(index, default) fetch, find(if_none, _offset offset : Int, & : Union(T) -> )
find(if_none = nil, *, offset : Int, & : Union(T) -> ) find, find!(offset : Int = 0, & : Union(T) -> ) find!, first(&) first, hash(hasher) hash, index(object, offset : Int = 0)
index(offset : Int = 0, & : Union(T) -> ) index, index!(obj, offset : Int = 0)
index!(offset : Int = 0, & : Union(T) -> ) index!, join(separator : String | Char | Number = "") : String join, last : Union(T)
last(&) last, last? : Union(T) | Nil last?, permutations(size : Int = self.size) : Array(Array(Union(T))) permutations, repeated_combinations(size : Int = self.size) : Array(Array(Union(T))) repeated_combinations, reverse_each(& : Union(T) -> ) : Nil
reverse_each reverse_each, rindex(value, offset = size - 1)
rindex(offset = size - 1, & : Union(T) -> ) rindex, rindex!(value, offset = size - 1)
rindex!(offset = size - 1, & : Union(T) -> ) rindex!, sample(n : Int, random : Random | Nil = nil) : Array(Union(T))
sample(random : Random | Nil = nil) sample, size size, to_a(& : Union(T) -> U) : Array(U) forall U to_a, unsafe_fetch(index : Int) unsafe_fetch, values_at(*indexes : Int) values_at

### Class methods inherited from module `Indexable(Union(*T))`

cartesian_product(indexables : Indexable(Indexable)) cartesian_product, each_cartesian(indexables : Indexable(Indexable), reuse = false, &)
each_cartesian(indexables : Indexable(Indexable), reuse = false) each_cartesian

### Instance methods inherited from module `Enumerable(Union(*T))`

accumulate(initial : U) : Array(U) forall U
accumulate : Array(Union(T))
accumulate(initial : U, &block : U, Union(T) -> U) : Array(U) forall U
accumulate(&block : Union(T), Union(T) -> Union(T)) : Array(Union(T)) accumulate, all?(& : Union(T) -> ) : Bool
all?(pattern) : Bool
all? : Bool all?, any?(& : Union(T) -> ) : Bool
any?(pattern) : Bool
any? : Bool any?, chunks(&block : Union(T) -> U) forall U chunks, compact_map(& : Union(T) -> _) compact_map, count(& : Union(T) -> ) : Int32
count(item) : Int32 count, cycle(n, & : Union(T) -> ) : Nil
cycle(& : Union(T) -> ) : Nil cycle, each(& : Union(T) -> ) each, each_cons(count : Int, reuse = false, &) each_cons, each_cons_pair(& : Union(T), Union(T) -> ) : Nil each_cons_pair, each_slice(count : Int, reuse = false, &) each_slice, each_step(n : Int, *, offset : Int = 0, & : Union(T) -> ) : Nil each_step, each_with_index(offset = 0, &) each_with_index, each_with_object(obj : U, & : Union(T), U -> ) : U forall U each_with_object, empty? : Bool empty?, find(if_none = nil, & : Union(T) -> ) find, find!(& : Union(T) -> ) : Union(T) find!, find_value(if_none = nil, & : Union(T) -> ) find_value, first(&)
first(count : Int) : Array(Union(T))
first : Union(T) first, first? : Union(T) | Nil first?, flat_map(& : Union(T) -> _) flat_map, group_by(& : Union(T) -> U) forall U group_by, in_groups_of(size : Int, filled_up_with : U = nil) forall U
in_groups_of(size : Int, filled_up_with : U = nil, reuse = false, &) forall U in_groups_of, in_slices_of(size : Int) : Array(Array(Union(T))) in_slices_of, includes?(obj) : Bool includes?, index(& : Union(T) -> ) : Int32 | Nil
index(obj) : Int32 | Nil index, index!(& : Union(T) -> ) : Int32
index!(obj) : Int32 index!, index_by(& : Union(T) -> U) : Hash(U, Union(T)) forall U index_by, join(io : IO, separator = "") : Nil
join(separator, io : IO) : Nil
join(separator = "") : String
join(io : IO, separator = "", & : Union(T), IO -> )
join(separator, io : IO, &)
join(separator = "", & : Union(T) -> ) join, map(& : Union(T) -> U) : Array(U) forall U map, map_with_index(offset = 0, & : Union(T), Int32 -> U) : Array(U) forall U map_with_index, max(count : Int) : Array(Union(T))
max : Union(T) max, max? : Union(T) | Nil max?, max_by(& : Union(T) -> U) : Union(T) forall U max_by, max_by?(& : Union(T) -> U) : Union(T) | Nil forall U max_by?, max_of(& : Union(T) -> U) : U forall U max_of, max_of?(& : Union(T) -> U) : U | Nil forall U max_of?, min(count : Int) : Array(Union(T))
min : Union(T) min, min? : Union(T) | Nil min?, min_by(& : Union(T) -> U) : Union(T) forall U min_by, min_by?(& : Union(T) -> U) : Union(T) | Nil forall U min_by?, min_of(& : Union(T) -> U) : U forall U min_of, min_of?(& : Union(T) -> U) : U | Nil forall U min_of?, minmax : Tuple(Union(T), Union(T)) minmax, minmax? : Tuple(Union(T) | Nil, Union(T) | Nil) minmax?, minmax_by(& : Union(T) -> U) : Tuple(Union(T), Union(T)) forall U minmax_by, minmax_by?(& : Union(T) -> U) : Tuple(Union(T), Union(T)) | Tuple(Nil, Nil) forall U minmax_by?, minmax_of(& : Union(T) -> U) : Tuple(U, U) forall U minmax_of, minmax_of?(& : Union(T) -> U) : Tuple(U, U) | Tuple(Nil, Nil) forall U minmax_of?, none?(& : Union(T) -> ) : Bool
none?(pattern) : Bool
none? : Bool none?, one?(& : Union(T) -> ) : Bool
one?(pattern) : Bool
one? : Bool one?, partition(& : Union(T) -> ) : Tuple(Array(Union(T)), Array(Union(T)))
partition(type : U.class) forall U partition, present? : Bool present?, product(initial : Number)
product
product(initial : Number, & : Union(T) -> )
product(& : Union(T) -> _) product, reduce(memo, &)
reduce(&) reduce, reduce?(&) reduce?, reject(& : Union(T) -> )
reject(type : U.class) forall U
reject(pattern) : Array(Union(T)) reject, sample(n : Int, random : Random | Nil = nil) : Array(Union(T))
sample(random : Random | Nil = nil) : Union(T) sample, select(& : Union(T) -> )
select(type : U.class) : Array(U) forall U
select(pattern) : Array(Union(T)) select, size : Int32 size, skip(count : Int) skip, skip_while(& : Union(T) -> ) : Array(Union(T)) skip_while, sum(initial)
sum
sum(initial, & : Union(T) -> )
sum(& : Union(T) -> ) sum, take_while(& : Union(T) -> ) : Array(Union(T)) take_while, tally(hash)
tally : Hash(Union(T), Int32) tally, tally_by(hash, &)
tally_by(&block : Union(T) -> U) : Hash(U, Int32) forall U tally_by, to_a : Array(Union(T))
to_a(& : Union(T) -> U) : Array(U) forall U to_a, to_h
to_h(& : Union(T) -> Tuple(K, V)) forall K, V to_h, to_set : Set(Union(T))
to_set(&block : Union(T) -> U) : Set(U) forall U to_set, zip(*others : Indexable | Iterable | Iterator, &)
zip(*others : Indexable | Iterable | Iterator) zip, zip?(*others : Indexable | Iterable | Iterator, &)
zip?(*others : Indexable | Iterable | Iterator) zip?

### Class methods inherited from module `Enumerable(Union(*T))`

element_type(x) element_type

### Instance methods inherited from module `Iterable(Union(*T))`

chunk(reuse = false, &block : Union(T) -> U) forall U chunk, chunk_while(reuse : Bool | Array(Union(T)) = false, &block : Union(T), Union(T) -> B) forall B chunk_while, cycle(n)
cycle cycle, each each, each_cons(count : Int, reuse = false) each_cons, each_cons_pair each_cons_pair, each_slice(count : Int, reuse = false) each_slice, each_step(n : Int)
each_step(n : Int, *, offset : Int) each_step, each_with_index(offset = 0) each_with_index, each_with_object(obj) each_with_object, slice_after(reuse : Bool | Array(Union(T)) = false, &block : Union(T) -> B) forall B
slice_after(pattern, reuse : Bool | Array(Union(T)) = false) slice_after, slice_before(reuse : Bool | Array(Union(T)) = false, &block : Union(T) -> B) forall B
slice_before(pattern, reuse : Bool | Array(Union(T)) = false) slice_before, slice_when(reuse : Bool | Array(Union(T)) = false, &block : Union(T), Union(T) -> B) forall B slice_when

### Instance methods inherited from struct `Value`

==(other : Log::Metadata::Value)
==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup

### Instance methods inherited from class `Object`

! : Bool !, !=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as

### Class methods inherited from class `Object`

from_json(string_or_io : String | IO, root : String)
from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml

### Macros inherited from class `Object`

class_getter(*names, &block) class_getter, class_getter!(*names) class_getter!, class_getter?(*names, &block) class_getter?, class_property(*names, &block) class_property, class_property!(*names) class_property!, class_property?(*names, &block) class_property?, class_setter(*names) class_setter, def_clone def_clone, def_equals(*fields) def_equals, def_equals_and_hash(*fields) def_equals_and_hash, def_hash(*fields) def_hash, delegate(*methods, to object) delegate, forward_missing_to(delegate) forward_missing_to, getter(*names, &block) getter, getter!(*names) getter!, getter?(*names, &block) getter?, property(*names, &block) property, property!(*names) property!, property?(*names, &block) property?, setter(*names) setter

##
Constructor Detail

def self.from(array : Array) : self #

Creates a tuple from the given array, with elements casted to the given types.

    Tuple(String, Int64).from(["world", 2_i64])       # => {"world", 2_i64}
    Tuple(String, Int64).from(["world", 2_i64]).class # => Tuple(String, Int64)

See also: `#from`.

def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node) #
def self.new(pull : JSON::PullParser) #
def self.new(*args : *T) #

Creates a tuple that will contain the given values.

This method is useful in macros and generic code because with it you can create empty tuples, something that you can't do with a tuple literal.

    Tuple.new(1, "hello", 'x') #=> {1, "hello", 'x'}
    Tuple.new                  #=> {}

    {}                         # syntax error

##
Class Method Detail

def self.[](index : Int) #

Returns the element type at the given index. Read the type docs to understand the difference between indexing with a number literal or a variable.

    alias Foo = Tuple(Int32, String)
    Foo[0]      # => Int32
    Foo[0].zero # => 0
    Foo[2]      # Error: index out of bounds for Tuple(Int32, String).class (2 not in -2..1)

    i = 0
    Foo[i]      # => Int32
    Foo[i].zero # Error: undefined method 'zero' for String.class (compile-time type is (Int32.class | String.class))

    i = 2
    Foo[i] # raises IndexError

def self.[](range : Range) #

Returns all element types that are within the given range. range must be a range literal whose value is known at compile-time.

Negative indices count backward from the end of the tuple (-1 is the last element). Additionally, an empty tuple is returned when the starting index for an element range is at the end of the tuple.

Raises a compile-time error if `range.begin` is out of range.

    alias Foo = Tuple(Int32, String, Char)
    Foo[0..1] # => Tuple(Int32, String)
    Foo[-2..] # => Tuple(String, Char)
    Foo[...1] # => Tuple(Int32)
    Foo[4..]  # Error: begin index out of bounds for Tuple(Int32, String, Char).class (4 not in -3..3)

    i = 0
    Foo[i..2] # Error: Tuple.[](Range) can only be called with range literals known at compile-time

    i = 0..2
    Foo[i] # Error: Tuple.[](Range) can only be called with range literals known at compile-time

def self.[]?(index : Int) #

Returns the element type at the given index or `nil` if out of bounds. Read the type docs to understand the difference between indexing with a number literal or a variable.

    alias Foo = Tuple(Int32, String)
    Foo[0]?         # => Int32
    Foo[0]?.zero    # => 0
    Foo[2]?         # => nil
    typeof(Foo[2]?) # => Nil

    i = 0
    Foo[i]?      # => Int32
    Foo[i]?.zero # Error: undefined method 'zero' for String.class (compile-time type is (Int32.class | String.class | Nil))

    i = 2
    Foo[i]? # => nil

def self.types #

Returns the types of this tuple type.

    tuple = {1, "hello", 'x'}
    tuple.class.types # => {Int32, String, Char}

##
Instance Method Detail

def +(other : Tuple) #

Returns a tuple that contains `self`'s elements followed by other's elements.

    t1 = {1, 2}
    t2 = {"foo", "bar"}
    t3 = t1 + t2
    t3         # => {1, 2, "foo", "bar"}
    typeof(t3) # => Tuple(Int32, Int32, String, String)

def <=>(other : self) #

The comparison operator.

Each object in each tuple is compared using the `<=>` operator.

Tuples are compared in an "element-wise" manner; the first element of this tuple is compared with the first one of other using the `<=>` operator, then each of the second elements, etc. As soon as the result of any such comparison is non-zero (i.e. the two corresponding elements are not equal), that result is returned for the whole tuple comparison.

If all the elements are equal, then the result is based on a comparison of the tuple sizes. Thus, two tuples are "equal" according to `<=>` if, and only if, they have the same size and the value of each element is equal to the value of the corresponding element in the other tuple.

    {"a", "a", "c"} <=> {"a", "b", "c"} # => -1
    {1, 2, 3, 4, 5, 6} <=> {1, 2}       # => 1
    {1, 2} <=> {1, 2.0}                 # => 0

def <=>(other : Tuple) #

The comparison operator.

Each object in each tuple is compared using the `<=>` operator.

Tuples are compared in an "element-wise" manner; the first element of this tuple is compared with the first one of other using the `<=>` operator, then each of the second elements, etc. As soon as the result of any such comparison is non-zero (i.e. the two corresponding elements are not equal), that result is returned for the whole tuple comparison.

If all the elements are equal, then the result is based on a comparison of the tuple sizes. Thus, two tuples are "equal" according to `<=>` if, and only if, they have the same size and the value of each element is equal to the value of the corresponding element in the other tuple.

    {"a", "a", "c"} <=> {"a", "b", "c"} # => -1
    {1, 2, 3, 4, 5, 6} <=> {1, 2}       # => 1
    {1, 2} <=> {1, 2.0}                 # => 0

def ==(other : self) #

Returns `true` if this tuple has the same size as the other tuple and their elements are equal to each other when compared with `#==`.

    t1 = {1, "hello"}
    t2 = {1.0, "hello"}
    t3 = {2, "hello"}

    t1 == t2 # => true
    t1 == t3 # => false

def ==(other : Tuple) #

Returns `true` if this tuple has the same size as the other tuple and their elements are equal to each other when compared with `#==`.

    t1 = {1, "hello"}
    t2 = {1.0, "hello"}
    t3 = {2, "hello"}

    t1 == t2 # => true
    t1 == t3 # => false

def ==(other) #
Description copied from struct Value

Returns `false`.

def ===(other : self) #

Returns `true` if case equality holds for the elements in `self` and other.

    {1, 2} === {1, 2} # => true
    {1, 2} === {1, 3} # => false

See also: `Object#===`.

def ===(other : Tuple) #

Returns `true` if `self` and other have the same size and case equality holds for the elements in `self` and other.

    {1, 2} === {1, 2, 3}             # => false
    {/o+/, "bar"} === {"foo", "bar"} # => true

See also: `Object#===`.

def [](index : Int) #

Returns the element at the given index. Read the type docs to understand the difference between indexing with a number literal or a variable.

    tuple = {1, "hello", 'x'}
    tuple[0]         # => 1
    typeof(tuple[0]) # => Int32
    tuple[3]         # Error: index out of bounds for Tuple(Int32, String, Char) (3 not in -3..2)

    i = 0
    tuple[i]         # => 1
    typeof(tuple[i]) # => (Char | Int32 | String)

    i = 3
    tuple[i] # raises IndexError

def [](range : Range) #

Returns all elements that are within the given range. range must be a range literal whose value is known at compile-time.

Negative indices count backward from the end of the tuple (-1 is the last element). Additionally, an empty tuple is returned when the starting index for an element range is at the end of the tuple.

Raises a compile-time error if `range.begin` is out of range.

    tuple = {1, "hello", 'x'}
    tuple[0..1] # => {1, "hello"}
    tuple[-2..] # => {"hello", 'x'}
    tuple[...1] # => {1}
    tuple[4..]  # Error: begin index out of bounds for Tuple(Int32, String, Char) (4 not in -3..3)

    i = 0
    tuple[i..2] # Error: Tuple#[](Range) can only be called with range literals known at compile-time

    i = 0..2
    tuple[i] # Error: Tuple#[](Range) can only be called with range literals known at compile-time

def []?(index : Int) #

Returns the element at the given index or `nil` if out of bounds. Read the type docs to understand the difference between indexing with a number literal or a variable.

    tuple = {1, "hello", 'x'}
    tuple[0]?         # => 1
    typeof(tuple[0]?) # => Int32
    tuple[3]?         # => nil
    typeof(tuple[3]?) # => Nil

    i = 0
    tuple[i]?         # => 1
    typeof(tuple[i]?) # => (Char | Int32 | String | Nil)

    i = 3
    tuple[i]? # => nil

def at(index : Int) #

Returns the element at the given index or raises IndexError if out of bounds.

    tuple = {1, "hello", 'x'}
    tuple.at(0) # => 1
    tuple.at(3) # raises IndexError

def at(index : Int, &) #

Returns the element at the given index or the value returned by the block if out of bounds.

    tuple = {1, "hello", 'x'}
    tuple.at(0) { 10 } # => 1
    tuple.at(3) { 10 } # => 10

def clone #

Returns a tuple containing cloned elements of this tuple using the `#clone` method.

def each(& : Union(*T) -> ) : Nil #

Yields each of the elements in this tuple.

    tuple = {1, "hello", 'x'}
    tuple.each do |value|
      puts value
    end

Output:

    1
    "hello"
    'x'

def first #

Returns the first element of this tuple. Doesn't compile if the tuple is empty.

    tuple = {1, 2.5}
    tuple.first # => 1

def first? #

Returns the first element of this tuple, or `nil` if this is the empty tuple.

    tuple = {1, 2.5}
    tuple.first? # => 1

    empty = Tuple.new
    empty.first? # => nil

def from(array : Array) #

Expects to be called on a tuple of types, creates a tuple from the given array, with types casted appropriately.

This allows you to easily pass an array as individual arguments to a method.

    require "json"

    def speak_about(thing : String, n : Int64)
      "I see #{n} #{thing}s"
    end

    data = JSON.parse(%(["world", 2])).as_a.map(&.raw)
    speak_about(*{String, Int64}.from(data)) # => "I see 2 worlds"

def hash(hasher) #

See `Object#hash(hasher)`

def inspect : String #

Same as `#to_s`.

def last #

Returns the last element of this tuple. Doesn't compile if the tuple is empty.

    tuple = {1, 2.5}
    tuple.last # => 2.5

def last? #

Returns the last element of this tuple, or `nil` if this is the empty tuple.

    tuple = {1, 2.5}
    tuple.last? # => 2.5

    empty = Tuple.new
    empty.last? # => nil

def map(& : Union(*T) -> ) #

Returns a new tuple where elements are mapped by the given block.

    tuple = {1, 2.5, "a"}
    tuple.map &.to_s # => {"1", "2.5", "a"}

def map_with_index(offset = 0, &) #

Like `#map`, but the block gets passed both the element and its index.

    tuple = {1, 2.5, "a"}
    tuple.map_with_index { |e, i| "tuple[#{i}]: #{e}" } # => {"tuple[0]: 1", "tuple[1]: 2.5", "tuple[2]: a"}

Accepts an optional offset parameter, which tells it to start counting from there.

def pretty_print(pp) : Nil #
def reduce(memo, &) #

Just like the other variant, but you can set the initial value of the accumulator.

    [1, 2, 3, 4, 5].reduce(10) { |acc, i| acc + i }             # => 25
    [1, 2, 3].reduce([] of Int32) { |memo, i| memo.unshift(i) } # => [3, 2, 1]

def reduce(&) #

Combines all elements in the collection by applying a binary operation, specified by a block, so as to reduce them to a single value.

For each element in the collection the block is passed an accumulator value (memo) and the element. The result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method. The initial value for the accumulator is the first element in the collection. If the collection has only one element, that element is returned.

Raises `Enumerable::EmptyError` if the collection is empty.

    [1, 2, 3, 4, 5].reduce { |acc, i| acc + i } # => 15
    [1].reduce { |acc, i| acc + i }             # => 1
    ([] of Int32).reduce { |acc, i| acc + i }   # raises Enumerable::EmptyError

The block is not required to return a `T`, in which case the accumulator's type includes whatever the block returns.

    # `acc` is an `Int32 | String`
    [1, 2, 3, 4, 5].reduce { |acc, i| "#{acc}-#{i}" } # => "1-2-3-4-5"
    [1].reduce { |acc, i| "#{acc}-#{i}" }             # => 1

def reduce?(&) #

Similar to `#reduce`, but instead of raising when the input is empty, return `nil`

    ([] of Int32).reduce? { |acc, i| acc + i } # => nil

def reverse #

Returns a new tuple where the elements are in reverse order.

    tuple = {1, 2.5, "a"}
    tuple.reverse # => {"a", 2.5, 1}

def reverse_each(& : Union(*T) -> ) #

Yields each of the elements in this tuple in reverse order.

    tuple = {1, "hello", 'x'}
    tuple.reverse_each do |value|
      puts value
    end

Output:

    'x'
    "hello"
    1

def size #

Returns the number of elements in this tuple.

    {'a', 'b'}.size # => 2

def to_a : Array(Union(*T)) #

Returns an `Array` with all the elements in the tuple.

    {1, 2, 3, 4, 5}.to_a # => [1, 2, 3, 4, 5]

def to_a(& : Union(*T) -> U) forall U #

Returns an `Array` with the results of running block against each element of the tuple.

    {1, 2, 3, 4, 5}).to_a { |i| i * 2 } # => [2, 4, 6, 8, 10]

def to_json(json : JSON::Builder) : Nil #
def to_s(io : IO) : Nil #

Appends a string representation of this tuple to the given `IO`.

    tuple = {1, "hello"}
    tuple.to_s # => "{1, \"hello\"}"

def to_static_array : StaticArray #

Returns a `StaticArray` with the same elements.

The element type is `Union(*T)`.

    {1, 'a', true}.to_static_array # => StaticArray[1, 'a', true]

def to_yaml(yaml : YAML::Nodes::Builder) : Nil #
def unsafe_fetch(index : Int) #
Description copied from module Indexable(Union(*T))

Returns the element at the given index, without doing any bounds check.

`Indexable` makes sure to invoke this method with index in `0...size`, so converting negative indices to positive ones is not needed here.

Clients never invoke this method directly. Instead, they access elements with `#[](index)` and `#[]?(index)`.

This method should only be directly invoked if you are absolutely sure the index is in bounds, to avoid a bounds check for a small boost of performance.