Making method errors more helpful by indicating the defining module


#1

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.


Julep: Taking multiple dispatch,export,import,binary compilation seriously
#2

Yep, this sounds great!

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


#3

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