I have a type structure that looks something like this:
abstract type AbstractA{T} end
struct A1{T} <: AbstractA{T} end # no field of type `T`
A1() = A1{Any}()
struct A2{T} <: AbstractA{T} end
A2() = A2{Any}()
and I would like a conversion mechanism that converts from A1{T}
to A1{S}
(note that both A1{T}()
and A1{S}()
constructors are readily available) defined on the abstract type for use construction in a struct that holds a value A1{T}
with a specific T
based on context (other field types).
Currently I have defined the Base.convert
method like this
Base.convert(::Type{AbstractA{S}}, a::A) where {S,A<:AbstractA} = eval(A.name.name){S}()
This works as intended
julia> convert(AbstractA{Float64}, A1{Int32}())
A1{Float64}()
but this seems like quite a hack. My first question is, is there any better (more idiomatic) way to do this?
It also doesn’t solve the problem of conversion. I have a composite type defined as
struct Composite{T, P<:AbstractArray{T}, A<:AbstractA{T}}
t::P
a::A
Composite(aa::AbstractArray, a::AbstractA)= new{eltype(aa),typeof(aa),typeof(a)}(aa, a)
end
but calling the Composite
constructor with different parameter types for P
and A
fails
julia> Composite([5.0], A1())
ERROR: TypeError: in Composite, in A, expected A<:AbstractA{Float64}, got Type{A1{Any}}
[...]
I am not surprised by this since how would the constructor know, which of Float64
and Any
to prefer. My question is, how to define the constructor correctly so that the conversion works?
A question for better understanding: How does parameter type promotion in type constructors work and can I modify the precedence by defining methods of Base.promote_type
?