Function whose parameter type is defined in another module

I have a custom module called Utilities, where I define the struct Utility

# utilities.jl
module Utilities

export Utility 

mutable struct Utility
 # etc...
end

# ..etc

end

and another module called SimplexTools where I am trying to import the module Utilities and declare a function whose arguments are of type Utility:

# simplexTools.jl
module SimplexTools

include("./utilities.jl")
using .Utilities

function buildSimplex(utilityA::Utility, utilityB::Utility)
# etc...
end

end

And, finally, I have a third module called EnvyFree that creates two instances of these Utility structs and calls the SimplexTools function buildSimplex, but when I run my code, I get the following error (I have simplified the folder structure a little bit for clarity):

ERROR: LoadError: MethodError: no method matching buildSimplex(::Main.Model.EnvyFree.Utilities.Utility, ::Main.Model.EnvyFree.Utilities.Utility)
Closest candidates are:
  buildSimplex(::Main.Model.EnvyFree.SimplexTools.Utilities.Utility, ::Main.Model.EnvyFree.SimplexTools.Utilities.Utility)

I have tried importing with import .Utilities: Utility, integrateUtility but it didn’t work. I don’t understand what’s happening here…

If you do include("utilities.jl") in both SimplexTools and EnvyFree you are just creating two different Utilities modules that happen to share the same name and code inside, but are seen as separate modules by Julia so Utility inside SimplexTools is not the same type as Utility inside EnvyFree, hence the error you see.

You need to have both SimplexTools and EnvyFree pointing to the same Utilities module.

The best way would be to have all the three be put into their own local packages and then you simply load the Utilities module in both SimplexTools and EnvyFree.

Have a look at 5. Creating Packages · Pkg.jl on how to generate your own packages (it’s a very simple process especially if you just want to have them locally without publishing. It also has a significant amount of benefits over simply loading module inside the REPL with include so it’s definitely worth it).

You can then refer to 3. Managing Packages · Pkg.jl for learning how to include one package (in your case Utilities) within the environment of another (SimplexTools and EnvyFree).

2 Likes

Thank you, that’s exactly what I was looking for!

Your modules don’t have to be in different packages, they can be module blocks in the same parent global scope. using ..Utilities would work in your module SimplexTools block then, don’t need an accompanying include("./utilities.jl"). You need 2 dots to reach the scope containing both SimplexTools and Utilities, 1 dot only reaches SimplexTools which does not contain Utilities. The 1st dot may seem unnecessary but it does distinguish it from true packages.

If the modules are big enough that you prefer them in separate files, you could split them into module blocks files and include them together in a parent file that you run; include is basically pasting code in the global scope, so note that all these files end up sharing the same parent scope containing the module blocks.

I’d prefer this when the modules are fairly interconnected, like EnvyFree using both SimplexTools and Utilities. But if Utilities is more independent and can be part of other distinct projects, best to make it a package.

1 Like