Avoid error message for function name conflict

Hi,

Is there a convenient way to avoid the error message when using two modules which export a function the same name?

Scenario is that package A depends on B and C. C just added a function which collides with one in B. Both C and B export alot of things which are used in A.

Is there an easier way than manually importing/qualifying everything out of B and/or C which A makes use of? Something like “use all but this from B”.

Out of curiosity: what were the function names and where the functions take at least one argument which was defined in the package? Were the functions conceptually very close in what they expected and returned, or so fundamentally different you would never mix them up?

To satisfy your curiosity then :slight_smile: : Name is flatten and in one package it turns an ND array into a matrix and in the other it turns a graph into an array of its vertices.

1 Like

This is probably helpful:

It appears that either fully qualified names (as in A.flatten) or explit importing of all used objects are the only options.

However, one entry suggests to redefine the conflicting names to make the code “nicer” as in myflatten(x) = A.flatten(x). That looks workable to me.

Thanks,

Using fully qualified names in A works of course, but it does not remove the warning when using/importing A.

To make matters worse, A reexports both B and C :frowning: .

Oh well, I guess I just learned a valuable lesson about encapsulation and it does not cost anything more than a major revision number and the inconvenience of having to always import stuff from B and C when using A :slight_smile:

About that using warning … I probably misunderstand, but this does not produce a warning:

# test1.jl
module B
    export foo
    foo() = println("B");
end

module C
    export foo
    foo() = println("C");
end


module A
    using ..B, ..C
    B.foo()
    C.foo()
end

using .A

and then on the REPL

julia> include("../scratch/test1.jl")
B
C

Sorry if I misunderstand the kind of warning you are talking about.

1 Like

@hendri54

Thanks alot for this!

It seems like the warning (which indeed is very helpful and potentially sanity preseving) is only produced when an actual unqualified call to the function is done in the module:

module B
   export foo
   foo() = println("B");
end

module C
   export foo
   foo() = println("C");
end


module A
   using ..B, ..C
   B.foo()
   C.foo()
   foo()
end

using .A

REPL:

julia> include("footest.jl")
B
C
WARNING: both C and B export "foo"; uses of it in module A must be qualified
ERROR: LoadError: UndefVarError: foo not defined

I could have sworn I had qualified all usage of flatten in A and I still got the warning when using it. I will double check it again but I think you just saved me one internet bit for a major revision number :slight_smile:

Ok, I have narrowed it down to this (it didn’t take me 2 hours, I was watching TV with the wife until she got tired, I promise):

#footest.jl
module B
    export foo
    foo() = println("B");
end

module C
    export foo
    foo() = println("C");
end


module A
    using Reexport
    @reexport using ..B
    @reexport using ..C
    import InteractiveUtils: subtypes
    subtypes(Integer)

    B.foo()
    C.foo()
end

using .A
julia> include("footest.jl")
WARNING: both C and B export "foo"; uses of it in module A must be qualified
B
C

Next stop is to see if there is some kind of witchcraft going on in Reexport could explain this…

This is the workaround I managed to come up with:

module B
    export foo
    foo() = println("B");
end

module C
    export foo
    foo() = println("C");
end


module A
    using Reexport
    @reexport using ..B
    @reexport using ..C

    module AA
        export T, TT
        abstract type T end
        struct TT <: T end
    end

    @reexport using .AA

    import InteractiveUtils: subtypes
    subtypes(AA, T)
end

using .A

Types TT and T where originally defined inside A, but that caused subtypes to trigger the warning when called. Putting them inside an internal module which is reexported seemed to avoid the issue.

Reexport was innocent here. Replacing it with explict exports (without the workaround) produced the same behaviour.

Less intrusive workaround:

module B
    export foo
    foo() = println("B");
end

module C
    export foo
    foo() = println("C");
end


module A
    using Reexport
    using ..B
    using ..C

    abstract type T end
    struct TT <: T end
    import InteractiveUtils: subtypes
    @show subtypes(A, T)

    @reexport using ..B
    @reexport using ..C
end

using .A