I noticed something strange about reflection on parameterized types.

Consider this simplified code:

julia> type X{T <: Number} x::T end
julia> f{T}(::X{T}) = 1
julia> XT = methods(f).defs.sig[1]
X{T}
julia> XT <: X
*false*
julia> X <: XT
true
julia> type Y{T} y::T end
julia> g{T}(::Y{T}) = 1
julia> YT = methods(g).defs.sig[1]
Y{T}
julia> YT <: Y
*true*
julia> Y <: YT
true

That's weird, why do X and Y behave differently for subtype?  Shouldn't a 
TypeVar-parameterized version of a type always be a subtype of the general, 
unparameterized type?  The possible instances of the TypeVar-parameterized 
type are certainly a subset of the possible instances of the 
unparameterized type.

Maybe this sheds some light on it:

julia> X
X{T<:Number} (constructor with 1 method)
julia> Y
Y{T} (constructor with 1 method)

The unparameterized types read back as if they were parameterized!  You 
can't tell the difference between the TypeVar that was used to declare the 
type (as in X), and a TypeVar of a method that was used to parameterize the 
type (as in XT).  Those two TypeVars named T are not the same object.  It 
seems like the <: operator is being confused by this.

If X actually was parameterized with an upper bound of Number, and XT was 
parameterized with an upper bound of Any, then XT <: X = false would make 
sense.  But of course the two TypeVar's named T actually have the same 
range, since X won't accept a parameter that is not a subtype of Number.

It seems like the parameters field of DataType is being overloaded for two 
different purposes, in one case to remember the parameters that were 
declared for a generic datatype, in the other case to remember the 
parameters with which a generic datatype was instantiated.  Shouldn't those 
two purposes be separated?

Either I am confused and this is working the way it is supposed to, or it 
is broken.  Should I file a bug?

Reply via email to