# Tuples, iterators, splats, and type stability

**URL:** <https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849>\
**Category:** General Usage\
**Tags:** tuple, type-stability\
**Created:** [July 10, 2020, 2:49pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849 "2020-07-10T14:49:31Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![mhauru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhauru/32/208880_2.png) [@mhauru](https://discourse.julialang.org/u/mhauru)\
**Post date:** [July 10, 2020, 2:49pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/1 "2020-07-10T14:49:31Z")

</div>

I’m trying understand type stability of functions like

```julia
f(t::Tuple) = tuple(t...)
g(t::Tuple) = tuple((identity(l) for l in t)...)

```

`identity` here is meant to be a place-holder for any type stable function. Of the two, `f` is stable, `g` is not:

```julia
julia> t = (:a, 1, 0.1);
julia> @code_warntype f(t)
Variables
  #self#::Core.Compiler.Const(f, false)
  t::Tuple{Symbol,Int64,Float64}

Body::Tuple{Symbol,Int64,Float64}
1 ─ %1 = Core._apply_iterate(Base.iterate, Main.tuple, t)::Tuple{Symbol,Int64,Float64}
└── return %1

julia> @code_warntype g(t)
Variables
  #self#::Core.Compiler.Const(g, false)
  t::Tuple{Symbol,Int64,Float64}

Body::Tuple{Vararg{Union{Float64, Int64, Symbol},N} where N}
1 ─ %1 = Base.Generator(Main.identity, t)::Base.Generator{Tuple{Symbol,Int64,Float64},typeof(identity)}
│ %2 = Core._apply_iterate(Base.iterate, Main.tuple, %1)::Tuple{Vararg{Union{Float64, Int64, Symbol},N} where N}
└── return %2

```

There are two, possibly related, things I don’t understand here. First, what exactly does `tuple(t...)` do? I would have expected this to `iterate` through `t`, and pass the results onto `tuple`. But I guess that’s not what’s happening, since `iterate` doesn’t seem to be type stable:

```julia
julia> @code_warntype iterate(t)
Variables
  #self#::Core.Compiler.Const(iterate, false)
  t::Tuple{Symbol,Int64,Float64}

Body::Union{Nothing, Tuple{Union{Float64, Int64, Symbol},Int64}}
1 ─ nothing
│ nothing
│ %3 = (#self#)(t, 1)::Union{Nothing, Tuple{Union{Float64, Int64, Symbol},Int64}}
└── return %3

```

So what exactly does splatting do then, and is this explained somewhere in the manual?

Second, for `g`, I’ve come to the conclusion that its type instability is probably caused by the compiler not being able to infer the length of a `Base.Generator{NTuple{N,T}}` from its type. Is there a reason why this is so? Could there be something like a value for `IteratorSize` called `TypeHasLength()` that would be a guarantee that `length(::T) = length(T)` for this type `T`, i.e. the length is inferable from the type? This seems to me like it would make a lot of sense for `Tuple`s, and probably also for a lot of user-defined composite types that have a number of fields, and `iterate` just goes through them. This is actually the original use case that got me thinking about all this: A user-defined, iterable type for which I would like a function like `g` to be type stable.

---

<div class="post-metadata">

**Author:** ![mhauru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhauru/32/208880_2.png) [@mhauru](https://discourse.julialang.org/u/mhauru)\
**Post date:** [July 10, 2020, 2:51pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/2 "2020-07-10T14:51:38Z")

</div>

PS. Derailing my own thread, but in trying to figure this out I’ve really come to think that `map` on generic iterators should return generators. I find it very unintuitive that `map(h, gen)` and `(h(i) for i in gen)` behave so very differently even when `gen` is a generator.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [July 10, 2020, 4:14pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/3 "2020-07-10T16:14:51Z")

</div>

From the [FAQ](https://docs.julialang.org/en/v1/manual/faq/#...-splits-one-argument-into-many-different-arguments-in-function-calls-1):

> `...` splits one argument into many different arguments in function calls

That’s really all there is to it: `f(t...)` is simply equivalent to `f(first(t), second(t), ..., last(t))`.

You are correct that one of the issues in your function `g` is that using a generator hides the length of `t` from the compiler, and so Julia must figure out a runtime which method of `tuple` to call and hence it cannot infer the return type of `g`. The other issue is that generators can only have a single `eltype`, so if the elements of `t` have different types then the `eltype` of the generator must be an abstract type which is a supertype of all of the element types.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [July 10, 2020, 5:37pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/4 "2020-07-10T17:37:38Z")

</div>

> [@mhauru](#):
>
> `map(h, gen)` and `(h(i) for i in gen)` behave so very differently

BTW, [https://github.com/JuliaLang/julia/pull/34352](https://github.com/JuliaLang/julia/pull/34352) added an uncollected `map` to go with `filter` etc:

```julia
julia> Iterators.map(sqrt, ntuple(+,5))
Base.Generator{NTuple{5,Int64},typeof(sqrt)}(sqrt, (1, 2, 3, 4, 5))

```

---

<div class="post-metadata">

**Author:** ![mhauru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhauru/32/208880_2.png) [@mhauru](https://discourse.julialang.org/u/mhauru)\
**Post date:** [July 11, 2020, 8:34am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/5 "2020-07-11T08:34:38Z")

</div>

> [@ettersi](#):
>
> That’s really all there is to it: `f(t...)` is simply equivalent to `f(first(t), second(t), ..., last(t))`

And what if `t` isn’t a `Tuple`, does it first gets converted to a `Tuple` with something like `tuple(t...)`?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 11, 2020, 8:57am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/6 "2020-07-11T08:57:51Z")

</div>

It is iterated. See, among other pages,

[Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#)…

[Frequently Asked Questions · The Julia Language](https://docs.julialang.org/en/v1/manual/faq/#The-two-uses-of-the-)…-operator:-slurping-and-splatting-1

---

<div class="post-metadata">

**Author:** ![mhauru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhauru/32/208880_2.png) [@mhauru](https://discourse.julialang.org/u/mhauru)\
**Post date:** [July 11, 2020, 10:31am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/7 "2020-07-11T10:31:36Z")

</div>

> [@Tamas\_Papp](#):
>
> It is iterated. See, among other pages,

Thanks. Whether it’s iterated is what I meant to ask above as well, but my brain-finger communication failed. I’ve read the pages you link though, and neither one of them really answers the question, e.g. the fact that general iterables go through `iterate` when splatting, but `Tuple`s don’t, is not specified.

> [@mcabbott](#):
>
> BTW, [https://github.com/JuliaLang/julia/pull/34352](https://github.com/JuliaLang/julia/pull/34352) added an uncollected `map` to go with `filter` etc:

Thanks, I wasn’t aware of this. Seems perfect, a reason to look forward to 1.6.

All this seems to point towards a rule of thumb though, that generators are a bad idea when dealing with tuples and tuple-like iterables (e.g. user types that `iterate` over their fields of mixed types), if one wants to maintain type stability.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [July 11, 2020, 11:10am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/8 "2020-07-11T11:10:39Z")

</div>

> [@mhauru](#):
>
> neither one of them really answers the question, e.g. the fact that general iterables go through `iterate` when splatting, but `Tuple` s don’t, is not specified

AFAIK `Tuple`s are technically `iterate`d too, it’s just that then the compiler can expand that efficiently.

If you want to find out these things interactively while learning Julia, constructs like

```julia
julia> Meta.@lower f(x...)
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope'
1 ─ %1 = Core._apply_iterate(Base.iterate, f, x)
└── return %1
))))

```

are useful.

---

<div class="post-metadata">

**Author:** ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)\
**Post date:** [July 11, 2020, 8:48pm UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/9 "2020-07-11T20:48:13Z")

</div>

Fix for the inference imprecision here (together with some other recent work on master):

[https://github.com/JuliaLang/julia/pull/36622](https://github.com/JuliaLang/julia/pull/36622)

---

<div class="post-metadata">

**Author:** ![mhauru](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mhauru/32/208880_2.png) [@mhauru](https://discourse.julialang.org/u/mhauru)\
**Post date:** [July 12, 2020, 11:07am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/10 "2020-07-12T11:07:58Z")

</div>

I am officially impressed with the Julia community’s responsivity to feedback.

---

<div class="post-metadata">

**Author:** ![Keno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/keno/32/285_2.png) [@Keno](https://discourse.julialang.org/u/Keno)\
**Post date:** [July 17, 2020, 3:05am UTC](https://discourse.julialang.org/t/tuples-iterators-splats-and-type-stability/42849/11 "2020-07-17T03:05:03Z")

</div>

Should be fixed on master.
