# Get tuple length from type?

**URL:** <https://discourse.julialang.org/t/get-tuple-length-from-type/32483>\
**Category:** General Usage\
**Tags:** type, tuple\
**Created:** [December 19, 2019, 3:22pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483 "2019-12-19T15:22:16Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ssfrr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssfrr/32/3736_2.png) [@ssfrr](https://discourse.julialang.org/u/ssfrr)\
**Post date:** [December 19, 2019, 3:22pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/1 "2019-12-19T15:22:16Z")

</div>

Is there a built-in function to get the length of a tuple as a `Val{N}`?

Basically I’m looking for something that would be of the form:

```julia
tuplen(::Type{Tuple{}}) = Val{0}()
tuplen(::Type{Tuple{T}}) where T = Val{1}()
tuplen(::Type{Tuple{T1, T2}}) where {T1, T2} = Val{2}()
tuplen(::Type{Tuple{T1, T2, T3}}) where {T1, T2, T3} = Val{3}()
...

```

In case this is an XY problem - what I’m actually trying to do is convert an array-of-tuples representation to a tuple-of-arrays representation, and with the above definition I can do:

```julia
"""
Convert an Array-of-Tuples to a Tuple-of-Arrays.
"""
toa(aot) = ntuple(i->getindex.(aot, i), tuplen(eltype(aot)))

```

without the above I could use `length(first(aot))` to get the length but that assumes the array is not empty.

edit: as a nested XY problem, I just realized that Plots can take vectors of tuples natively and I don’t need to transform my data to tuple-of-vectors after all. Carry on…

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [December 19, 2019, 3:47pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/2 "2019-12-19T15:47:23Z")

</div>

Yup–it’s actually a simple one-liner:

```julia
julia> tuple_len(::NTuple{N, Any}) where {N} = Val{N}()
tuple_len (generic function with 1 method)

julia> tuple_len((1, 2, 3))
Val{3}()

julia> tuple_len((1, "hello", π))
Val{3}()

julia> tuple_len((1, "hello", π, [1]))
Val{4}()

```

This works because tuples (unlike all other types) are variadic, so you can dispatch on `NTuple{Any, N}` to match all tuples of length N.

---

<div class="post-metadata">

**Author:** ![ssfrr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssfrr/32/3736_2.png) [@ssfrr](https://discourse.julialang.org/u/ssfrr)\
**Post date:** [December 19, 2019, 7:03pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/3 "2019-12-19T19:03:51Z")

</div>

Ah, thanks for that. I’d forgotten that tuple types are special.

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [December 19, 2019, 11:45pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/4 "2019-12-19T23:45:15Z")

</div>

So why isn’t it `length()`? Already defined in Base?

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [December 20, 2019, 12:04am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/5 "2019-12-20T00:04:45Z")

</div>

Sorry, that isn’t the same thing as I just realized. `length()` already exists in base for tuples,  
but returns an integer for the length.

---

<div class="post-metadata">

**Author:** ![ssfrr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ssfrr/32/3736_2.png) [@ssfrr](https://discourse.julialang.org/u/ssfrr)\
**Post date:** [December 20, 2019, 12:49am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/6 "2019-12-20T00:49:03Z")

</div>

Also it’s not defined on the `Tuple` type, only tuple values:

```julia
julia> length(Tuple{Float64, Int64})
ERROR: MethodError: no method matching length(::Type{Tuple{Float64,Int64}})
Closest candidates are:
  length(::Core.SimpleVector) at essentials.jl:593

```

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petrkryslucsd/32/215825_2.png) [@PetrKryslUCSD](https://discourse.julialang.org/u/PetrKryslUCSD)\
**Post date:** [December 20, 2019, 12:56am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/7 "2019-12-20T00:56:02Z")

</div>

Right.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [December 20, 2019, 1:10am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/8 "2019-12-20T01:10:52Z")

</div>

It’s also worth noting that the compiler is pretty good at dealing with tuple lengths as regular old integers using the built-in length function. For example, we can write a function that looks like it might be type-unstable:

```julia
julia> function maybe_type_unstable(x::Tuple)
         if length(x) == 2
           return 1.0
         else
           return "hello world"
         end
       end
maybe_type_unstable (generic function with 1 method)

```

but the compiler is smart enough to figure out the value of `length(x)` at compile time and infer the result:

```julia
julia> @code_warntype maybe_type_unstable((1, 2))
Variables
  #self#::Core.Compiler.Const(maybe_type_unstable, false)
  x::Tuple{Int64,Int64}

Body::Float64
...

```

```julia
julia> @code_warntype maybe_type_unstable((1, 2, 3))
Variables
  #self#::Core.Compiler.Const(maybe_type_unstable, false)
  x::Tuple{Int64,Int64,Int64}

Body::String
...

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [February 15, 2022, 5:51pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/9 "2022-02-15T17:51:38Z")

</div>

Sorry to came so late after the fight, but we finally don’t have a solution to get the length of a tuple type ?

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 15, 2022, 8:09pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/10 "2022-02-15T20:09:58Z")

</div>

Do you mean besides defining the one-liner function marked as a solution?

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [February 15, 2022, 8:32pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/11 "2022-02-15T20:32:09Z")

</div>

Yep this function gets the length of a tuple, not from the tuple type ad was requested at the beginning (and as it seems the OP is referenced) . Actually I found a solution asking another question there [How can i index a tuple type?](https://discourse.julialang.org/t/how-can-i-index-a-tuple-type/76501) so nvm

Type{Tuple{…}} Is not the same as NTuple{…}

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 16, 2022, 12:20am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/12 "2022-02-16T00:20:26Z")

</div>

The solution in the other thread may be efficient, but is probably an implementation detail that cannot be relied upon.

As it is said in the accepted answer:

> [@rdeits](#):
>
> This works because tuples (unlike all other types) are variadic, so you can dispatch on `NTuple{Any, N}` to match all tuples of length N.

So you can use `NTuple{N, T}` to match any `Tuple{...}`. The only matter is that you want the function to take tuple types instead of tuples. The solution below is correct and do not rely in any implementation details, while it may be ugly and inefficient.

```julia
julia> tuple_type_length(x) = (n = -1; while !(x <: NTuple{n+=1, Any}); end; return n)

tuple_type_length (generic function with 1 method)

julia> tuple_type_length(Tuple{Int, Char})
2

julia> tuple_type_length(Tuple{Int, Char, String})
3

```

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [February 16, 2022, 3:08am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/13 "2022-02-16T03:08:10Z")

</div>

One can avoid internals by using

```julia
julia> fieldcount(Tuple{Int,Float64})
2

```

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 16, 2022, 2:23pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/14 "2022-02-16T14:23:48Z")

</div>

Seems a good solution, I did not know `fieldcount`. My only worry is the caveat in the documentation:

> Get the number of fields that an instance of the given type would have. An error is thrown if the type is too abstract to determine this.

Kinda hard to know beforehand what is a “too abstract” type.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [February 16, 2022, 2:43pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/15 "2022-02-16T14:43:06Z")

</div>

> [@Henrique\_Becker](#):
>
> Kinda hard to know beforehand what is a “too abstract” type.

Any concrete type should be fine with `fieldtype`. Even many incomplete types with defined-but-type-unspecified fields such as `Complex{T} where T`, `Tuple{T,T} where T`, and `Tuple{Tuple{Vararg}}` will work.

Examples of types that will fail are `Tuple` (with no further elaboration), `Tuple{Vararg}`, and `NTuple{N,Any} where N`. The number of fields that these types have is undefined.

So `fieldcount` should work with almost any type that actually has a number of fields. One might be able to cook up some pathological corner cases, but I haven’t thought of one yet. If you find one that fails that you think shouldn’t, you can consider opening a bug report.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [February 28, 2022, 10:55am UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/16 "2022-02-28T10:55:40Z")

</div>

Is there anything wrong with this variant of the accepted solution (sligthly adapted to work on Tuple types instead of Tuple instances)?

```julia
julia> tuple_len(::Type{<:NTuple{N, Any}}) where {N} = Val{N}()
tuple_len (generic function with 1 method)

julia> x = (1, "hello", 42.0)
(1, "hello", 42.0)

julia> tuple_len(typeof(x))
Val{3}()

```

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 28, 2022, 3:36pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/17 "2022-02-28T15:36:53Z")

</div>

I believe there is no problem, but I would adopt the simpler `fieldcount` solution now that I am aware of it, unless you want the code to fail in non-tuple types.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [February 28, 2022, 4:01pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/18 "2022-02-28T16:01:32Z")

</div>

OK, but `fieldcount` gives a plain integer result, as opposed to the initial requirement that the result be a `Val`-wrapped value.

I agree that, since constant propagation is likely to work well in many cases, `fieldcount` would probably a very good and standard way to do this (but in those cases, the question then becomes: why not simply `length`?)

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 28, 2022, 4:41pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/19 "2022-02-28T16:41:43Z")

</div>

Is there any api guarantee that an NTuple will always have exactly N fields? Using `fieldcount` seems a bit ‘hacky’.

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 28, 2022, 5:12pm UTC](https://discourse.julialang.org/t/get-tuple-length-from-type/32483/20 "2022-02-28T17:12:57Z")

</div>

> [@ffevotte](#):
>
> why not simply `length` ?

`length` works if you have an instance of the object, true, but I thought the idea was to have a function that would work directly over the type?

Also, yes, `fieldtype` does not return a `Val` but neither does `N` in the parameter type annotation, both give `Int` values which can after be wrapped inside `Val`. It may be that one solution is recognized as type-stable by the compiler (i.e., recognizes the static mapping between input and output types) and the other solution isn’t, but this is speculation and should be checked.
