JuliaLang/julia

Improving MethodError message for anonymous functions

Open

#56.325 aperta il 25 ott 2024

Vedi su GitHub
 (7 commenti) (6 reazioni) (0 assegnatari)Julia (5773 fork)batch import
error messagesgood first issue

Metriche repository

Star
 (48.709 star)
Metriche merge PR
 (Merge medio 23g 11h) (145 PR mergiate in 30 g)

Descrizione

Context: improving error experience for beginner Julia programmers.

In this example, you get a MethodError for your anonymous method (::var"#3#4"):

julia> vals = [5,6,10,20];

julia> accumulate(vals; init=0) do (old, new)
           old + new
       end
ERROR: MethodError: no method matching (::var"#3#4")(::Int64, ::Int64)
The function `#3` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  (::var"#3#4")(::Any)
   @ Main REPL[2]:2

Stacktrace:
 [1] _accumulate!(op::var"#3#4", B::Vector{Union{}}, A::Vector{Int64}, dims::Nothing, init::Some{Int64})
   @ Base ./accumulate.jl:368
 [2] accumulate!(op::Function, B::Vector{Union{}}, A::Vector{Int64}; dims::Nothing, kw::@Kwargs{init::Int64})
   @ Base ./accumulate.jl:350
 [3] accumulate(op::Function, A::Vector{Int64}; dims::Nothing, kw::@Kwargs{init::Int64})
   @ Base ./accumulate.jl:291
 [4] top-level scope
   @ REPL[2]:1

The problem is that my do syntax used (old, new) (a single tuple argument) instead of old, new (two integer arguments):

julia> accumulate(vals; init=0) do old, new
           old + new
       end
4-element Vector{Int64}:
  5
 11
 21
 41

But the error is difficult to understand!

Ideas

I have seen this pattern more often (MethodError on an anonymous function that I defined), and I think we could make meaningful improvements to this error message! Ideas:

  1. Say "anonymous function": We can communicate better that it's about an "anonymous function". The name var"#3#4" is not so useful for beginners. (In the case of a do-block, it might even be non-obvious that you wrote a function.)
  2. Simplify "Closest candidates": Anonymous functions can only have one method (right?). So instead of showing "Closest candidates", the error can be stated in a simpler way:
The anonymous function has signature:
   (::Any)
but it was called with types:
   (::Int64, ::Int64)
  1. Number of arguments: the function was called with 2 arguments, but no method accepts that. When dispatch fails because of the number of arguments, I think this is the most helpful bit of debugging info available (like a sanity check), and we could say this explicitly in the error. It could be phrased as advice (when the situation is simple enough):
Tip: The function was called with 2 arguments, but it only accepts 1 argument.

Guida contributor