# Use function on type parameter to decide struct field type at compile time

**URL:** <https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172>\
**Category:** General Usage\
**Tags:** performance, type\
**Created:** [October 24, 2022, 2:55am UTC](https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172 "2022-10-24T02:55:25Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [October 24, 2022, 2:55am UTC](https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172/1 "2022-10-24T02:55:25Z")

</div>

This code does not work, but I want to do something like the following (the general idea should be clear):

```julia
map_type(::Type{String}) = Int64
map_type(::Type{Int64}) = String

struct Foo{T}
    a::map_type(T)
end

```

Basically the function map\_type can be fully resolved at compile time so one could imagine a world where this works. But if you enter this in to the REPL you will see

```julia
ERROR: MethodError: no method matching map_type(::TypeVar)
Closest candidates are:
  map_type(::Type{String})
  map_type(::Type{Int64})

```

Is there a way to achieve such a thing? Presumably in a real world use case the `map_type` function would be a little more complicated. A motivating example may be to do the following transformation:

```julia
map_type(::Val{N}, ::Type{T}) where T <: NTuple{N, Real} where N = begin
    [Foo{fieldtype(T, i)} for i in 1:N]
end

struct Foo{T <: Real}
    a :: T
end

struct Bar{N, T <: NTuple{N, Real}}
    foos::Tuple{map_type(Val(N), T)...}
end

```

This doesn’t work, but the idea is to allow `Bar` to contain a variable number of differently parameterized `Foo`s in a type-stable way.

I understand this is bordering abuse of the type system, but I have a use case in mind for creating a time series iterator that merges a variable number of other time series iterators (output in chronological order from multiple iterators). Obviously the output of such an iterator would not be type-stable (unless all underlying iterators output the same type), but it could be restricted to a small `Union `type so that the compiler could still use a union splitting optimization for performance. (Or at least that is my theory)

---

<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:** [October 24, 2022, 4:04am UTC](https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172/2 "2022-10-24T04:04:28Z")

</div>

There’s no way to do this the way you’ve specified it, unfortunately. Generally you’d work around this by adding another type parameter, like:

```julia
struct Foo{T, V}
  a::V
  
  Foo{T}(a) where {T} = new{T, map_type(T)}(a)
end

```

where the inner constructor is responsible for computing `V`. The [ComputedFieldTypes](https://github.com/vtjnash/ComputedFieldTypes.jl) package has a couple of macros to make that pattern a little bit easier.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [October 24, 2022, 4:32am UTC](https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172/3 "2022-10-24T04:32:28Z")

</div>

So just to see if I understand, I could do the more complicated goal I was trying to achieve simply with:

```julia
struct Foo{T <: Real}
    a :: T
end

struct Bar{T}
    foos::T

    Bar(foos) = begin
        new{Tuple{[typeof(f) for f in foos]...}}(foos)
    end
end

f1 = Foo(1)
f2 = Foo(2.0)
b = Bar((f1, f2))
typeof(b) === Bar{Tuple{Foo{Int64}, Foo{Float64}}} # true

```

Moreover will any function I call with `b` that access the underlying `foos` generate efficient code since the compiler knows the types of each `foo`?

For example in:

```julia
test_func(b::Bar) = begin
    s = 0.0    
    for f in b.foos
        s += f.a
    end
end

```

will the compiler unfold the loop and insert the appropriate addition calls since it knows the type of each f exactly?

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [October 24, 2022, 4:47am UTC](https://discourse.julialang.org/t/use-function-on-type-parameter-to-decide-struct-field-type-at-compile-time/89172/4 "2022-10-24T04:47:07Z")

</div>

Actually based on the output of `@code_warntype` using a `for` loop does still yield type instability because the type of `f` is different on each iteration.

Replacing the for loop with individual indexing:

```julia
s += b.foos[1].a
s += b.foos[2].a

```

yields completely type stable code. Look at this interesting thread for interesting general approaches that don’t involve hardcoding [Type stability while looping over Tuple](https://discourse.julialang.org/t/type-stability-while-looping-over-tuple/83272). Namely recursion and the Unrolled.jl package
