The typeof
a tuple is a subtype of Tuple
:
julia> typeof((1, 2, 3))
Tuple{Int64,Int64,Int64}
julia> typeof((1.0, :x, (1, 2)))
Tuple{Float64,Symbol,Tuple{Int64,Int64}}
Unlike other data types, Tuple
types are covariant. Other data types in Julia are generally invariant. Thus,
julia> Tuple{Int, Int} <: Tuple{Number, Number}
true
julia> Vector{Int} <: Vector{Number}
false
This is the case because everywhere a Tuple{Number, Number}
is accepted, so too would a Tuple{Int, Int}
, since it also has two elements, both of which are numbers. That is not the case for a Vector{Int}
versus a Vector{Number}
, as a function accepting a Vector{Number}
may wish to store a floating point (e.g. 1.0
) or a complex number (e.g. 1+3im
) in such a vector.
The covariance of tuple types means that Tuple{Number}
(again unlike Vector{Number}
) is actually an abstract type:
julia> isleaftype(Tuple{Number})
false
julia> isleaftype(Vector{Number})
true
Concrete subtypes of Tuple{Number}
include Tuple{Int}
, Tuple{Float64}
, Tuple{Rational{BigInt}}
, and so forth.
Tuple
types may contain a terminating Vararg
as their last parameter to indicate an indefinite number of objects. For instance, Tuple{Vararg{Int}}
is the type of all tuples containing any number of Int
s, possibly zero:
julia> isa((), Tuple{Vararg{Int}})
true
julia> isa((1,), Tuple{Vararg{Int}})
true
julia> isa((1,2,3,4,5), Tuple{Vararg{Int}})
true
julia> isa((1.0,), Tuple{Vararg{Int}})
false
whereas Tuple{String, Vararg{Int}}
accepts tuples consisting of a string, followed by any number (possibly zero) of Int
s.
julia> isa(("x", 1, 2), Tuple{String, Vararg{Int}})
true
julia> isa((1, 2), Tuple{String, Vararg{Int}})
false
Combined with co-variance, this means that Tuple{Vararg{Any}}
describes any tuple. Indeed, Tuple{Vararg{Any}}
is just another way of saying Tuple
:
julia> Tuple{Vararg{Any}} == Tuple
true
Vararg
accepts a second numeric type parameter indicating how many times exactly its first type parameter should occur. (By default, if unspecified, this second type parameter is a typevar that can take any value, which is why any number of Int
s are accepted in the Vararg
s above.) Tuple
types ending in a specified Vararg
will automatically be expanded to the requested number of elements:
julia> Tuple{String,Vararg{Int, 3}}
Tuple{String,Int64,Int64,Int64}
Notation exists for homogenous tuples with a specified Vararg
: NTuple{N, T}
. In this notation, N
denotes the number of elements in the tuple, and T
denotes the type accepted. For instance,
julia> NTuple{3, Int}
Tuple{Int64,Int64,Int64}
julia> NTuple{10, Int}
NTuple{10,Int64}
julia> ans.types
svec(Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64,Int64)
Note that NTuple
s beyond a certain size are shown simply as NTuple{N, T}
, instead of the expanded Tuple
form, but they are still the same type:
julia> Tuple{Int,Int,Int,Int,Int,Int,Int,Int,Int,Int}
NTuple{10,Int64}