# Public interface to get all type parameters?

**URL:** <https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514>\
**Category:** General Usage\
**Tags:** parametric-types\
**Created:** [September 17, 2024, 6:50pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514 "2024-09-17T18:50:10Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [September 17, 2024, 6:50pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/1 "2024-09-17T18:50:10Z")

</div>

Is it possible to implement the following function:

```julia
get_parameters(::Type{T}) where {T} = T.parameters

```

without relying on the internal field `parameters`? As far as I can tell, the answer seems to be no, since this approach keeps coming up as an answer to the question of how to get a type’s parameters, e. g.

> [@Get the type parameters of a parametric type](https://discourse.julialang.org/t/get-the-type-parameters-of-a-parametric-type/113308):
>
> I have an instance of a parametric type. Is it possible to somehow retrieve the type parameters for this instance? E.g. for ```julia struct MyStruct{T} x::T function MyStruct(x) return new{typeof(x)}(x) end end ms = MyStruct(1.0) typeof(ms) I'd like to know the type parameter `Float64`.

> [@Getting parameters of, and aliases for, any arbitrary type](https://discourse.julialang.org/t/getting-parameters-of-and-aliases-for-any-arbitrary-type/103616):
>
> Hello, and as always, thanks in advance for taking the time to read this post and help me out. I’m back to toying around with (and hopefully learning) Julia. In order to get a better feel for the type system and the possibilities that the language offers, I’ve decided to implement a subtype tree printer (probably a fairly common thing for novices to do). This is working fine, but it’s not showing all the info I’d like. Specifically, when a type takes parameters, it doesn’t list them; and whe…

and because of this old issue:

> <https://github.com/JuliaLang/julia/issues/20555#issuecomment-308969161>
>
> Julia allows for reflection.
> It is infact really powerful. You can do crazy thi…ngs \[like examine the code for a function programatically\](http://stackoverflow.com/a/39305272/179081).
> 
> My issue is that it is largely based on unexported methods, and on directly reading various fields. Sometimes in complicated ways. Code based on this "privately" facing API breaks every single release.
> 
> Consider, this example that came up in code I am writing.
> I would like to find out if a function has any methods that take a keyword arg with a given name.
> 
> \`\`\`julia
> function methods\_with\_kwarg(func::Function, kwarg\_name::Symbol)
> #BLACK-MAGIC, 0.5 only
> supporting\_methods = Method\[\]
> ml = methods(func)
> if isdefined(ml.mt, :kwsorter)
> kwsort\_t = typeof(ml.mt.kwsorter)
> for mmm in ml.ms
> sig = mmm.sig
> all\_kwarg\_list = Base.kwarg\_decl(sig, kwsort\_t)
> if kwarg\_name ∈ all\_kwarg\_list
> push!(supporting\_methods, mmm)
> end
> end
> end
> supporting\_methods
> end
> \`\`\`
> 
> \`\`\`julia
> julia\> methods\_with\_kwarg(repeat, :outer)
> 
> 1-element Array{Method,1}:
> - repeat(A::AbstractArray) at abstractarraymath.jl:329
> \`\`\`
> 
> So in that code, 2 Public API method was used: \`methods\` and \`isdefined\`.
> And then 5 private API methods/fields: \`MethodTable.kwsorter\`, \`Method.sig\`, \`MethodList.ms\`, \`MethodList.mt\`, and \`Base.kwarg\_decl\`.
> 
> They are all undocumented. and I know they change in 0.6, and in 0.4, and 0.3.
> It would be nice to be able to do reflection without having to go deep into the guts of the language.
> 
> Towards this end, I feel it is necessary to make a consideration of what reflection methods a language like julia should provide, and then define, export, and document methods to that end.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [September 17, 2024, 7:06pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/2 "2024-09-17T19:06:14Z")

</div>

I might misunderstand the question, but would something like

```julia-repl
julia> struct S{T1, T2} end

julia> get_parameters(::S{T1, T2}) where {T1, T2} = (T1, T2)
get_parameters (generic function with 1 method)

julia> s = S{Float32, UInt64}()
S{Float32, UInt64}()

julia> get_parameters(s)
(Float32, UInt64)

```

not work? (By the way, my suggestion here is very similar to [a post of @sylvaticus](https://discourse.julialang.org/t/get-the-type-parameters-of-a-parametric-type/113308/4) in the first topic thread you linked.)

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 17, 2024, 7:11pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/3 "2024-09-17T19:11:50Z")

</div>

> [@eldee](#):
>
> would something like […] not work?

That requires you to implement `get_parameters` for every new type. Which is fine if you only need to extract the parameters from a particular type you know about. But it isn’t quite the same as a general reflection API.

On the other hand, extracting parameters of arbitrary types you know nothing about is of much more limited utility, unless you are writing some kind of generic debugging/introspection tool.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 17, 2024, 7:16pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/4 "2024-09-17T19:16:48Z")

</div>

The key is really that you need to know _something_ about the type itself in order to do anything _meaningful_ with its parameters. And at that point, you might as well dispatch directly on the type (since you know it!).

What do you want to do with the parameters?

A decent alternative can be to expose the meaning you want in the parameters of an abstract supertype. The classic example here is `AbstractVector{T}`. I can’t expect that the first parameter of all arrays will be its eltype (simple counter-example: `BitArray{1}`). But I can dispatch on `::AbstractVector{T}` and always know that the `T` there is the eltype.

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [September 17, 2024, 8:01pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/5 "2024-09-17T20:01:22Z")

</div>

If your use-case is interactive, where performance is not too important, and if you are happy with the textual representation in `typeof`, but want to capture the parameters in a `Vector`, you could parse this string representation using something like

```julia
function get_parameters(x)
    s = string(typeof(x))
    params = []
    bracket_counter = 0 # nested param level
    prev_param_end = nothing
    for (i, c) in enumerate(s)
        if c == '{'
            bracket_counter += 1
            isnothing(prev_param_end) && (prev_param_end = i)
        elseif c == '}'
            bracket_counter -= 1
        end
        if c == ',' && bracket_counter == 1 || c == '}' && bracket_counter == 0
            push!(params, eval(Meta.parse(s0[prev_param_end+1 : i-1])))
            prev_param_end = i
        end
    end
    return params
end

```

Note that this not particularly elegant, but it gets the job done (for certain use-cases, as explained at the start of the post).

```julia-repl
julia> struct S{A, B, C} end

julia> s = S{UInt16, typeof(rand(2, 3)), 12}()
S{UInt16, Matrix{Float64}, 12}()

julia> get_parameters(s)
3-element Vector{Any}:
   UInt16
   Matrix{Float64} (alias for Array{Float64, 2})
 12

```

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [September 17, 2024, 8:28pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/6 "2024-09-17T20:28:52Z")

</div>

I appreciate all the answers trying to address potential use cases, but this was really a question about the language itself, so I’d be happy with a simple “no”. (Which seems to be the case?)

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [September 18, 2024, 12:56pm UTC](https://discourse.julialang.org/t/public-interface-to-get-all-type-parameters/119514/7 "2024-09-18T12:56:14Z")

</div>

Just stumbled across this more recent issue:

> <https://github.com/JuliaLang/julia/issues/45376>
>
> \`foo(@nospecialize(T::Type{\<:Foo})) = T.parameters\[1\]\` is helpful when Foo is co…mplicated and could potentially generate excessive methods otherwise (e.g., \`foo(::Type{\<:Foo{T1,T2,...}})\`). \[Keno recently pointed out\](https://github.com/SciML/Static.jl/pull/55#discussion\_r875407731) this isn't safe. I propose we standardize access to a types parameters with something like this: 
> 
> \`\`\`julia
> getparam(x::DataType, i::Int) = x.parameters\[i\]
> getparam(x::UnionAll, i::Int) = getparam(x.body, i)
> getparam(x::TypeVar, i::Int) = getparam(x.ub, i)
> getparam(x::Union, i::Int) = \_combine\_params(getparam(x.a, i), getparam(x.b, i))
> \_combine\_params(a::Type, b::Type) = typejoin(a, b)
> \_combine\_params(@nospecialize(a), @nospecialize(b)) = a === b ? a : Any
> \`\`\`

A bit of a more specific subset of the older issue linked above, and more relevant to the question.
