Strange method overwriting case -> precompilation issue

Hey,

I have a module: Arithmetics.jl
I have precompilation issue due to.

mean(arr; dims) = sum(arr, dims=dims) / prod(size(arr, r) for r in dims)
mean(arr) = sum(arr) / length(arr)

It says that mean(arr) is overwritten with mean(arr;dims) which sounds nonsense as mean(arr; dims) doesn’t create the one arg version of mean.

What is this problem?

It does create it:

julia> f(a; b) = a + b
f (generic function with 1 method)

julia> f(1)
ERROR: UndefKeywordError: keyword argument `b` not assigned
2 Likes

Wow, indeed, thank you for pointing it out.

Then how could I create the dims version and specify a custom version for the “without the keyword version” without breaking precompilation? :o

You could maybe do something like

function mean(arr; dims=nothing)
    if dims === nothing
        return mean(arr) = sum(arr) / length(arr)
    else
        return sum(arr, dims=dims) / prod(size(arr, r) for r in dims)
    end
end
1 Like

Yes, ok. Not the best but. Okay. Thank you @kristoffer.carlsson!

I also saw this: Keyword arguments affect methods dispatch · Issue #9498 · JuliaLang/julia · GitHub
I hope this will be figured out. I believe the “keyword” error should be handled from the compiler side. So the compiler should know “Just In Time”, that the function just doesn’t exist and offer similar methods. It would be more beneficial to send a “it just doesn’t exist” instead of it generating these boilerplate functions with UndefKeywordError. If that could avoid these kind of overwrite issues in the future.
Mainly, because this became serious issues of today, from 1.10 as it treats precompilation error very seriously already!

Julia does not dispatch on keyword arguments. If you want dispatch, you can use a helper function which turns the keyword argument into a positional argument:

mean(arr; dims=nothing) = _mean(arr, dims)
_mean(arr, ::Nothing) = sum(arr) / length(arr)
_mean(arr, dims) = sum(arr; dims) / prod(size(arr, r) for r in dims)

This approach is used for example in reduce.jl.

4 Likes

Well, if precompilation is not crucial for you, your code just works as expected:

julia> f(x; kw) = 2
f (generic function with 1 method)

julia> f(x) = 1
f (generic function with 1 method)

julia> f("a")
1

julia> f("a"; kw="b")
2

This is pretty much a bug though.

1 Like

Excellent version! Really thank you!
Actually, this is close to perfect with the current overloading problem. :slight_smile: