Skip to content

confusing dispatch when method parameter bounds are wider than a type parameter's declared bounds #6383

@carlobaldassi

Description

@carlobaldassi

See a85476b and 005197a and comments therein.

In summary, dispatch on a parametric type whose type is restricted in the declaration (type A{T<:Integer} etc.) make a difference between A, A{T} and A{T<:Integer}. In one case, A{T} seems to be taken as more general than A; in another case, A seems to be taken as more general than A{T<:Integer} - see examples below.

Example: this shows the ambiguity

julia> type A{T<:Integer} <: Real
           a::T
       end

julia> type B <: FloatingPoint
       end

julia> tst{T<:FloatingPoint,S}(::Type{T}, x::A{S}) = println(1)
tst (generic function with 1 method)

julia> tst(::Type{B}, x::A) = println(2) # this should disambiguate between the one above and the one below
tst (generic function with 2 methods)

julia> tst(::Type{B}, x::Real) = println(2)
Warning: New definition 
    tst(Type{B},Real) at none:1
is ambiguous with: 
    tst(Type{T<:FloatingPoint},A{S}) at none:1.
To fix, define 
    tst(Type{B},A{S})
before the new definition.
tst (generic function with 3 methods)

julia> tst(B, A(1)) # works
2

Currently, the workarounds for the example above are: defining the disambiguation method with an otherwise useless parameter

julia> type A{T<:Integer} <: Real
           a::T
       end


julia> type B <: FloatingPoint
       end

julia> tst{T<:FloatingPoint,S}(::Type{T}, x::A{S}) = println(1)
tst (generic function with 1 method)

julia> tst{S}(::Type{B}, x::A{S}) = println(2) # useless parameter S
tst (generic function with 2 methods)

julia> tst(::Type{B}, x::Real) = println(2) # no warning though
tst (generic function with 3 methods)

julia> tst(B, A(1))
2

Or restricting the first method to S<:Integer:

julia> type A{T<:Integer} <: Real
           a::T
       end

julia> type B <: FloatingPoint
       end

julia> tst{T<:FloatingPoint,S<:Integer}(::Type{T}, x::A{S}) = println(1) # the <:Integer part should be implicit
tst (generic function with 1 method)

julia> tst(::Type{B}, x::A) = println(2)
tst (generic function with 2 methods)

julia> tst(::Type{B}, x::Real) = println(2)
tst (generic function with 3 methods)

julia> tst(B, A(1))
2

One more problem: from the last example, continue like this:

julia> tst(::Type{FloatingPoint}, x::A) = println(3) # this should be more specific then the one which prints 1
tst (generic function with 4 methods)

julia> tst(FloatingPoint, A(1)) # calls the wrong version
1

Again, to fix it restrict the type parameter in the above definition:

julia> tst{S<:Integer}(::Type{FloatingPoint}, x::A{S}) = println(3)
tst (generic function with 4 methods)

julia> tst(FloatingPoint, A(1))
3

Metadata

Metadata

Assignees

Labels

bugIndicates an unexpected problem or unintended behaviortypes and dispatchTypes, subtyping and method dispatch

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions