# Conversion of inner "flag" type parameters from supertype "flag" type parameters for composite struct construcor

**URL:** <https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306>\
**Category:** General Usage\
**Tags:** question, parametric-types, convert, constructors\
**Created:** [August 2, 2025, 10:49am UTC](https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306 "2025-08-02T10:49:25Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![kunzaatko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kunzaatko/32/25153_2.png) [@kunzaatko](https://discourse.julialang.org/u/kunzaatko)\
**Post date:** [August 2, 2025, 10:49am UTC](https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306/1 "2025-08-02T10:49:25Z")

</div>

I have a type structure that looks something like this:

```julia
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

```julia
Base.convert(::Type{AbstractA{S}}, a::A) where {S,A<:AbstractA} = eval(A.name.name){S}()

```

This works as intended

```julia-repl
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

```julia
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-repl
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`?

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [August 2, 2025, 11:55am UTC](https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306/2 "2025-08-02T11:55:47Z")

</div>

The `A.name.name` is an internal detail which is not guaranteed to work. It’s best to avoid it. However, I don’t think there’s a documented way to retrieve the `A1` from an object `A1{S}()`.  
What’s needed to solve it is constructions like `fun(a::T{S}) where {T<:AbstractA, S} ...`, but that’s not supported. Yet.

Unless you need to create subtypes of `AbstractA` on the fly, I suggest to make a convert method for each subtype. If one needs to create more, it can be embedded in some function to create the necessary converts and constructors:

```julia-auto
abstract type AbstractA{T} end

const subtypes = (:A1, :A2)
for subtype in subtypes
    @eval begin
        struct $subtype{T} <: AbstractA{T} end
        $subtype() = $subtype{Any}()
        Base.convert(::Type{AbstractA{S}}, a::$subtype) where S = $subtype{S}()
    end
end

```

The `Composite` constructor suffers from the same problem. It’s probably better to avoid the object `A1()` as an argument, and stick to just the type name `A1`:

```julia-auto
struct Composite{T, P<:AbstractArray{T}, A<:AbstractA{T}}
    t::P
    a::A
    function Composite(aa::AbstractArray{T}, ::Type{AT}) where {T, AT <: AbstractA}
        typ = AT{T}
        new{eltype(aa),typeof(aa),typ}(aa, typ())
    end
end

Composite([5.0], A1)

```

Alternatively, you can create an outer constructor for each subtype, and call the inner constructor with `invoke` (to avoid infinite recursion):

```julia-auto
struct Composite{T, P<:AbstractArray{T}, A<:AbstractA{T}}
    t::P
    a::A
    Composite(aa::AbstractArray{T}, a::AbstractA{T}) where {T} = new{T, typeof(aa), typeof(a)}(aa,a)
end

for subtype in subtypes
    @eval begin
        function Composite(aa::AbstractArray{T}, a::$subtype) where {T}
            newa = convert(AbstractA{T}, a)
            invoke(Composite, Tuple{typeof(aa), AbstractA{T}}, aa, newa)
        end
    end
end

Composite([5.0], A1())

```

There might exist more elegant solutions, perhaps someone knows?

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [August 2, 2025, 12:14pm UTC](https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306/3 "2025-08-02T12:14:38Z")

</div>

There’s also an alternative to create a function `atype` for each subtype, which returns the type `A1`, `A2` etc:

```julia-auto
abstract type AbstractA{T} end

const subtypes = (:A1, :A2)

for subtype in subtypes
    @eval begin
        struct $subtype{T} <: AbstractA{T} end
        $subtype() = $subtype{Any}()
        atype(::$subtype) = $subtype
    end
end

Base.convert(::Type{AbstractA{S}}, a::AbstractA) where {S} = atype(a){S}()

struct Composite{T, P<:AbstractArray{T}, A<:AbstractA{T}}
    t::P
    a::A
    function Composite(aa::AbstractArray{T}, a::AbstractA) where T
        newa = convert(AbstractA{T}, a)
        new{eltype(aa),typeof(aa),typeof(newa)}(aa, newa)
    end
end

julia> Composite([5.0], A1())

```

---

<div class="post-metadata">

**Author:** ![kunzaatko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kunzaatko/32/25153_2.png) [@kunzaatko](https://discourse.julialang.org/u/kunzaatko)\
**Post date:** [August 2, 2025, 1:08pm UTC](https://discourse.julialang.org/t/conversion-of-inner-flag-type-parameters-from-supertype-flag-type-parameters-for-composite-struct-construcor/131306/4 "2025-08-02T13:08:17Z")

</div>

I prefer this method.  
I solved the problem with composite construction with a combination of an inner constructor and outer constructors that call the `convert` directly.  
For these types, I have

```julia
struct Composite{T, P<:AbstractArray{T}, A<:AbstractA{T}}
    t::P
    a::A
    Composite{T}(aa::AbstractArray, a::AbstractA) where {T} = new{T, typeof(aa), typeof(a)}(aa,a)
end
Composite(aa::AbstractArray{S}, a::AbstractA) where {S} = Composite{S}(aa, convert(AbstractA{S}, a))

```

Does this method have any drawbacks? I like to avoid using `invoke` when not necessary since I have a hard time reasoning about it.
