What's the difference between these two types with implicit and explicit parameters?

julia> T1 = Vector{S} where {T<:Integer, S<:AbstractUnitRange{T}}
Vector{S} where {T<:Integer, S<:AbstractUnitRange{T}} (alias for Array{S, 1} where {T<:Integer, S<:AbstractUnitRange{T}})

julia> T2 = Vector{S} where {S<:AbstractUnitRange{<:Integer}}
Vector{S} where S<:(AbstractUnitRange{var"#s34"} where var"#s34"<:Integer) (alias for Array{S, 1} where S<:(AbstractUnitRange{var"#s34"} where var"#s34"<:Integer))

julia> T1 == T2
false

Could someone give me an example to explain the difference between the two?

Ah the difference appears to be

julia> Vector{AbstractUnitRange{<:Integer}} <: T2
true

julia> Vector{AbstractUnitRange{<:Integer}} <: T1
false
1 Like

Is that intended? Because, I would suppose <: is like <= and you could chain any number of xn <= ... <= x2 <= x1 and all variables would share the same upper bound, here it seems like the upper bound is lost (more akin <).

The difference is that T1 requires all AbstractUnitRange to have the same eltype T, while the second allows different eltypes. Therefore the following are the same:

julia> T2 = Vector{S} where {S<:AbstractUnitRange{<:Integer}}
Vector{S} where S<:(AbstractUnitRange{var"#s1"} where var"#s1"<:Integer) (alias for Array{S, 1} where S<:(AbstractUnitRange{var"#s1"} where var"#s1"<:Integer))

julia> T3 = Vector{S} where {T<:Integer, S<:AbstractUnitRange{<:T}}
Vector{S} where {T<:Integer, S<:(AbstractUnitRange{var"#s1"} where var"#s1"<:T)} (alias for Array{S, 1} where {T<:Integer, S<:(AbstractUnitRange{var"#s1"} where var"#s1"<:T)})

julia> T2 == T3
true

(note the difference - in T3 and additional <: is used before T.

3 Likes