Skip to content

defining a method of a generic comparison with one argument unconstrained in a package is a bug #310

Open
@nsajko

Description

@nsajko

Defining a == method with one of the arguments untyped should never be done in a registered package. This is done here, and in some other places:

Base.:(==)(α, q::RationalPoly) = α * q.den == q.num
Base.:(==)(q::RationalPoly, α) = α == q

The reason that's a bug is that that kind of method signature will be ambiguous with regards to methods defined in other packages. Observe, fresh REPL session:

julia> struct A end  # in one package

julia> struct B end  # in another package

julia> function Base.:(==)(::A, ::Any) end

julia> function Base.:(==)(::Any, ::A) end

julia> function Base.:(==)(::B, ::Any) end

julia> function Base.:(==)(::Any, ::B) end

julia> using Test

julia> detect_ambiguities(Main)
12-element Vector{Tuple{Method, Method}}:
 (==(::A, ::Any) @ Main REPL[3]:1, ==(::Any, ::Missing) @ Base missing.jl:76)
 (==(::Any, ::A) @ Main REPL[4]:1, ==(::Missing, ::Any) @ Base missing.jl:75)
 (==(::A, ::Any) @ Main REPL[3]:1, ==(w, v::WeakRef) @ Base gcutils.jl:36)
 (==(::Any, ::A) @ Main REPL[4]:1, ==(w::WeakRef, v) @ Base gcutils.jl:35)
 (==(::A, ::Any) @ Main REPL[3]:1, ==(::Any, ::B) @ Main REPL[6]:1)
 (==(::A, ::Any) @ Main REPL[3]:1, ==(::Any, ::A) @ Main REPL[4]:1)
 (==(::B, ::Any) @ Main REPL[5]:1, ==(::Any, ::B) @ Main REPL[6]:1)
 (==(::Any, ::B) @ Main REPL[6]:1, ==(::Missing, ::Any) @ Base missing.jl:75)
 (==(::B, ::Any) @ Main REPL[5]:1, ==(w, v::WeakRef) @ Base gcutils.jl:36)
 (==(::B, ::Any) @ Main REPL[5]:1, ==(::Any, ::Missing) @ Base missing.jl:76)
 (==(::Any, ::A) @ Main REPL[4]:1, ==(::B, ::Any) @ Main REPL[5]:1)
 (==(::Any, ::B) @ Main REPL[6]:1, ==(w::WeakRef, v) @ Base gcutils.jl:35)

Or, more minimally and concretely:

julia> struct A end  # in one package

julia> function Base.:(==)(::A, ::Any) end

julia> struct B end  # in another package

julia> function Base.:(==)(::Any, ::B) end

julia> A() == B()
ERROR: MethodError: ==(::A, ::B) is ambiguous.

Candidates:
  ==(::A, ::Any)
    @ Main REPL[2]:1
  ==(::Any, ::B)
    @ Main REPL[4]:1

Possible fix, define
  ==(::A, ::B)

Stacktrace:
 [1] top-level scope
   @ REPL[5]:1

I saw this on issue #290 first, but decided to open a new issue, since what I'm pointing out seems worse than invalidation of precompiled code and is not related to invalidation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions