Making method errors more helpful by indicating the defining module

Currently, MethodErrors for missing methods do not print any information about the module to which the underlying function belongs. For example:

julia> module Bar
         f(x::Int) = 10
       end
Bar

julia> using .Bar: f

julia> f(10)
10

julia> f("hello")
ERROR: MethodError: no method matching f(::String)
Closest candidates are:
  f(::Int64) at REPL[1]:2

This can make it more difficult to determine exactly which function I should overload to fix the method error. Just looking at the error message, it would appear that defining f(::String) would be appropriate, but I actually need to define Foo.f(::String) or import Foo: f; f(::String) = ....

The issue gets worse when method errors occur deeper in the code, as it can be pretty unclear what the originating module for a given function is.

To be clear, I’m not suggesting changing the language semantics at all, just the way we report errors.

I suspect that this would also help with a very common category of error for new users, which is failing to import Base methods. For example, a new user might do the following:

julia> module Foo

       struct Bar; end
       sort([Bar(), Bar()])
       end
ERROR: MethodError: no method matching isless(::Foo.Bar, ::Foo.Bar)

Given that error message, the natural thing to do is to define precisely what is suggested:

julia> module Foo

       struct Bar; end
       isless(::Bar, ::Bar) = true
       sort([Bar(), Bar()])
       end
WARNING: replacing module Foo
ERROR: MethodError: no method matching isless(::Foo.Bar, ::Foo.Bar)

but of course that doesn’t actually work.

If, instead, the MethodError printed MethodError: no method matching Base.isless(::Foo.Bar, ::Foo.Bar), then we would at least be helping users towards the correct implementation:

julia> module Foo

       struct Bar; end
       Base.isless(::Bar, ::Bar) = true
       sort([Bar(), Bar()])
       end
WARNING: replacing module Foo
Foo

Method ambiguity errors already show the function with its relevant module, so this is clearly possible. I’m happy to open a PR if this seems like a good idea.

7 Likes

Yep, this sounds great!

Tangentially related: https://github.com/JuliaLang/julia/pull/24299

Yep. Tangentially related, it would be great to no longer have (at least) three different implementations of this with varying features. :stuck_out_tongue: