# Write a constructor for these aliases?

**URL:** <https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135>\
**Category:** New to Julia\
**Created:** [October 14, 2025, 8:56am UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135 "2025-10-14T08:56:17Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 14, 2025, 8:56am UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/1 "2025-10-14T08:56:17Z")

</div>

I am trying to write a generic constructor for a bunch of type aliases that all share a common structure:

```julia
# Abstract type AbstractA with a bunch of different concrete subtypes: 
abstract type AbstractA end 
struct A1{T} <: AbstractA
    x::T
    y::T
end
struct A2{T} <: AbstractA
    x::T
end
struct A3{T} <: AbstractA
    x::T
end

# Wrapper B with a corresponding bunch of aliases: 
struct B{d, TA}
    a::TA
    B(d, a::AbstractA) = new{d, typeof(a)}(a)
end
const B1{d, T} = B{d, A1{T}}
const B2{d, T} = B{d, A2{T}}
const B3{d, T} = B{d, A3{T}}

```

But now i want to define constructors for the `BX` aliases, as

```julia
BX(d, args..., kargs...) = B(d, AX(args...; kwargs...))

```

for all `AX<:AbstractA` and associated `BX`.

I tried:

```julia
(::Type{<:B{D, <:AbstractA} where D})(d, args...; kwargs...) = "Dispatches but dont know which A here."

```

Also :

```julia
(::Type{<:B{D, <:A} where D})(d, args...; kwargs...) where A = "This one wont work, but should gives access to A"

```

An idea on the right way to write this constructor ?

---

<div class="post-metadata">

**Author:** ![YanickKind](https://avatars.discourse-cdn.com/v4/letter/y/cab0a1/32.png) [@YanickKind](https://discourse.julialang.org/u/YanickKind)\
**Post date:** [October 14, 2025, 12:52pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/2 "2025-10-14T12:52:49Z")

</div>

Did I understand that correctly that you want to to define constructors for all B’s (`B1`,`B2`, `B3`) within one method?

In case of yes, this works for me:

```julia-auto
function (b::Type{<:B})(d, args...; kwargs...) 
    (ft,) = fieldtypes(b)
    return B(d, ft(args...; kwargs...))
end 

b1 = B1(1 , "Grüße", "Test")
println(b1)
b2 = B2(2,2)
println(b2)
b3 = B3(3,10.)
println(b3)

```

yields

```julia-auto
B1{1, String}(A1{String}("Grüße", "Test"))
B2{2, Int64}(A2{Int64}(2))
B3{3, Float64}(A3{Float64}(10.0))

```

Edit: you can simply use `ft = fieldtype(b,1)` instead of `(ft,) = fieldtypes(b)`

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [October 14, 2025, 1:10pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/3 "2025-10-14T13:10:04Z")

</div>

> [@lrnv](#):
>
> ```julia-auto
> const B1{d, T} = B{d, A1{T}}
> const B2{d, T} = B{d, A2{T}}
> const B3{d, T} = B{d, A3{T}}
> ...
> (::Type{<:B{D, <:A} where D})(d, args...; kwargs...) where A = ...
> 
> ```

You’re trying to find a supertype of the aliases `B1`/`B2`/`B3` for the method’s dispatch that also extracts `A1`/`A2`/`A3` like type parameter values for `B`, but the aliases actually specified `A1{T}`/`A2{T}`/`A3{T}` substituted with a known `T` value as type parameter values for `B`. From another angle, we can’t make a supertype `B{d, a{T}} where {d, a, T}` or substitute `a` alone; a type parameter `a` is not a parametric type, even if we intend it to be, so it can’t have type parameters like `T`.

Thing is, you don’t specifically need a type parameter, you just need a UnionAll mapping `Dict(B1=>A1,B2=>A2,B3=>A3)`. `B1`/`B2`/`B3` aliases a parametric struct `B`, so it has the same sole field `a::TA`. You can use `dump` to check that `B1`/`B2`/`B3` specified `A1`/`A2`/`A3` as the sole `TA`, which is how it could adopt their parameter `T`. That’s why `fieldtypes`/`fieldtype(b, :a)` works perfectly.

> [@lrnv](#):
>
> `B(d, a::AbstractA) = new{d, typeof(a)}(a)`

Watch out for the type instability here. `d` being a value would make `@code_warntype` indicate abstract types, but `d` being a type would make `@code_warntype` deceptively assume a constant `d` value. `B{d}(a::AbstractA)` wouldn’t be out of line.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 14, 2025, 1:28pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/4 "2025-10-14T13:28:42Z")

</div>

Thansk to both for all the explanations, this is clearer for me now.

> [@YanickKind](#):
>
> ```julia-auto
> function (b::Type{<:B})(d, args...; kwargs...) 
> (ft,) = fieldtypes(b)
> return B(d, ft(args...; kwargs...))
> end 
> 
> ```

This works perfectly.

> [@Benny](#):
>
> > [@lrnv](#):
> >
> > `B(d, a::AbstractA) = new{d, typeof(a)}(a)`
> 
> Watch out for the type instability here. `d` being a value would make `@code_warntype` indicate abstract types, but `d` being a type would make `@code_warntype` deceptively assume a constant `d` value. `B{d}(a::AbstractA)` wouldn’t be out of line.

Indeed, this is why i started reviewing this old code at the begining. I managed to adapt the previous case to provide the `BX{d}(...)` syntax :

```julia
function (b::Type{<:B{d}})(args...; kwargs...) where d 
    (ft,) = fieldtypes(b)
    return B{d}(ft(args...; kwargs...)) # assuming this constructors exists and is defined in B struct. 
end 

```

But for compatibility reasons I need to keep the old unstable `BX(d, args...)` versions, and if I load both constructors i get an ambiguity…

---

<div class="post-metadata">

**Author:** ![YanickKind](https://avatars.discourse-cdn.com/v4/letter/y/cab0a1/32.png) [@YanickKind](https://discourse.julialang.org/u/YanickKind)\
**Post date:** [October 14, 2025, 2:04pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/5 "2025-10-14T14:04:28Z")

</div>

Personally, I wouldnt’t bother if you do not call the constructors in performance critical code and just take the convenience. Having values as type parameters can be very convenient and I take the performance penalty in non performance critical code.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 14, 2025, 2:09pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/6 "2025-10-14T14:09:25Z")

</div>

I am having the dilemma indeed. If I stay with the current situation, constructors are not type stable but then everything i do with the obejcts is, and i indeed do not construt them in performance-critical code. So we are good.

I just wanted to allow the construction as `BX{d}(args...)` as well, just in case. But I still cannot find the right syntax.

---

<div class="post-metadata">

**Author:** ![YanickKind](https://avatars.discourse-cdn.com/v4/letter/y/cab0a1/32.png) [@YanickKind](https://discourse.julialang.org/u/YanickKind)\
**Post date:** [October 14, 2025, 3:12pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/7 "2025-10-14T15:12:19Z")

</div>

> [@lrnv](#):
>
> Indeed, this is why i started reviewing this old code at the begining. I managed to adapt the previous case to provide the `BX{d}(...)` syntax :
> 
> ```julia-auto
> function (b::Type{<:B{d}})(args...; kwargs...) where d 
> (ft,) = fieldtypes(b)
> return B{d}(ft(args...; kwargs...)) # assuming this constructors exists and is defined in B struct. 
> end 
> 
> ```

Did you try this out? It should recursively call itself and error.

I’m stil wondering if you need the first variadic argument `args...`? (I do not really use it, so there might be lack of knowledge on my side)

In the following code:

```julia-auto
function (b::Type{<:B})(d, args...; kwargs...) 
    ft = fieldtype(b,1)
    return B(d, ft(args...; kwargs...))
end 

function (b::Type{<:B{d}})(args...; kwargs...) where d 
    ft = fieldtype(b,1)
    return B(d, ft(args...; kwargs...))
end 

b4 = B2{2}(rand(5))

```

I get an ambiguity since `(b::Type{<:B})` is not more specific than `(b::Type{<:B{d}})`. And the `args...` allows an arbitrary amount of agruments (zero included) s.t. it cannot distinguish between `(d, args...) ` and `(args...)` since `args..` can just simply be empty.

However chaning `args...` to `args` works:

```julia-auto
function (b::Type{<:B})(d, args; kwargs...) 
    ft = fieldtype(b,1)
    return B(d, ft(args; kwargs...))
end 

function (b::Type{<:B{d}})(args; kwargs...) where d 
    ft = fieldtype(b,1)
    return B(d, ft(args; kwargs...))
end 

b4 = B2{2}(rand(2))
b5 = B2(2,rand(2))
println(b4)
println(b5)

```

yields

```julia-auto
B2{2, Vector{Float64}}(A2{Vector{Float64}}([0.047862735617204555, 0.38961447120103077]))
B2{2, Vector{Float64}}(A2{Vector{Float64}}([0.751595176865353, 0.4652809371308122]))

```

Is there a case where you need the variadic argument?

Edit: Code formatting, typo

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 14, 2025, 3:22pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/8 "2025-10-14T15:22:39Z")

</div>

@YanickKind, Yes this is the ambiguity i hit. The solution with passing args as a vector is nice, but for the moment i need the variadic one indeed for retrocompatibility…

BTW, Cross-link to the concrete issue in the package: [[Constructors] Propose type-stable constructors · Issue #333 · lrnv/Copulas.jl · GitHub](https://github.com/lrnv/Copulas.jl/issues/333)

---

<div class="post-metadata">

**Author:** ![YanickKind](https://avatars.discourse-cdn.com/v4/letter/y/cab0a1/32.png) [@YanickKind](https://discourse.julialang.org/u/YanickKind)\
**Post date:** [October 14, 2025, 3:24pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/9 "2025-10-14T15:24:32Z")

</div>

Ah ok, perhaps someone more experienced might help. Sorry I cannot be more of a help.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 14, 2025, 3:31pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/10 "2025-10-14T15:31:30Z")

</div>

Thanks anyway, i learned a lot already 😉

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [October 14, 2025, 9:36pm UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/11 "2025-10-14T21:36:50Z")

</div>

> [@lrnv](#):
>
> But for compatibility reasons I need to keep the old unstable `BX(d, args...)` versions

`Copulas` is a v0, so SemVer demands no version compatibility and `Pkg` only insists patches of a non-zero minor version be compatible. In other words, leading zeros indicate an experimental stage, and Julia shifts the breaking changes to the leading nonzero version as part of that. It wouldn’t be out of line for you to make a still-experimental v0.2 with refactored type structures and method tables. It’s far better to make such changes for v0, however insignificant, than v1 where there are more promises.

On the other hand, it looks like a medium to large package, and you mention compatibility with other packages that can be affected by refactors. It’s also not great to release a breaking version for just a few reasons because it’s very likely to discover other desired breaking changes that should have been included; people wouldn’t appreciate adjusting to v0.12.0 within a year. It makes sense not to jump the gun when the performance improvements aren’t certain.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 15, 2025, 10:35am UTC](https://discourse.julialang.org/t/write-a-constructor-for-these-aliases/133135/12 "2025-10-15T10:35:06Z")

</div>

@Benny What you say is very wise and largely applicable to other packages as well. I will definitely follow these advices.
