# How to get a tuple's field using a runtime index in a type stable way?

**URL:** https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629
**Category:** General Usage
**Created:** [March 14, 2024, 7:17pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629 "2024-03-14T19:17:46Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 14, 2024, 7:17pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/1 "2024-03-14T19:17:46Z")

</div>

Suppose I have a tuple, which contains some data. I want to get one of the fields of the tuple, with an index at runtime, _but I know the type of the field the index points to_. Is there a way to do this?

My best attempt so far is the follow:

```julia
tup = (10, 100, 1., 2., 3.)

function test(tup, idx, type::Type{T}) where T
    ret::T = tup[idx]
    ret
end

@time test(tup, 1, Int)

```

But this allocates:

```julia
0.000008 seconds (1 allocation: 48 bytes)

```

I want to tell the compiler this is always going to be type T, and if its not it can throw an error BEFORE it gets the field. Is there a way to do this with generated functions or some Core compiler hint or some other nasty trick?

---

<div class="post-metadata">

### Author: ![JonasWickman](https://avatars.discourse-cdn.com/v4/letter/j/9de0a6/32.png) [@JonasWickman](https://discourse.julialang.org/u/JonasWickman)
#### Post date: [March 14, 2024, 7:58pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/2 "2024-03-14T19:58:09Z")

</div>

This probably doesn’t help your actual use case (though maybe), but I think you get an allocation here becease `tup` is a global variable. Try `@test`ing this:

```julia
function outer_test()
    tup = (10, 100, 1., 2., 3.)
    ret = test(tup, 1, Int)
end

```

and you’ll get zero allocations. However, in this case, `1` is a constant index, which is why you’re not getting an allocation.

This won’t help you if your actual index is truly generated at runtime though.

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 14, 2024, 8:00pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/3 "2024-03-14T20:00:47Z")

</div>

Thanks for the reply!

I modified your example so the idx is randomly chosen between 1 and 2

```julia
function test(tup, idx, type::Type{T}) where T
    # @inline Core.getfield(tup, idx)::T
    # Core.unsafe_convert(T, Core.getfield(tup, idx))
    # Core.get_binding_type
    ret::T = Base.getindex(tup, idx)
end

function outer_test()
    tup = (10, 100, 1., 2., 3.)
    idx = rand((1, 2))
    @noinline ret = test(tup, idx, Int)
end

@time outer_test()

```

With the @noinline, we still get 1 allocation. Without it, we don’t…

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 14, 2024, 8:18pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/4 "2024-03-14T20:18:32Z")

</div>

Intuitively, I feel like this should be possible. Please, if anyone experienced can tell me why it isn’t, I would appreciate it.

---

<div class="post-metadata">

### Author: ![raminammour](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raminammour/32/13572_2.png) [@raminammour](https://discourse.julialang.org/u/raminammour)
#### Post date: [March 14, 2024, 9:29pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/5 "2024-03-14T21:29:02Z")

</div>

As you can tell, it took a few tries 😃

```julia
function test4(tup,idx,typ::Type{T}) where T
       idx == 1 && (x=first(tup); isa(x,T) && return x)
       test4(Base.tail(tup),idx-1,T)
end

```

This seems to do the trick and not allocate (throws an error otherwise), it is also type stable. `outer_test` would not allocate regardless of inlining.

Hope this helps…

Edit:  
This seems to do the same and simpler:

```julia
function test4(tup,idx,typ::Type{T}) where T
       idx == 1 && (x=first(tup); return x::T) 
       #or if you want an explicit error
       #isa(x,T) ? (return x) : error("Bla"))
       test4(Base.tail(tup),idx-1,T)
end

```

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [March 14, 2024, 10:02pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/6 "2024-03-14T22:02:17Z")

</div>

Have you considered, alternatively, the use of named tuples?

```julia
nt=(;zip([:a,:b,:c,:d,:e],tup)...)
julia> @btime $nt.e
  1.500 ns (0 allocations: 0 bytes)
3.0

julia> @btime $nt.b
  1.500 ns (0 allocations: 0 bytes)
100

```

or

```julia

function test(tup, idx)
    ret = getfield(tup,idx)
    ret
end

@btime test($tup, 4)

function test1(tup, idx)
     r=first(iterate(tup,idx))
     r
end

```

---

<div class="post-metadata">

### Author: ![cortner](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cortner/32/204_2.png) [@cortner](https://discourse.julialang.org/u/cortner)
#### Post date: [March 14, 2024, 11:53pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/7 "2024-03-14T23:53:46Z")

</div>

I think this is only possible if you know the returned type.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [March 14, 2024, 11:55pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/8 "2024-03-14T23:55:01Z")

</div>

> [@Larbino1](#):
>
> But this allocates:

Are you sure that `test(...)` allocates?

```julia-repl
julia> const tup_const = (10, 100, 1., 2., 3.)
(10, 100, 1.0, 2.0, 3.0)

julia> function test(tup, idx, type::Type{T}) where T
           ret::T = tup[idx]
           ret
       end
test (generic function with 1 method)

julia> @time test(tup_const, 3, Float64)
  0.000003 seconds
1.0

julia> @btime test(tup_const, 3, Float64)
  1.041 ns (0 allocations: 0 bytes)
1.0

```

You may also want to consider the effect of constant propagation.

Note the union type below.

```julia-repl
julia> @code_warntype test(tup_const, 3, Float64)
MethodInstance for test(::Tuple{Int64, Int64, Float64, Float64, Float64}, ::Int64, ::Type{Float64})
  from test(tup, idx, type::Type{T}) where T @ Main REPL[27]:1
Static Parameters
  T = Float64
Arguments
  #self#::Core.Const(test)
  tup::Tuple{Int64, Int64, Float64, Float64, Float64}
  idx::Int64
  type::Core.Const(Float64)
Locals
  ret::Float64
  @_6::Union{Float64, Int64}
Body::Float64
1 ─ Core.NewvarNode(:(ret))
│ %2 = Base.getindex(tup, idx)::Union{Float64, Int64}
│ (@_6 = %2)
│ %4 = (@_6 isa $(Expr(:static_parameter, 1)))::Bool
└── goto #3 if not %4
2 ─ goto #4
3 ─ %7 = Base.convert($(Expr(:static_parameter, 1)), @_6::Int64)::Float64
└── (@_6 = Core.typeassert(%7, $(Expr(:static_parameter, 1))))
4 ┄ (ret = @_6::Float64)
└── return ret

```

If we create a function with the index three hard-coded in, we see the absence of instability.

```julia-repl
julia> function test2(tup, idx)
           tup[idx]
       end
test2 (generic function with 2 methods)

julia> f(tup) = @inline test2(tup, 3)
f (generic function with 1 method)

julia> @code_warntype f(tup_const)
MethodInstance for f(::Tuple{Int64, Int64, Float64, Float64, Float64})
  from f(tup) @ Main REPL[43]:1
Arguments
  #self#::Core.Const(f)
  tup::Tuple{Int64, Int64, Float64, Float64, Float64}
Locals
  val::Float64
Body::Float64
1 ─ nothing
│ (val = Main.test2(tup, 3))
│ nothing
└── return val

```

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [March 15, 2024, 8:04am UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/9 "2024-03-15T08:04:28Z")

</div>

> [@Larbino1](#):
>
> With the @noinline, we still get 1 allocation. Without it, we don’t…

The `test` call was simple enough to inline, resulting in the `getindex` call being directly in `outer_test`. `tup`’s type only contains `Int` or `Float64`, so the compiler can infer that an inlined `getindex` only returns a `Int` or `Float64`. Hypothetically the compiler could’ve leveraged the niche detail that `rand((1,2))` only selects the indices with `Int`, but the compiler evidently doesn’t go that far. On the other hand, if the tuple contained 4+ types, the `getindex` return type is inferred as `Any`. You can see the effect directly in the `getindex` call:

```julia
julia> @code_warntype getindex((10, 100, 1., 2., 3.), 2)
MethodInstance for getindex(::Tuple{Int64, Int64, Float64, Float64, Float64}, ::Int64)
  from getindex(t::Tuple, i::Int64) @ Base tuple.jl:31
Arguments
  #self#::Core.Const(getindex)
  t::Tuple{Int64, Int64, Float64, Float64, Float64}
  i::Int64
Body::Union{Float64, Int64}
1 ─ nothing
│ %2 = Base.getfield(t, i, $(Expr(:boundscheck)))::Union{Float64, Int64}
└── return %2

julia> @code_warntype getindex((10, 100im, 1., 2.0im, 3.), 2)
MethodInstance for getindex(::Tuple{Int64, Complex{Int64}, Float64, ComplexF64, Float64}, ::Int64)
  from getindex(t::Tuple, i::Int64) @ Base tuple.jl:31
Arguments
  #self#::Core.Const(getindex)
  t::Tuple{Int64, Complex{Int64}, Float64, ComplexF64, Float64}
  i::Int64
Body::Any
1 ─ nothing
│ %2 = Base.getfield(t, i, $(Expr(:boundscheck)))::Any
└── return %2

```

If your index isn’t a literal or a constant, limiting the number of types in the tuple to 3 (a limit that can change across minor revisions) is the best you can hope for. To `@time` this properly, you’d need a global variable to hold the index instead of inputting a literal, otherwise the compiler knows the exact index and type, making the type inference report above irrelevant. Note that this specialization over the literal or constant value rather than its type `Int` is not a general feature, the compiler treats the underlying built-in function `Core.getfield` specially.

```julia
julia> @time getindex((10, 100, 1., 2., 3.), 2);
  0.000001 seconds

julia> @time getindex((10, 100im, 1., 2.0im, 3.), 2);
  0.000004 seconds

julia> i::Int = 2;

julia> @time getindex((10, 100, 1., 2., 3.), i);
  0.000009 seconds

julia> @time getindex((10, 100im, 1., 2.0im, 3.), i);
  0.000014 seconds (1 allocation: 32 bytes)

```

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [March 15, 2024, 10:40am UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/10 "2024-03-15T10:40:13Z")

</div>

That’s awesome @raminammour! I think it can be further simplified a bit:

```julia
function test5(tup, idx, type)
    idx == 1 && return tup[1]::type
    test5(Base.tail(tup), idx-1, type)
end

```

I think we can even drop the type argument while maintaining the same performance:

```julia
function test6(tup, idx)
    idx == 1 && return tup[1]
    test6(Base.tail(tup), idx-1)
end

```

(and call with `test6(tup, idx)::type` if necessary).

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 15, 2024, 11:40am UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/11 "2024-03-15T11:40:13Z")

</div>

> [@raminammour](#):
>
> ```julia
> function test4(tup,idx,typ::Type{T}) where T
> idx == 1 && (x=first(tup); return x::T) 
> #or if you want an explicit error
> #isa(x,T) ? (return x) : error("Bla"))
> test4(Base.tail(tup),idx-1,T)
> end
> 
> ```

Wow! Thank you, this is great 😃

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 15, 2024, 11:40am UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/12 "2024-03-15T11:40:40Z")

</div>

Yes, I stated that I do know the return type.

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 15, 2024, 11:42am UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/13 "2024-03-15T11:42:11Z")

</div>

The problem is explicitly how to solve this when we can’t hard code in the index, but you (somehow) know the return type. If you can hard code the index it is trivial

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [March 15, 2024, 12:48pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/14 "2024-03-15T12:48:26Z")

</div>

@Larbino1 the way I’d recommend approaching this would be to re-order your `Tuple{Int, Int, Float64, Float64, Float64}` into a `Tuple{Tuple{Int, Int}, Tuple{Float64, Float64, Float64}}` because then the compiler can better understand what is going on.

You’d then index this thing like `new_tup[1][i]` where `1` and `2` are the only valid indices of `new_tup[1]`.

* * *

If you want to get kinda fancy though, an alternative would be to make a `MaskedTuple{T, Tup}` type that behaves like `Tup <: Tuple` except only lets you grab the entries of type `T`.

e.g. something like

```julia
struct MaskedTuple{T, Tup <: Tuple, N}
    masked_tup::Tup
    inds::NTuple{N, Int}
    function MaskedTuple{T}(tup::Tuple) where {T}
        masked_tup = filter(x -> x isa T, tup)
        counter = Ref(0)
        inds = ntuple(length(tup)) do i
            if tup[i] isa T
                counter[] += 1
            else
                0
            end
        end
        new{T, typeof(masked_tup), length(inds)}(masked_tup, inds)
    end
end
Base.length(mt::MaskedTuple) = length(mt.inds)
Base.getindex(m::MaskedTuple{T}, i::Int) where {T} = let j = m.inds[i]
    if j === 0
        @noinline ((i, m, T) -> error(lazy"Index $i of $m is not of type $T"))(i, m, T)
    end
    m.masked_tup[j]
end

function Base.show(io::IO, mt::MaskedTuple{T}) where {T}
    print(io, "MaskedTuple{$T}(" * join((mt.inds[i] == 0 ? "_" : mt[i] for i ∈ 1:length(mt)), ", ")* ")")
end

```

and then

```julia-repl
julia> function test(tup, idx, ::Type{T}) where {T}
           MaskedTuple{T}(tup)[idx]
       end;

julia> let tup = Ref((1, 2, 3.0, 4.0, 5.0))
           @btime test($tup[], rand(1:2), Int)
       end;
  4.970 ns (0 allocations: 0 bytes)
1

```

This works because we’ve made it so that we’re only ever accessing a `Tuple{Int, Int}`, at an unkown index rather than a `Tuple{Int, Int, Float64, Float64, Float64}`.

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 15, 2024, 1:13pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/15 "2024-03-15T13:13:07Z")

</div>

This is a pattern I’ve ended up creating several times for may package. I wonder if it has a name or a better implementation.

Consider this: I have a machine with many buttons, of many (but fewer) different types. I want to store a collection of buttons and `press` all the buttons, but in a type stable way.

The way I end up solving this is with a `Tuple{Vector{ButtonType1}, Vector{ButtonType2}...}`, then to add a button, I use a generated function to add it to the right vector. I can keep an index to this button so I can get back to it later which is something like `CollectionIndex(Val{tupidx}(), vecidx)`

This way, we don’t create huge tuples (only as big as the numbe of types), we can still map/foreach etc. over the collection;  
`map(press, button_collection)`  
by implementing map on our collection, and we can still go back inside the collection and get the items in a type stable way (as tupidx is known at compile time due to being a Val)

---

<div class="post-metadata">

### Author: ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)
#### Post date: [March 15, 2024, 2:22pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/16 "2024-03-15T14:22:48Z")

</div>

I did something like this for `Dict`s instead of `Vector`s about a year ago: [`ConcreteTupleDicts.jl`](https://github.com/SBuercklin/ConcreteTupleDicts.jl)

An equivalent backing for `Array`s or `Vector`s (or generalization which subsumes both the `Array` and `Dict` implementations) would probably be a useful contribution. My construction code is a bit messy because I was trying to get it type stable, but the retrieval worked nicely for the use-case I had

---

<div class="post-metadata">

### Author: ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)
#### Post date: [March 15, 2024, 2:29pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/17 "2024-03-15T14:29:29Z")

</div>

Another ref I ran into when working on the concrete tuple-dict stuff: [`TypeSortedCollections.jl`](https://github.com/tkoolen/TypeSortedCollections.jl)

I think this implements the pattern you described with tuples of vectors of homogeneous types

---

<div class="post-metadata">

### Author: ![Larbino1](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/larbino1/32/37831_2.png) [@Larbino1](https://discourse.julialang.org/u/Larbino1)
#### Post date: [March 15, 2024, 2:38pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/18 "2024-03-15T14:38:53Z")

</div>

Amazing, thank you!

EDIT: This is exactly what I was looking for, shame I didn’t manage to find it. Would have saved me many headaches, but now I can clean things up using it 🙂

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [March 15, 2024, 2:58pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/19 "2024-03-15T14:58:40Z")

</div>

> [@Larbino1](#):
>
> The problem is explicitly how to solve this when we can’t hard code in the index, but you (somehow) know the return type.

I would argue that we do know the return type from the tuple type. There should not be a need to encode the type at a particular index twice.

```julia-repl
julia> begin
           second(x) = x[2]
           third(x) = x[3]
           fourth(x) = x[4]
           fifth(x) = x[5]
       end
fifth (generic function with 1 method)

julia> square(f, tup) = f(tup)^2
square (generic function with 1 method)

julia> @code_warntype square(first, tup)
MethodInstance for square(::typeof(first), ::Tuple{Int64, Int64, Float64, Float64, Float64})
  from square(f, tup) @ Main REPL[13]:1
Arguments
  #self#::Core.Const(square)
  f::Core.Const(first)
  tup::Tuple{Int64, Int64, Float64, Float64, Float64}
Body::Int64
1 ─ %1 = Main.:^::Core.Const(^)
│ %2 = (f)(tup)::Int64
│ %3 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│ %4 = (%3)()::Core.Const(Val{2}())
│ %5 = Base.literal_pow(%1, %2, %4)::Int64
└── return %5

julia> @code_warntype square(fifth, tup)
MethodInstance for square(::typeof(fifth), ::Tuple{Int64, Int64, Float64, Float64, Float64})
  from square(f, tup) @ Main REPL[13]:1
Arguments
  #self#::Core.Const(square)
  f::Core.Const(fifth)
  tup::Tuple{Int64, Int64, Float64, Float64, Float64}
Body::Float64
1 ─ %1 = Main.:^::Core.Const(^)
│ %2 = (f)(tup)::Float64
│ %3 = Core.apply_type(Base.Val, 2)::Core.Const(Val{2})
│ %4 = (%3)()::Core.Const(Val{2}())
│ %5 = Base.literal_pow(%1, %2, %4)::Float64
└── return %5

```

---

<div class="post-metadata">

### Author: ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)
#### Post date: [March 15, 2024, 3:04pm UTC](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629/20 "2024-03-15T15:04:58Z")

</div>

> [@sbuercklin](#):
>
> [`TypeSortedCollections.jl`](https://github.com/tkoolen/TypeSortedCollections.jl)

See (my) [UnionCollections.jl](https://github.com/JuliaAPlavin/UnionCollections.jl) as well (: Appears to be more fully-featured for Arrays, also supports Dictionaries.

[Next page](https://discourse.julialang.org/t/how-to-get-a-tuples-field-using-a-runtime-index-in-a-type-stable-way/111629.md?page=2)
