struct Tuple(T*)

Overview

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

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       (Int32)
tuple[1]                  #=> "hello" (String)
tuple[2]                  #=> 'x'     (Char)

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 .

Tuples are the preferred way to return fixed-length 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                              #=> {1, "hello", 'x'} (Tuple(Int32, String, Char))

Superclass hierarchy

Object
Value
Tuple(T*)

Included Modules

Comparable(Tuple), Enumerable(typeof(...)), Iterable

Defined in:

Class Method Summary

Instance Method Summary

Class Method Detail

def self.new(*args)

Creates a tuple that will contain the given arguments.

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

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

{}                         # syntax error

def self.new(pull : JSON::PullParser)

Instance Method Detail

def <=>(other : Tuple)

Implements 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 lengths. Thus, two tuples are "equal" according to #<=> if, and only if, they have the same length 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

See Object#<=>.


def <=>(other : self)

Implements 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 lengths. Thus, two tuples are "equal" according to #<=> if, and only if, they have the same length 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

See Object#<=>.


def ==(other : Tuple)

Returns true if this tuple has the same length 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 : self)

Returns true if this tuple has the same length 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 [](index : Int)

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

tuple = {1, "hello", 'x'}
tuple[0]                  #=> 1 (Int32)
tuple[3]                  #=> compile error: index out of bounds for tuple {Int32, String, Char}

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

i = 3
tuple[i]                  #=> runtime error: IndexError

def []?(index : Int)

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

tuple = {1, "hello", 'x'}
tuple[0]                  #=> 1
tuple[3]                  #=> nil

def at(index : Int, &block)

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 at(index : Int)

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

tuple = {1, "hello", 'x'}
tuple[0]                  #=> 1
tuple[3]                  #=> raises IndexError

def clone

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


def dup

Returns self.


def each(&block)

Yields each of the elements in this tuple.

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

Output:

1
"hello"
'x'

def each

Returns an Iterator for the elements in this tuple.

{1, 'a'}.each.cycle.take(3).to_a #=> [1, 'a', 1]

def empty?

Returns true if this tuple is empty.

Tuple.new.empty? #=> true
{1, 2}.empty?    #=> false

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 hash

returns a hash value based on this tuple's length and contents.

see object#hash.


def inspect

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 length

Returns the number of elements in this tuple.

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

def map(&block)

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 size

Same as #length.


def to_json(io)

def to_s(io)

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

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

def types

Returns a tuple containing the types of this tuple.

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

def values_at(*indexes : Int)

Returns a tuple populated with the elements at the given indexes. Raises if any index is invalid.

{"a", "b", "c", "d"}.values_at(0, 2) #=> {"a", "c"}