Better way to get the corresponding constructor from composite-type instances?

MWE:

julia> abstract type MyType{T} <: Any end

julia> struct myT1{T} <: MyType{T}
       a::T
       end

julia> struct myT2{T} <: MyType{T}
       a::T
       end

julia> getBuilder(a::MyType) = getfield(Main, (nameof∘typeof)(a))
getBuilder (generic function with 1 method)

julia> m1 = myT1(1.3)
myT1{Float64}(1.3)

julia> m2 = myT2(1.4)
myT2{Float64}(1.4)

julia> getBuilder(m1) == myT1
true

julia> getBuilder(m2) == myT2
true

Is there a better solution than how getBuilder is currently defined? Thanks!

1 Like

Maybe getBuilder(a::T{<:Any}) where {T<:MyType}=T?

I don’t think this is the sort of thing that you generally should be doing. Can you tell us the higher level goal? We might be able to suggest a better pattern.

2 Likes

If I understand correctly, the general consensus is that it is “hacky” and you shouldn’t do it. See Search results for 'strip type parameters' - Julia Programming Language

If you own the types, you could just do

myBuilder(::myT1) = myT1
myBuilder(::myT2) = myT2

If you have many types, you could achieve the same with less typing with metaprogramming, i.e. maybe something like

for op ∈ (:myT1, :myT2)
           eval(quote
               getBuilder(::$op) = $op
           end)
       end
1 Like

This was discussed a little while ago in this thread: Is there a way to get a UnionAll base type from a concrete type?

One good way seems to be to use the package ConstructionBase.jl, and write

using ConstructionBase
m1 = myT1(1.0)
constructorof(typeof(m1)) # myT1

It’s not defined for instances, but you could define

builder(x::Type) = constructorof(x)
builder(x) = builder(typeof(x))
2 Likes