Abstract parametric constructors

How can I create a constructor for a parametric type using its abstract supertype?
This is my minimal nonworking example :wink:

abstract type MyNumber{T1<:Integer,T2<:Integer} end

struct MyNumber1{T1,T2} <: MyNumber{T1,T2}
    a :: T1
    b :: T2
end

struct MyNumber2{T1,T2} <: MyNumber{T1,T2}
    a :: T1
    b :: T2
end

function (::Type{MT})(a::T1,b) where {T1 <: Integer, MT<:MyNumber{T1}}
    println("here?")
end

MyNumber1{Int}(1,2)

the error message is:

julia> MyNumber1{Int}(1,2)
ERROR: MethodError: no method matching (MyNumber1{Int64, T2} where T2)(::Int64, ::Int64)
Stacktrace:
[1] top-level scope
  @ REPL[10]:1

if I write it as a Union like:

function (::Type{MT})(a::T1,b) where {T1 <: Integer, MT<:Union{MyNumber1{T1}, MyNumber2{T1}}}
    println("here?")
end

it works though.
Appreciate any help and explanation why this doesn’t work.

I do not know the explanation, but this works

function (::Type{MT})(a::T1,b) where {T1 <: Integer, MT<:MyNumber{T1, T2} where T2}
    println("here?")
end

Also

julia> (MyNumber1{Int64, T2} where T2) <: MyNumber{Int64}
false

julia> (MyNumber1{Int64, T2} where T2) <: (MyNumber{Int64, T3} where T3)
true
1 Like

Thanks a lot. I’ve never seen a where inside a where before :grinning_face_with_smiling_eyes:
I was wondering why I need to specify all of the types of the parametric type (so T1 and T2) in general.

I guess it’s called triangular dispatch and it was a big deal around 0.5 or 0.6

As for your second question, someone with deeper understanding should come in here.

1 Like

You can just skip the the type signature:

julia> abstract type MyNumber{T1<:Integer,T2<:Integer} end

julia> struct MyNumber1{T1,T2} <: MyNumber{T1,T2}
           a :: T1
           b :: T2
       end

julia> MyNumber1(1,2)
MyNumber1{Int64,Int64}(1, 2)

edit: I see that the definition of that function complicates things, sorry.

Sorry my example is a bit contrived. In my actual example I have some parts in the parametric fields (don’t know how to call them :smiley: ) which can’t be extracted from the values of the function. Therefore I need to give T1 but T2 can be taken from the input. Hope that makes sense.