# Self-inflicted type proliferation

**URL:** <https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450>\
**Category:** Performance\
**Created:** [December 9, 2025, 1:59pm UTC](https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450 "2025-12-09T13:59:02Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![nilsbecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilsbecker/32/12157_2.png) [@nilsbecker](https://discourse.julialang.org/u/nilsbecker)\
**Post date:** [December 9, 2025, 1:59pm UTC](https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450/1 "2025-12-09T13:59:02Z")

</div>

I have the feeling I’m overdoing it / not doing the right thing with types. I’m wrapping `ODESolution`s coming from `OrdinaryDifferentialEquations` for downstream use like this:

```julia-auto
struct SolSR_FS{T<:Real,O,B} <: SolSR
  sol::O
  bd::B
  tspan::Tuple{T,T}
  tjumps::Vector{T}
end

struct SS_Data{N,T<:Real,V<:Real,O,B}
  # this mass of type parameters sure is ugly. but it does improve performance
  # for S_to_end! Not clear what the most compact way would be to achieve
  # performance.
  sol :: SolSR_FS{T,O,B}
  ts :: SVector{N,T}
  R_steps :: SVector{N,V}
  lambda_emR_steps :: SVector{N,V}
end

```

Here the `T` is the time type and `V` the value element type of the solution, and I introduced `O` and `B` solely because they make a downstream function `f(::SS_Data, args...)` faster and eliminate any red lines in `@code_warntype`  
But I feel this ugly zoo of types must be at least partially unnecessary? Is there a better way to tell downstream that the output `sol(t)` is of a known type?

---

<div class="post-metadata">

**Author:** ![mxhbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mxhbl/32/211886_2.png) [@mxhbl](https://discourse.julialang.org/u/mxhbl)\
**Post date:** [December 9, 2025, 3:53pm UTC](https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450/2 "2025-12-09T15:53:28Z")

</div>

If you don’t want to carry around `O` and `B`, you could just define

```julia-auto
struct SS_Data{N,T<:Real,V<:Real,SOL<:SolSR}
  sol :: SOL
  ts :: SVector{N,T}
  R_steps :: SVector{N,V}
  lambda_emR_steps :: SVector{N,V}
end

```

which should have the same performance.

---

<div class="post-metadata">

**Author:** ![nilsbecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilsbecker/32/12157_2.png) [@nilsbecker](https://discourse.julialang.org/u/nilsbecker)\
**Post date:** [December 9, 2025, 3:55pm UTC](https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450/3 "2025-12-09T15:55:37Z")

</div>

but keeping the parameters in `SolSR_FS` ? (my supertype `SolSR` has no parameters)

---

<div class="post-metadata">

**Author:** ![mxhbl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mxhbl/32/211886_2.png) [@mxhbl](https://discourse.julialang.org/u/mxhbl)\
**Post date:** [December 10, 2025, 8:34am UTC](https://discourse.julialang.org/t/self-inflicted-type-proliferation/134450/4 "2025-12-10T08:34:02Z")

</div>

Yes, unless you know the exact type of `O` or `B` beforehand it’s best to keep them as parameters. Even if you did know their type beforehand in your specific case, having them as parameters makes your code more flexible.

For comparison, this is the definition of `ODESolution` itself (from [SciMLBase.jl/src/solutions/ode\_solutions.jl at c34519d2948b15145c407b0d55c7b79e16c2f4b4 · SciML/SciMLBase.jl · GitHub](https://github.com/SciML/SciMLBase.jl/blob/c34519d2948b15145c407b0d55c7b79e16c2f4b4/src/solutions/ode_solutions.jl#L108))

```julia
struct ODESolution{T, N, uType, uType2, DType, tType, rateType, discType, P, A, IType, S,
    AC <: Union{Nothing, Vector{Int}}, R, O, V} <:
       AbstractODESolution{T, N, uType}
    u::uType
    u_analytic::uType2
    errors::DType
    t::tType
    k::rateType
    discretes::discType
    prob::P
    alg::A
    interp::IType
    dense::Bool
    tslocation::Int
    stats::S
    alg_choice::AC
    retcode::ReturnCode.T
    resid::R
    original::O
    saved_subsystem::V
end

```

Almost every field has its own type parameter. But you don’t need to write these out in your definition of `SolSR_FS`, in the same way you don’t need to write out the type parameters of `SolSR_FS` in the definition of `SS_Data`.

Of course, sometimes it is useful to (partially) write out the signature, for example if you want to enforce constraints on type parameters (e.g. if you wanted to make sure some number types are equal.)
