== seems to work given the one type, though I don’t see this documented for iterated unions in particular.
julia> let sig = Tuple{typeof(sin),Float64}, T = Type
(T{sig} == T{S} where {S<:sig},
T{sig} == T{S} where {sig<:S<:sig}) # force S == sig
end
(false, true)
It’s not, one strictly subtypes the other:
julia> let sig = Tuple{typeof(sin),Float64}, T = Type
(Union{T{sig}, T{Union{}}} == T{<:sig},
Union{T{sig}, T{Union{}}} <: T{<:sig},
T{<:sig} <: Union{T{sig}, T{Union{}}})
end
(false, true, false)
Can’t imagine what else could be in T{<:sig} though. Results are the same for sig = Int, T = Vector so it’s not an artifact of Tuple or Type.
I wonder if the question is easier for us to answer if we restrict ourselves to a subset of possible Tuples? For context: in my particular use case, there’s a performance optimisation that I can perform if I know that Type{T} where T<:Tuple{...} contains only Type{Tuple{...}} and Type{Union{}}, so I’m quite happy if we’re able to determine if this is the case for a large-ish family of Tuple{...}s, as opposed to all possible Tuple{...}s.
For example, given Tuple{P_1,P_2,P_3...} where each P_n is not a subtype of Type (because this contains some edge cases that I find hard to reason about), is it enough to check that all P_n are concrete?
This makes sense. There’s still the edge case involving something like Tuple{Type{F}} for some type F to deal with, so perhaps something like this would work?
function is_safe_to_optimise(x::Type{<:Tuple})
# Exclude `UnionAll`s, `Union`s, and `Core.TypeofBottom`.
x isa DataType || return false
try
# Exclude eg. `Tuple{DataType}` because `DataType` is concrete, but `Type{F} <: DataType`.
any(T -> T <: Type, fieldtypes(x)) && return false
# It's now enough to know that everything is concrete?
return isconcretetype(x)
catch
# If contains a `Vararg`, the fieldcount will not be defined, and an `ArgumentError` thrown.
return false
end
end
Thanks again everyone for your thoughts on this, I greatly appreciate you all taking the time to respond.
I don’t think that we’ve landed on a completely satisfying solution (although I suspect that is_safe_to_optimise is fairly close), so I’m not going to give anything the green tick at this point, in case someone knows something we don’t and stumbles across this in the future!