Get generic constructor of parametric type

Is there a smart /easy way to get the generic constructor of a parametric type from its instance? I actually thought that this is a standard thing, but couldn’t find anything.

abstract type AbstractFooBar end
struct Foo{T} <: AbstractFooBar
    p::T
end
struct Bar{T} <: AbstractFooBar
    p::T
end
#= more subtypes
struct X{T} <: AbstractFooBar end
struct Y{T} <: AbstractFooBar end
.
=#

function get_generic_constructor(fb::AbstractFooBar)
    fb isa Bar && return Bar
    fb isa Foo && return Foo
    #= Would like to avoid doing  this for all subtybes of AbstractFooBar
    fb isa X && return X ...
    =#
end

What I want to archive is the following behavior:

a = Bar(3) 
#Bar{Int64}(3)
b =  get_generic_constructor(Bar(3))
#Bar
b("three") 
#Bar{String}("three")

I need this in my code to make it compatible to ForwardDiff.jl. So please my favorite community, enlighten me

Another way of saying what you want to do is to get the UnionAll type if it exists. You can get it with typeof(a).name.wrapper.
That line can also take types without parameters, but in those cases, typeof(a) === typeof(a).name.wrapper

1 Like

Thanks,
typeof(a).name.wrapper was what I was looking for.
Since I never saw this anywhere before and I encountered this problem already multiple times, I wonder if I do something fundamentally wrong. However thanks a lot…

Great, I had the same question and found the answer here. Whatever you do fundamentally, wrong, so do I !!!

1 Like

I think this solution depends on implementation details and, therefore, may break in any change of Julia versions. As far as I know, the founders/‘language designers’ have not decided on a way to do what you want to do, or even if having such feature is desirable.

1 Like

Do you know if there is an open issue about that somewhere?. Because I can think of several workarounds for this, but they all suffer from a lack of generically and I would like to know more about the pros and cons regarding such a feature.

Is this helpful ConstructionBase.jl/constructorof.md at master · JuliaObjects/ConstructionBase.jl · GitHub?

2 Likes

Absolutely!! The whole magic is actually done only by these lines:

@generated function constructorof(::Type{T}) where T
    getfield(parentmodule(T), nameof(T))
end

constructorof(typeof(a))  # Bar

I think you want issue 35543.

2 Likes