Make `Type{}` "covariant"


#1

This is probably a stupid question: couldn’t Type behave covariantly? So, e.g. Type{Int}<:Type{Integer}. As Type can never be instantiated, the usual road-blocks for covariance do not apply. Also Type is pretty special already, so being more special shouldn’t come as too much of a surprise.

Then this would work:

f{T}(::Type{AbstractArray{T,1}}) = T
f(Range{Int}) # -> Int

instead of the parameter juggle needed currently (this gets better with the type-overhaul but above would still be useful).


#2

This doesn’t sound right T1 <: T2 means that if isa(v1, T1) then isa(v1, T2) However, isa(Int, Type{Int}) but !isa(Int, Type{Integer}).


#3

Yes, to make isa(Int, Type{Integer})==true is the essence of the proposal.


#4

This will be a major breaking change since then f(::Type{Integer}) will have the same meaning as f{T<:Integer}(::Type{T}) and being able to distinguish the two is a important reason why Type is useful.


#5

Yes, it would be breaking for sure. Note though that with the current dispatch rules your latter function would win over the former when called with f(Int), thus the distinction could still be made. Here the not quite analogous example with Tuple:

julia> f(::Tuple{Integer}) = 1
f (generic function with 1 method)

julia> f{T<:Integer}(::Tuple{T}) = 2
f (generic function with 2 methods)

julia> f((3,))
2

#6

I believe that behavior is a bug.


#7

And just to prove the point, this behavior is fixed on the jb/subtype branch and the two methods are treated as the same one and overwrites each other.

               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.6.0-dev.1562 (2016-12-12 21:00 UTC)
 _/ |\__'_|_|_|\__'_|  |  jb/subtype/d514ed4* (fork: 18 commits, 1 day)
|__/                   |  x86_64-pc-linux-gnu

julia> f(::Integer) = 1
f (generic function with 1 method)

julia> f{T<:Integer}(::T) = 2
WARNING: Method definition f(T) in module Main at REPL[1]:1 overwritten at REPL[2]:1.
f (generic function with 1 method)

julia> f2(::Tuple{Integer}) = 1
f2 (generic function with 1 method)

julia> f2{T<:Integer}(::Tuple{T}) = 2
WARNING: Method definition f2(Tuple{T}) in module Main at REPL[3]:1 overwritten at REPL[4]:1.
f2 (generic function with 1 method)

#8

Yep, that kills it. Thanks @yuyichao for your time to discuss this.