I tried to achieve the double constraint (NTuple{N, T}
and TwoOrThreeTuple{T}
) by defining an intermediate abstract type alias. However, I encountered inconsistent result from Julia’s compiler:
julia> abstract type MyType{V} <: Any end
julia> const TwoOrThreeTuple{T} = Union{NTuple{2, T}, NTuple{3, T}}
Union{Tuple{T, T}, Tuple{T, T, T}} where T
julia> const MyTwoThree{T, V<:TwoOrThreeTuple{T}} = MyType{V}
MyTwoThree{T} where T (alias for MyType{V} where {T, V<:Union{Tuple{T, T}, Tuple{T, T, T}}})
julia> struct myT2{T, N, V<:NTuple{N, T}} <: MyTwoThree{T, V}
a::V
end
julia> myT2((1,))
myT2{Int64, 1, Tuple{Int64}}((1,))
julia> MyTwoThree{Int, Tuple{Int}}
ERROR: TypeError: in MyType, in V, expected V<:Union{Tuple{Int64, Int64}, Tuple{Int64, Int64, Int64}}, got Type{Tuple{Int64}}
Stacktrace:
[1] top-level scope
@ REPL[6]:1
As you can see, MyTwoThree
should forbid any types that are not subtypes of TwoOrThreeTuple
from being its second parameter (V
). In fact, if you try to write such an illegal instance of MyTwoThree
, it can correctly detect the issue. However, when I tried to construct a myT2
with an illegal parameter V::Tuple{Int}
, the construction bypassed this check.
I’m unsure whether this is considered a “bug”, or another “feature” of Julia’s type system. I am concerned either way.