One design pattern I keep stumbling upon is that I want to generate parametric types based on existing parametric types, but with certain constraints among parameters, such that inappropriate combinations are prevented from ever being defined by the user (and causing further trouble).
For example, let’s say I have types Type1{S}
and Type2{S,T}
and I want to define a new type Type3{U,V}
such that U<:Type1{S}
and V<:Type2{S,T}
, but in addition I want to enforce that the parameter S
in both parameters is the same. I.e. trying to call or define a Type3{U,V}
for some U<:Type1{S}
and V<:Type2{S2,T}
will produce an error whenever S
and S2
are different.
The problem I have is that I do not really know how to create such types in a Julia-paradigmatic way, or even whether this is the best way to solve the problem I have (i.e. excluding types with inconsistent parameters to exist).
When I want Type3
to be an abstract type, I can do
# correct syntax, but not the desired result
abstract type Type3{U<:Type1{S} where S, V<:Type2{S,T} where {S, T}} end
but this does not force the S
in both U
and V
to be the same.
The following does not work, but should give a flavor of what I’m trying to do:
# throws error `syntax: invalid type signature`
abstract type Type3{U<:Type1{S}, V<:Type2{S,T}} where {S,T} end
The following works for structs, but is probably a bit too convoluted (especially if the pattern keeps coming up), and cannot be done for abstract types because they lack constructors:
# correct syntax and outcome
struct Type3{S, T, U, V}
x::U
y::V
Type3(x::Type1{S}, y::Type2{S,T}) where {S, T} = new{S, T, typeof(x), typeof(y)}(x, y)
end
Slightly simpler would be the following (which again does not work):
# throws error `syntax: invalid type signature`
struct Type3{U<:Type1{S}, V<:Type2{S, T} where {S, T}
x::U
y::V
end