# Is there a way to "forward" getindex for Tuples in a type-stable way?

**URL:** <https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889>\
**Category:** General Usage\
**Created:** [March 26, 2017, 10:48pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889 "2017-03-26T22:48:24Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [March 26, 2017, 10:48pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/1 "2017-03-26T22:48:24Z")

</div>

I have some data structure which has a field which is a Tuple, and I want to forward `getindex` called on my data structure to this tuple, while maintaining type stability. From what I can tell, there is some magic happening somewhere that makes tuple indexing type-stable in the first place, which isn’t happening for my case. Here’s what I mean,

```julia

immutable TupleWrapper{A,B}
    data :: Tuple{A,B}
end

import Base: getindex
getindex(t::TupleWrapper, i) = getindex(t.data,i)

using Base.Test
foo(x) = x[1]
@inferred foo((1.,2)) # is OK
@inferred foo(TupleWrapper((1.,2)))
> ERROR: return type Float64 does not match inferred return type Union{Float64,Int64}
 in error(::String) at ./error.jl:21

```

Is there any way to do this?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [March 27, 2017, 10:10am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/2 "2017-03-27T10:10:59Z")

</div>

Don’t use `getindex` with runtime integers `i` (`x[i]`) if you want it to be type-stable. Instead, you need all of the those integers to be known at compile-time. So

```julia
for i = 1:3
  x[i]
end

```

are not type stable calls for an inhomogenous tuple, while

```julia
x[1]; x[2]; x[3]

```

is. Two ways to handle this. One is a metaprogramming: generated functions work nicely. But another way is recursion. I’m thinking of writing a blog post to describe it in full, but an example of how to do this is found here:

[https://github.com/JuliaDiffEq/OrdinaryDiffEq.jl/blob/master/src/callbacks.jl#L195](https://github.com/JuliaDiffEq/OrdinaryDiffEq.jl/blob/master/src/callbacks.jl#L195)

In this example, `apply_discrete_callback!(integrator,callback)` needs to be called on every callback in a tuple (and each callback is differently typed). So the basic call is:

```julia
apply_discrete_callback!(integrator,discrete_callbacks...)

```

This then gets “caught” by function headers like

```julia
apply_discrete_callback!(integrator::ODEIntegrator,callback::DiscreteCallback,args...)

```

where `callback` is the first callback in the list and `args` is the rest. You can then recrusively do something on `callback` and pass `args` into `apply_discrete_callback!`, and it’ll get smaller an smaller. Manage the Base cases and you’re good: no `getindex` was ever needed.

Then, for this code, the compiler will inline this into one giant call. It essentially makes it amount to:

```julia
apply_discrete_callback!(integrator,callback[1])
apply_discrete_callback!(integrator,callback[2])
apply_discrete_callback!(integrator,callback[3])
...

```

knowing what the index is at compile time and thus able to infer each call and be type-stable. The only cost here is the compile time, but if you’re keeping the tuples around and repeatedly calling this, it’ll only have to compile this full recursive routine once for the the tuple.

---

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [March 27, 2017, 11:19am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/3 "2017-03-27T11:19:57Z")

</div>

> [@ChrisRackauckas](#):
>
> Don’t use getindex with runtime integers i (x[i]) if you want it to be type-stable. Instead, you need all of the those integers to be known at compile-time. So
> 
> ```julia
> for i = 1:3
> x[i]
> end
> 
> ```
> 
> are not type stable calls for an inhomogenous tuple, while
> 
> ```julia
> x[1]; x[2]; x[3]
> 
> ```
> 
> is.

Thanks for the reply. Yea, I am definitely not trying to do this with run-time integers, where I’d expect it to be hopeless. But like you see above, while `x[1]; x[2]; x[3]` is type-stable for an inhomogenous Tuple, it’s _not_ type-stable for my TupleWrapper, even though I’m just forwarding to the underlying Tuple function. This is surely because by the time `i` makes it to my `getindex` function, its a run-time integer, but I’m wondering if there’s a way to preserve the functionality normal Tuples have with explicit constant indexing like `[1]`, `[2]`, etc…?

Your recursive example is nice for the case where you want to loop over everything (here I just want index certain things by hand). A blog post about it could be nice, I think its similar the way `broadcast` is kept type stable, and definitely reading that code was a big “aha” moment for me.

---

<div class="post-metadata">

**Author:** ![pint](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pint/32/125_2.png) [@pint](https://discourse.julialang.org/u/pint)\
**Post date:** [March 27, 2017, 11:26am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/4 "2017-03-27T11:26:05Z")

</div>

i can’t try now, but maybe it works:

```julia
getindex{N}(t::TupleWrapper, ::Val{N}) = t.data[N]
@inline getindex(t::TupleWrapper, n) = getindex(t, Val{n}())

```

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [March 27, 2017, 11:50am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/5 "2017-03-27T11:50:20Z")

</div>

> [@marius311](#):
>
> Thanks for the reply. Yea, I am definitely not trying to do this with run-time integers, where I’d expect it to be hopeless. But like you see above, while x[1]; x[2]; x[3] is type-stable for an inhomogenous Tuple, it’s not type-stable for my TupleWrapper, even though I’m just forwarding to the underlying Tuple function. This is surely because by the time i makes it to my getindex function, its a run-time integer, but I’m wondering if there’s a way to preserve the functionality normal Tuples have with explicit constant indexing like [1], [2], etc…?

Oh I see. My bad! I read the problem wrong. I saw a runtime value used for tuples (in the `getindex` function) and a type-stability issue and took off on that 🙂. But yeah…

> <https://github.com/JuliaLang/julia/blob/master/base/tuple.jl#L21>

Looks like that works by inlining a `getfield` call? I’m not sure why your `getindex` wouldn’t work if theirs does, unless it needs another compiler pass or something. I tried adding `@inline` to yours to see if it would do anything… nope.

> [@pint](#):
>
> i can’t try now, but maybe it works:

That infers `Any`.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [March 27, 2017, 1:27pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/6 "2017-03-27T13:27:35Z")

</div>

If I understand correctly, inlining can never help with type stability, because it’s done after the type inference step ([https://github.com/JuliaLang/julia/issues/17880](https://github.com/JuliaLang/julia/issues/17880)). It’s a significant issue for my code, too… I don’t think there’s a solution to your problem, except to use `Val{i}` for the index. In general you can use a macro to avoid the problem, but it doesn’t work because you need dispatch.

---

<div class="post-metadata">

**Author:** ![andyferris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyferris/32/235_2.png) [@andyferris](https://discourse.julialang.org/u/andyferris)\
**Post date:** [March 28, 2017, 9:44am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/7 "2017-03-28T09:44:16Z")

</div>

Yep, this one comes up a fair bit in my work. The current solution is a macro or a `Val` or your own defined indexing type. Recursion and generated functions work well with `map` and `reduce`-style functions.

To me, it seems a bit of a pity that inlining happens strictly after type inference. My understanding is that it wouldn’t be trivial to implement inlining as a part of the inference loop and have it be efficient (compilation would become slower). OTOH I’m not aware of any other language that implements interprocedural constant propagation, so perhaps that is fair.

But some solution to this problem would open up APIs currently not possible for these kind of containers.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 9:55am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/8 "2017-09-17T09:55:36Z")

</div>

Hello,

I am having exactly the same problem. I want to index a container of a tuple in a type-stable way. There have been many suggestions here on how to do this, but I am a beginner.

Is there a way I can get some info on how to do this “with a macro or with `Val`” ?

I have tried the

```julia
getindex{N}(t::TupleWrapper, ::Val{N}) = t.data[N]
@inline getindex(t::TupleWrapper, n) = getindex(t, Val{n}())

```

approach but it doesn’t work. So now I am looking on doing it with a generated function  
`@generated function getmyfield ` . Is there any tutorial on that?

I tried the extremely naive:

```julia
@generated function getobstacle(BT::BilliardTable{T, S}, i::Int) where {T,S}
    return :(BT.bt[i])
end

```

but it didn’t work! I would appreciate some hints in the right direction.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [September 17, 2017, 11:53am UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/9 "2017-09-17T11:53:58Z")

</div>

> [@Datseris](#):
>
> getindex{N}(t::TupleWrapper, ::Val{N}) = t.data[N]  
> @inline getindex(t::TupleWrapper, n) = getindex(t, Val{n}())

```julia
getindex{N}(t::TupleWrapper, ::Val{N}) = t.data[N]
@inline getindex(t::TupleWrapper, n) = getindex(t, Val{n}())

```

The first definition is right, but the second isn’t type-stable. You have to use `mywrapper[Val{N}]` in every call. See [https://docs.julialang.org/en/latest/manual/performance-tips/#Types-with-values-as-parameters-1](https://docs.julialang.org/en/latest/manual/performance-tips/#Types-with-values-as-parameters-1)

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 12:37pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/10 "2017-09-17T12:37:04Z")

</div>

Thanks for the answer. I have done the following, which work so far, after many different combinations of tests:

```julia
immutable BilliardTable{T, BT<:Tuple}
    bt::BT
end

ObstInd(i::Int) = SVector{1, Val{i}}(Val(i))

getobstacle(bt::BilliardTable{T,S}, ::Val{N}) where {T,S,N} = bt.bt[N]
getobstacle(bt::BilliardTable{T,S}, ::SVector{1, Val{N}}) where {T,S,N} = bt.bt[N]

```

Both of the above `getobstacle` functions pass the `@inferred` test. In the second case I have to explicitly **first construct** an `SVector` by calling `ObstInd(3)` and then call `getobstacle`.

Now, when I do:  
`getobstacle(bt::BilliardTable{T,S}, N::Int) where {T,S} = getobstacle(bt, ObstInd(N)) `  
it doesn’t infer anymore.

I am guessing that this is what you meant by passing `mywrapper` in every call. Is there any super efficient wrapper I can create myself? thus far I am using an `SVector{1}` but maybe it can be done better?..

Thanks for the help though!

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 12:42pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/11 "2017-09-17T12:42:41Z")

</div>

Also, how can this be done with generated functions? Is there any code existing that already does it and I can look at? By myself I didn’t have much progress.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [September 17, 2017, 12:43pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/12 "2017-09-17T12:43:37Z")

</div>

A type stable function has, for each argument types, a single concrete return type. For example, `sin(::Int)` always returns a `Float64`, and so it is type-stable. Your `ObstInd(i::Int)` function cannot be type-stable, because depending on the _value_ of i, it can return an object of type `SVector{1, Val{1}}`, `SVector{1, Val{2}}`, etc. You could fix this by rewriting `ObstInd` as `ObstInd{N}(::Val{N}) = ...`

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 12:52pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/13 "2017-09-17T12:52:36Z")

</div>

The function: `ObstInd(::Val{N}) where {N} = SVector{1, Val{N}}(Val(N)) ` passes the `@inferred` test.  
However, using:

```julia
getobstacle(bt::BilliardTable{T,S}, N::Int) where {T,S} = 
getobstacle(bt, ObstInd(Val(N)))

```

Fails. The inferred type is `Any`.

EDIT: I can see why this last function `getobstacle(bt, N::Int)` is type unstable!  
Is there any way to fix it / make it work?

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [September 17, 2017, 1:10pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/14 "2017-09-17T13:10:38Z")

</div>

> [@Datseris](#):
>
> I can see why this last function getobstacle(bt, N::Int) is type unstable!
> 
> Is there any way to fix it / make it work?

You have to pass `Val{N}` and `ObstInd{Val{N}}` objects everywhere (\*) instead of `Int`s.

(\*) everywhere that’s performance-sensitive.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 1:18pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/15 "2017-09-17T13:18:35Z")

</div>

Great. I have done it, and now my huge function that indexes that Billiard thing is type stable.

However, it is 1000 times slower than using simply a Vector (instead of a Wrapper around a Tuple) even though the vector case has major inference issues.

Is this because of using `Val{i}` in all of the innermost loops of a big (and expensive) function?

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [September 17, 2017, 1:39pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/16 "2017-09-17T13:39:25Z")

</div>

[https://docs.julialang.org/en/latest/manual/performance-tips/#The-dangers-of-abusing-multiple-dispatch-(aka,-more-on-types-with-values-as-parameters)-1](https://docs.julialang.org/en/latest/manual/performance-tips/#The-dangers-of-abusing-multiple-dispatch-(aka,-more-on-types-with-values-as-parameters)-1)

> even though the vector case has major inference issues.

What are those? What’s in your vector/tuple?

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 1:48pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/17 "2017-09-17T13:48:05Z")

</div>

My basic type is `Obstacle{T} where {T<:AbstractFloat}`. This is abstract.

My vector is `Vector{Obstacle{T}}` and inside contains numerous **concrete** objects of types `Wall{T}` and `Disk{T}`. I am constantly calling functions:

```julia
collisiontime(bt[i])
resolvecollision!(bt[i]

```

etc. for all `i in eachindex(bt)`, with `bt` being this `Vector{Obstacle{T}}`. All of these functions operate with the concrete types `Wall, Disk`, each one is strictly typed.

Of course `bt[i]` is not type stable and so I have the inference issues here. I get around most of that, by declaring the local variables in my functions. E.g. in my code I write:  
`tmin::T = collisiontime(bt[i])` and similarly everywhere else.

For the change to “tuples” I created a wrapper

```julia
immutable BilliardTable{T, BT<:Tuple}
    bt::BT
end

getobstacle(bt::BilliardTable{T,S}, ::Val{N}) where {T,S,N} = bt.bt[N]

```

I create a tuple out of all the elements of the previous vector `bt` and I call that `BT`. Now,  
instead of having the non-inferable `bt[i]`, I replace this everywhere with `getobstacle(BT, Val(i))`. Pretty much everything else is left untouched.

When I benchmark the big function that encloses all these smaller functions, it is 1000 slower when using `BT` instead of `bt`.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [September 17, 2017, 2:37pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/18 "2017-09-17T14:37:35Z")

</div>

> [@Datseris](#):
>
> Is this because of using Val{i} in all of the innermost loops of a big (and expensive) function?

Are you only making `i` constants? This is about constants, not loops or anything like that. Of course when it’s not constant it won’t be type-inferrable.

---

<div class="post-metadata">

**Author:** ![Datseris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/datseris/32/13406_2.png) [@Datseris](https://discourse.julialang.org/u/Datseris)\
**Post date:** [September 17, 2017, 5:28pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/19 "2017-09-17T17:28:50Z")

</div>

Oh damn it! no it’s not a constant it is the variable of a `for` loop.

So what I am trying to do is not possible? To access a container that has more than 1 concrete `Type` in a type-stable way, when iterating trough the container as a loop?

---

<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:** [September 17, 2017, 8:18pm UTC](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889/20 "2017-09-17T20:18:39Z")

</div>

It’s not directly possible, since there’s no way for the compiler to know the type of each element if you’re just iterating through them in a loop. But there are a lot of other options to make this work:

- [Unrolled.jl](https://github.com/cstjean/Unrolled.jl)
- [ArrayPartition](https://github.com/JuliaDiffEq/RecursiveArrayTools.jl#arraypartition)
- [TypeSortedCollections.jl](https://github.com/tkoolen/TypeSortedCollections.jl)
- Lisp-y tuple recursion like in [Type stability when arguments are functions - #4 by tim.holy](https://discourse.julialang.org/t/type-stability-when-arguments-are-functions/4734/4)

(this isn’t specific to having a wrapper around a tuple–you’ll have the same issues with regular Julia tuples too). All of these make it possible to call a function on a mixture of types in an inferable way, without necessarily implementing a type-stable getindex().

Another option would be to store [FunctionWrappers](https://github.com/yuyichao/FunctionWrappers.jl) instead of the objects themselves in order to create a concretely-typed collection.

[Next page](https://discourse.julialang.org/t/is-there-a-way-to-forward-getindex-for-tuples-in-a-type-stable-way/2889.md?page=2)
