Warning both package a and b export the same function

With Julia 1.10 I get the following warning:

WARNING: both VortexStepMethod and NonlinearSolve export "solve!"; uses of it in module KiteModels must be qualified

I don’t get it with Julia 1.11. Any idea why?

What is the best way to avoid this warning?

Not sure about the discrepancy between Julia versions, but to get red if the warning use explicit imports in KiteModels, I.e.

using NinlinearSolve: NonlinearProblem, solve!

Rather than importing everything which is exported.

The point is that we need both solve! methods in KiteModels. Could we make a change in VortexStepMethod to avoid this warning? Like adding:

import NonlinearSolve: solve!

to extend this method for a different type?

If you’ve resolve the name conflict (and thus the warning) you can use the long form including the module in source

using NonlinearSolve: .. what you need but solve!
using VortexStepMethod: .. what you need but solve!

# later in code
NonlinearSolve.solve!(...)
VortexStepMethod.solve!(...)
1 Like

I understand, but I would prefer to avoid that this problem appears in the first place. I think if I write:

using NonlinearSolve
import NonlinearSolve: solve!, solve

in VortexStepMethod then the problem will disappear even if I do

using VortexStepMethod, NonlinearSolve

in KiteModels

I do not know about either of the packages. But what is it exactly what you want to achieve?

Do you want to end up with one function solve! and two methods defined for it?
In this case one package should make its function available (export or public) and the other package should import (not using) it or address it with its FQN like OtherPackage.solve! when defining the additional method

Or do you want to end up with two functions solve! with one method defined for each?
Then you should either use the FQNs or rename at least one of both functions when bringing them into the namespace.

I think changing the solve! function in VortexStepMethod to become NonlinearSolve’s, which originates in the lightweight dependency CommonSolve, is a breaking change. Even if those modules would define separate specificity sub-trees of methods by working on distinct types they own, it’s technically possible that someone relied on solve! being (at least) 2 distinct functions with separate method tables. It’s also likely nobody did so you could get away with it.

I’d recommend against import with names or bare using followed by extensions with unqualified method definitions because its presence changes whether the same method code extends another module’s function or tries to create a new one. Opposition to unqualified extension methods is more often mentioned for import with names, but bare using is a bit sneakier because whether the name was referenced beforehand is an additional factor:

julia> module D
        export f
        function f end
       end;

julia> module E # first, no reference or definition
        using ..D
       end;

julia> D.f === E.f
true

julia> module E # no reference -> new function
        using ..D
        f() = 0
       end;
WARNING: replacing module E.

julia> D.f === E.f
false

julia> module E # prior reference -> attempted extension
        using ..D
        f
        f() = 0
       end;
WARNING: replacing module E.
ERROR: invalid method definition in E: function D.f must be explicitly imported to be extended

I’d hazard a guess that you intended VortexStepMethod.solve! === NonlinearSolve.solve! in the first place, but bare using threw you off.

1 Like

To be honest, I do not understand what you wrote, that is too abstract for me.

I want to have a function solve! with two methods, one implemented by NonlinearSolve.solve! and one implemented by VortexStepMethod.solve!

That should be simple and straightforward.

Does your VortexStepMethod.solve! follow the conventions and API of CommonSolve.jl? If so, make VortexStepMethod depend upon CommonSolve, and make your VortexStepMethod solve! definitions explicitly extend CommonSolve’s function (typically by fully-qualifying CommonSolve.solve! in all your method definitions).

Then there’s only one function shared between both libraries and both can export it without trouble.

If you can’t do that, folks can still be using both packages together without this warning or major consternation — they just need to make sure that all usages are fully qualified or explicitly renamed.

5 Likes

Very good point. This looks like the way forward.

Before the currently proposed fixes, you had 2 distinct functions instead, and it is sounding more like it was unintentional. To adapt the D/E example to your case, I guessed that you expected

using NonlinearSolve
...
function solve!(...

to extend NonlinearSolve.solve!, but that instead made a new function with a separate method table in VortexStepMethod. Any of the fixes here would undo that and extend NonlinearSolve.solve! instead, but it seems like a breaking change, which isn’t as smooth for v1+ packages. I don’t expect it to break much; anyone who previously qualified or renamed the 2 distinct functions would still have working calls, just silently changed to the same function. But it’d break unusual reliance on the 2 functions being distinct, like a condition solve_func !== NonlinearSolve.solve! or try-catch-ing MethodErrors for the wrong function, and it’d break anyone’s code that extended the 2 functions separately over their own types.