# Inhibit same type parameters

For example, I have 4 types `A`, `B`, `C` and `D`, which can be filled in a parametric type `P`.

``````const U = Union{A, B, C, D}

struct P{F <: U, S <: U}
a::Vector
b::Vector
function P{F, S}(a, b) where {F, S}
F == S && throw(ArgumentError("The parameters must have different types!"))
end
end
``````

However, what I want is that `F` cannot be equal to `S`. How can I do that if I do not want specify it in the inner constructor? What if I just want to inhibit statements like `P{A, A}`, `P{B, B}`, etc., even without parameters `(a, b)` because generating `a` and `b` can take time?

There’s no way to make it so that simply writing `P{A, A}` errors, if that’s what you want. If you call `dump(P)`, you get

``````julia> dump(P)
UnionAll
var: TypeVar
name: Symbol F
lb: Core.TypeofBottom Union{}
ub: Union{A, B, C, D}
body: UnionAll
var: TypeVar
name: Symbol S
lb: Core.TypeofBottom Union{}
ub: Union{A, B, C, D}
body: P{F<:Union{A, B, C, D},S<:Union{A, B, C, D}} <: Any
a::Array{T,1} where T
b::Array{T,1} where T
``````

This shows how `UnionAll`s like `P` are represented in Julia. You can have upper bounds (`ub`) and lower bounds (`lb`) on type variables, but `UnionAll` itself does not support more complicated constraints, probably to limit the computational complexity of type system queries (but I’m far from an expert on this subject).

1 Like