# Getting the parametric constructors from \`methods\`

**URL:** <https://discourse.julialang.org/t/getting-the-parametric-constructors-from-methods/96632>\
**Category:** General Usage\
**Tags:** parametric-types, methods, reflection\
**Created:** [March 26, 2023, 3:16pm UTC](https://discourse.julialang.org/t/getting-the-parametric-constructors-from-methods/96632 "2023-03-26T15:16:50Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [March 26, 2023, 3:16pm UTC](https://discourse.julialang.org/t/getting-the-parametric-constructors-from-methods/96632/1 "2023-03-26T15:16:50Z")

</div>

If I call `methods(Dict)`, it just returns the “non-parametric constructors”:

```julia
julia> methods(Dict)
# 5 methods for type constructor:
[1] Dict() in Base at dict.jl:118
[2] Dict(ps::Pair{K, V}...) where {K, V} in Base at dict.jl:124
[3] Dict(kv::Tuple{}) in Base at dict.jl:119
[4] Dict(ps::Pair...) in Base at dict.jl:125
[5] Dict(kv) in Base at dict.jl:127

```

I can get the “parametric constructors” with a call like this:

```julia
julia> methods(Dict{Int,Int})
# 6 methods for type constructor:
[1] Dict{K, V}() where {K, V} in Base at dict.jl:88
[2] Dict{K, V}(d::Dict{K, V}) where {K, V} in Base at dict.jl:92
[3] Dict{K, V}(p::Pair) where {K, V} in Base at dict.jl:108
[4] Dict{K, V}(ps::Pair...) where {K, V} in Base at dict.jl:109
[5] Dict{K, V}(kv) where {K, V} in Base at dict.jl:100
[6] Dict{K, V}(slots, keys, vals, ndel, count, age, idxfloor, maxprobe) where {K, V} in Base at dict.jl:96

```

However, I had hoped to be able to use a call like `methods(Dict{K,V} where {K,V})`, but that just returns the “non-parametric constructors”. Is there a more generic way of getting the `UnionAll` constructor methods for a type, rather than calling `methods` on a specific instance like `Dict{Int,Int}`?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [March 26, 2023, 3:56pm UTC](https://discourse.julialang.org/t/getting-the-parametric-constructors-from-methods/96632/2 "2023-03-26T15:56:37Z")

</div>

I suppose `Dict` is already `Dict{K,V} where {K,V}`, so it makes sense that those two return the same thing when provided to `methods`.

```julia
julia> Dict == (Dict{K,V} where {K,V})
true

```

---

<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:** [September 29, 2024, 1:42am UTC](https://discourse.julialang.org/t/getting-the-parametric-constructors-from-methods/96632/3 "2024-09-29T01:42:58Z")

</div>

I stumbled on a lifehack for parametric constructors! I was going to make a new topic, but maybe it’s fine to necropost when there’s no replies? Anyway, it seems to work on `Dict` (shows 11 methods), but I’ll demonstrate it on `Ref` because there’s an extra difficulty there:

```julia
julia> methods(Ref) # also methods(Ref{T} where T)
# 4 methods for type constructor:
 [1] Ref(x::Ptr{T}, i::Integer) where T
     @ Base refpointer.jl:142
 [2] Ref(x::Ref, i::Integer)
     @ Base refpointer.jl:141
 [3] Ref(x::AbstractArray, i::Integer)
     @ Base refpointer.jl:164
 [4] Ref(x)
     @ Base refpointer.jl:137

julia> methods(Ref{Int})
# 2 methods for type constructor:
 [1] Ref{T}() where T
     @ Base refpointer.jl:138
 [2] Ref{T}(x) where T
     @ Base refpointer.jl:139

```

However, the given parameters determine which methods the type reaches. In this case, a different parameter reaches more methods:

```julia
julia> methods(Ref{Ptr})
# 4 methods for type constructor:
 [1] Ref{P}(a::Array{<:Union{Cstring, Cwstring, Ptr}}) where P<:Union{Cstring, Cwstring, Ptr}
     @ Base refpointer.jl:145
 [2] Ref{P}(a::Array{T}) where {T, P<:Union{Cstring, Cwstring, Ptr}}
     @ Base refpointer.jl:148
 [3] Ref{T}() where T
     @ Base refpointer.jl:138
 [4] Ref{T}(x) where T
     @ Base refpointer.jl:139

```

But when we strip `UnionAll` to `DataType` by repetitively accessing the `body` field, we seem to get them all at once:

```julia
julia> methods(let x = Ref; while x isa UnionAll x = x.body end; x end)
# 8 methods for type constructor:
 [1] Ref{P}(a::Array{<:Union{Cstring, Cwstring, Ptr}}) where P<:Union{Cstring, Cwstring, Ptr}
     @ Base refpointer.jl:145
 [2] Ref{P}(a::Array{T}) where {T, P<:Union{Cstring, Cwstring, Ptr}}
     @ Base refpointer.jl:148
 [3] Ref(x::Ptr{T}, i::Integer) where T
     @ Base refpointer.jl:142
 [4] Ref(x::Ref, i::Integer)
     @ Base refpointer.jl:141
 [5] Ref(x::AbstractArray, i::Integer)
     @ Base refpointer.jl:164
 [6] Ref{T}() where T
     @ Base refpointer.jl:138
 [7] Ref(x)
     @ Base refpointer.jl:137
 [8] Ref{T}(x) where T
     @ Base refpointer.jl:139

```

I’m assuming this only works because the stripped `DataType` can actually be called for instantiation, which seems like a quirk of internals.

```julia
julia> Ref.body(6)
Base.RefValue{Int64}(6)

```

I’m stoked about this, but it’s still not proven if this gets ALL the methods; I don’t actually understand what `methods`’ docstring means by “the method table” when there appears to be overlapping _ad hoc_ tables over the type parameters. This also doesn’t work for parametric function-like objects aka functors because their concrete types constrain the type parameters; [there was work](https://github.com/JuliaLang/julia/pull/52304) toward reflection with the callable’s type, but I do not know if it would handle unspecified type parameters. If there’s a more stable way, I’m all ears.
