Description
A radical idea that came up in #24166 and on slack: Make Tuple
invariant in its parameters.
Pro:
- Makes
Tuple
s less special/magical. - (Hopefully) reduces special cases in subtyping code.
- Allows abandoning the "diagonal rule" that is useful is dispatch, but nasty in code working with (especially widening) types, ref bug in type widening #24582.
- Would allow for e.g.
Tuple{Union{Int,Missing}, Union{Int,Missing}}
to be concrete. (Added based on comment below.) - ...
Con:
- Probably huge effort, needs to be well justified.
- ...
(Hoping to stir up a discussion that adds to these lists.)
Of course the current covariant behavior is useful more often than not, but the new InvariantTuple
(for the sake of discussion) could be use to express it: Tuple{Number,Any}
would become Tuple{<:Number, <:Any}
. The diagonal rule would be trivial: Tuple{T,T} where T
would become InvariantTuple{T,T} where T
(but T
would no longer be confined to concrete types), while Tuple{T,T,Ref{T}} where T
(N.B. diagonal rule does not apply!) would become InvariantTuple{<:T,<:T,<:Ref{T}} where T
.
Handling Vararg
s needs more thought: Tuple{Vararg{Any}}
would need to be interpreted as InvariantTuple{<:Any,<:Any,...}
while Tuple{Vararg{T}} where T
would need to be interpreted as InvariantTuple{T,T,...} where T
. Hence we would need two different syntaxes for InvariantTuple{Vararg}
to distinguish these cases. Maybe InvariantTuple{Vararg{T} where T}
for Tuple{Vararg{Any}}
vs. InvariantTuple{Vararg{T}} where T
for Tuple{Vararg{T}} where T
?
I have no idea whether we actually want to go down this road eventually, but I feel like it at least deserves discussion. (CC @andyferris)