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> 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> 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> 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> 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 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.