Trouble importing a module that depends on another globally imported module

I have a project which is structured like:

Connect4Solver:
->Connect4Board.jl
->MCTS.jl

Connect4Board.jl defines a module Connect4Board which defines a type Board.
MCTS.jl defines a module MCTS which imports Connect4Board as follows:

include("Connect4Board.jl")
using(.Connect4Board)

After importing both of these modules into the REPL the same way (changing just the name for the MCTS import), I am able to create new instances of the Board type.
However, when I go to pass an instance of this into functions declared in the MCTS module, I get the following error:

ERROR: MethodError: no method matching MCTSpickmove(::Board)
Closest candidates are:
  MCTSpickmove(::Main.MCTS.Connect4Board.Board, ::Float32) at D:\Users\Zachary\Julia Projects\Connect4Solver\MCTS.jl:67
  MCTSpickmove(::Main.MCTS.Connect4Board.Board) at D:\Users\Zachary\Julia Projects\Connect4Solver\MCTS.jl:67
Stacktrace:
 [1] top-level scope at none:0

I am able to avoid this error by exporting the necessary parts of Connect4Board from MCTS instead of directly importing both into the REPL, but that seems pretty sloppy. Is there a better way to get around this?

Perhaps you’re defining the module multiple times by using include? This can be very confusing because it redefines a new module with the same name, and is rarely what you want. Instead you should add your module to the load path and it will be found automatically by using, or at least have a single file which includes both modules exactly once.

Consider the following sad and confusing story-in-code:

julia> module A
           struct B end
           foo(b::B) = "something"
       end
Main.A

julia> b = A.B()
Main.A.B()

julia> A.foo(b)
"something"

julia> OldA = A
Main.A

julia> module A
           struct B end
           foo(b::B) = "something"
       end
WARNING: replacing module A.
Main.A

julia> A.foo(b)
ERROR: MethodError: no method matching foo(::Main.A.B)
Closest candidates are:
  foo(::Main.A.B) at REPL[11]:3
Stacktrace:
 [1] top-level scope at none:0

julia> b isa A.B
false

julia> b isa OldA.B
true

Note the “WARNING: replacing module A”. If you ever see this kind of thing, it means you’ve redefined a module with the same name as an existing module. Any variable b which you had hanging around from the old module is still available, but it has the type OldA.B (printed as A.B) rather than A.B (also printed as A.B!). This might be the problem you’re having if you’re calling include multiple times on a file with the module code inside.

4 Likes

I see what you’re saying here, but I’m not importing them both in the same namespace. It never gives a warning like that either.

Fair enough, I was just taking a guess based on incomplete information. If you can provide a link to the code or a reduced version of the code which is causing the problem then it will be easier to understand your confusion. See PSA: make it easier to help you.

1 Like

How exactly are you doing this? If you are include()-ing both files, then this is exactly the problem that @Chris_Foster described: you have two copies of your Connect4Board module, one of which from the include() at the REPL and another from the include() inside MCTS.jl.

2 Likes

Yeah just identical include and using. If this is the issue, how would I avoid that? For example, with MCTS.jl depending on the Connect4Board module, it can’t compile when that module isn’t imported.

If you do:

push!(LOAD_PATH, "/path/to/your/src")

then you should be able to do:

using YourPackageName

without needing to include() anything from the REPL.

2 Likes

I was a bit wary of changing LOAD_PATH for something I’m still testing, but I suppose there is always removing from it too, so I guess this is the best way. Thank you!

Perhaps you didn’t see the warning because you were including one module inside the other, and then including it again inside Main? Then you’d get Main.A and Main.B.A where the names don’t clash (and you get no warning), but it’s essentially the problem I described above.

[Edit: I see @rdeits already suggested this explanation]

Yeah it looks like you were right. Thanks for the help!