Warning about name conflict

I see some existing answers to this question, but I still don’t understand in this case:

I’ve got a function in a module

step(a::MyType1, b::MyType2)

Where I invoke this in my code, I get a warning that it is in conflict with Base.step, but when I look at the code of Base.step all the methods have fully typed parameters that don’t seem to match mine at all. It’s obviously easy enough to solve, but I don’t understand why the warning since there appears to be no conflict other than the name.

You define a new function step which happens to clash with a previous function from Base.
Since you do no explicitly extedt the Base function it warms you about the name conflict.

If your function can be throught of as a logical extension of Base.step then you can simply define

Base.step(a::MyType1, b::MyType2)

If your function is unrelated to Base.step and is not a reasonable extension, it is probably better to give it a different name altogether

Edit: to be a bit more clear: Julias multiple dispatch distinguishes the intended definition of new methods from unintended ones.
If you define Base.step for your own type, then you signalize that your method will in effect do the same thing as the base method, only for different arguments.
In particular this means that other functions which call Base.step, will automatically use your function if the type signature is matching, allowing for very powerful generic code.
If you don’t intend on doing the same thing as the base function, the warning reminds you that the name is somewhat ambiguous and should better be changed.

It’s worth also adding a note that you can shadow the Base definition if (and only if) you don’t also touch the Base implementation. This can be a little tricky at the REPL because there’s a bit of statefulness, but in with module it’s much clearer to see the three situations here:

julia> module NamingConflict
           struct MyStruct end
           step(1:2) # Use Base.struct implicitly somewhere in the module...
           step(::MyStruct, ::MyStruct) = something
ERROR: invalid method definition in NamingConflict: function Base.step must be explicitly imported to be extended

julia> module Shadow
           struct MyStruct end;
           # Create a _separate_ step function that doesn't have any of the Base behaviors
           step(::MyStruct, ::MyStruct) = something

julia> methods(Shadow.step)
# 1 method for generic function "step" from Main.Shadow:
 [1] step(::Main.Shadow.MyStruct, ::Main.Shadow.MyStruct)
     @ REPL[54]:3

julia> methods(Base.step)
# 8 methods for generic function "step" from Base:
 [1] step(r::StepRange)
     @ range.jl:699
# ...

julia> module Import
           struct MyStruct end
           Base.step(::MyStruct, ::MyStruct) = something

julia> methods(Base.step)
# 9 methods for generic function "step" from Base:
 [1] step(::Main.Import.MyStruct, ::Main.Import.MyStruct)
     @ Main.Import REPL[57]:3
 [2] step(r::StepRange)
     @ range.jl:699
# ...
1 Like

I have the same question as the OP.
What I don’t understand is that, isn’t it the job of multiple dispatch to identify and use the most specific function? Isn’t this the behavior what we want?

That’s not quite how multiple dispatch works. You have to be explicit about adding a method to the methods table of a specific function. See the manual about import vs using.

If defining a function f were to modify or overwrite any function named f in any other package (even packages deep down in your dependency stack that you’re not aware of), it would result in complete chaos.

Besides, function names have no real meaning: you can always rename them with as. So if I do

using LinearAlgebra: dot as inner

should that suddenly add methods to a function inner that any other package might define?

Two functions are two different objects, independent of what names are attached to them, and whether those names are identical or different, and each function has its own method table.

The only restriction is that you can’t have the same name refer to two different functions in the same namespace.

1 Like

I thought there was one giant method table in the namespace. Now I understand why I can’t have the same function name imported from different libraries. It’s because there are multiple method tables.

Thanks for taking the time to answer my questions.

That, in fact, all a function is: a table of zero or more methods.

julia> function f end
f (generic function with 0 methods)

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

julia> f(a,b) = 2
f (generic function with 2 methods)