Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch broken for containers of objects parametrized with TypeVars #12596

Closed
timholy opened this issue Aug 13, 2015 · 8 comments
Closed

Dispatch broken for containers of objects parametrized with TypeVars #12596

timholy opened this issue Aug 13, 2015 · 8 comments
Labels
types and dispatch Types, subtyping and method dispatch

Comments

@timholy
Copy link
Member

timholy commented Aug 13, 2015

Maybe I'm just not seeing it, but to me this seems to be a bug:

abstract Paint{T, N}

abstract AbstractColor{T, N} <: Paint{T, N}
abstract Color{T}            <: AbstractColor{T, 3}
abstract Transparent{C<:AbstractColor,T,N} <: Paint{T,N}

immutable RGB{T<:FloatingPoint} <: Color{T}
    r::T # Red [0,1]
    g::T # Green [0,1]
    b::T # Blue [0,1]
end

colortype{C<:AbstractColor    }(::Type{C})                  = C
colortype{C<:AbstractColor    }(::Type{Transparent{C}})     = C
colortype{C<:AbstractColor,T  }(::Type{Transparent{C,T}})   = C
colortype{C<:AbstractColor,T,N}(::Type{Transparent{C,T,N}}) = C

T = TypeVar(:T)
colortype(RGB{Float32})                     # yields RGB{Float32}
colortype(RGB)                              # yields RGB{T<:FloatingPoint}
colortype(RGB{T})                           # yields RGB{T}
P = Transparent{RGB{Float32},Float32,4}
colortype(P)                                # yields RGB{Float32}
P = Transparent{RGB{T},T,4}

julia> colortype(P)
ERROR: LoadError: MethodError: `colortype` has no method matching colortype(::Type{Transparent{RGB{T},T,4}})
 in include at ./boot.jl:254
 in include_from_node1 at ./loading.jl:264
while loading /tmp/color_trouble2.jl, in expression starting on line 25

Yet

C = TypeVar(:C,AbstractColor)
N = TypeVar(:N)

julia> typeintersect(P, Transparent{C,T,N})
Transparent{RGB{T},T,4}

julia> P <: Transparent{C,T,N}
true
@timholy timholy added the types and dispatch Types, subtyping and method dispatch label Aug 13, 2015
@timholy
Copy link
Member Author

timholy commented Aug 13, 2015

It's actually the 2nd parameter that's causing the problem, and it depends on whether it's a bound or unbound typevar. Reduced case:

abstract AbstractColor{T, N}
abstract Color{T}            <: AbstractColor{T, 3}
abstract Transparent{C<:AbstractColor,T,N}

immutable RGB{T<:FloatingPoint} <: Color{T}
    r::T # Red [0,1]
    g::T # Green [0,1]
    b::T # Blue [0,1]
end

C = TypeVar(:C,AbstractColor,true)
Tu = TypeVar(:T,false)
Tb = TypeVar(:T,true)
N = TypeVar(:N,true)
B = Transparent{C,Tb,N}

julia> P = Transparent{RGB{Tu},Tu,4}
Transparent{RGB{T},T,4}

julia> typeintersect(Type{P}, Type{B})
Union{}

julia> P = Transparent{RGB{Tu},Tb,4}
Transparent{RGB{T},T,4}

julia> typeintersect(Type{P}, Type{B})
Type{Transparent{RGB{T},T,4}}

The key lines seem to be here.

This may give me enough guidance to work around this.

@mbauman
Copy link
Member

mbauman commented Aug 13, 2015

Sounds like #2552 (comment) and/or #11597. I've actually stopped restricting type parameters in my own code and just enforcing it by what constructors I provide because of wonkiness like this and because I often want "triangular" constraints which aren't expressible in any case.

@timholy
Copy link
Member Author

timholy commented Aug 13, 2015

Yeah, this indeed popped up in a rework of Color.jl, for which I'm trying to design some nice traits to compensate for the lack of triangular dispatch. It specifically arose through introspection on TypeConstructors which arise from typealiases. I got around it by ditching all the typealiases and generating types by metaprogramming.

@timholy
Copy link
Member Author

timholy commented Aug 15, 2015

Rearing its head again. Here's a simple real-world example:

julia> abstract A{T,N}

julia> immutable B{T} <: A{T,3}
           val::T
       end

julia> len{T,N}(::Type{A{T,N}}) = N
len (generic function with 1 method)

julia> super(B)
A{T,3}

julia> len(super(B))
ERROR: MethodError: `len` has no method matching len(::Type{A{T,3}})

This seems to be a consequence of fixing #7062. I have to say, this seems like a worse problem to have than #7062. What do you think, @vtjnash?

@timholy
Copy link
Member Author

timholy commented Aug 15, 2015

Just to show you how devious I am (in case you had any remaining doubts), here's a workaround:

julia> len2{N}(::Type{A{TypeVar(:T),N}}) = N
len2 (generic function with 1 method)

julia> len2(super(B))
3

@vtjnash
Copy link
Member

vtjnash commented Aug 15, 2015

#12596 (comment)

that answer looks correct to me. the TypeVar T is not being matched in the first example, so the method cannot be used. the official way to avoid this is to use a typealias (although constructing the TypeVar manually is pretty similar).

@timholy
Copy link
Member Author

timholy commented Aug 16, 2015

I wonder whether this issue should turn into "further disambiguate the printing of method tables and types so the proper dispatch rules are obvious"?

@JeffBezanson
Copy link
Member

closed by #18457

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

No branches or pull requests

4 participants