Modules and namespaces

Hey everyone, so I have a weird namespace issue. I import a struct “parameter” into a module QuadratureTypes, then import a function which takes an instance of parameter as input from QadratureTypes into another module, where I attempt to use it.

# parameters.jl
module Parameters
abstract type Parameter end
struct parameter <: Parameter
...
module QuadratureTypes
include("../../core/parameters.jl")
using .Parameters: parameter, Parameter
...
include("../../../src/core/parameters.jl")
using .Parameters: Parameter, parameter
function quad_info(p:: parameter) 
...

However when I try to use the function quad_info, it complains of an unmatched input arg.

quad_info(!Matched::Main.QuadratureTypes.Parameters.parameter)

The type of the input I am passing in is the following

parameter

How did these two versions of parameter come about, and did I do something wrong in my imports? Why is there both parameter and Main.QuadratureTypes.Parameters.parameter instead of a single one?

My guess is, you have a

using QuadratureTypes

and a

include("...somepath...parameters.jl")

in your main for your function quad_info to know about parameter.

Try to remove the include and refer to the types parameter and Parameter only with
QuadratureTypes.Parameters and QuadratureTypes.parameters.

Does this make sense?

By the way: the convention is to make types starting with uppercase. So it would be, if you like to follow the convention, Parameter and e.g.

struct ParameterStruct <: Parameter
...
4 Likes

Perhaps this is helpful (really just explaining oheil’s answer a bit): If you include the same file twice, it usually indicates a problem.
In this case, you seem to include “parameters.jl” in Main and in QuadratureTypes.
This results in Main.Parameter being different from Main.QuadratureTypes.Parameter.

4 Likes

Thanks for your replies @hendri54 and @oheil. The naming convention has been noted. However, if including the same file twice poses a problem, then how do I go about reusing a struct from a module? I have a file parameters.jl containing the module Parameters containing the struct parameter. In order to use the struct parameter in other modules, it appears that I have to first do include(...parameters.jl) followed by either using or import .Parameters: parameter inside of the module. Then when I export functions from these modules, they aren’t compatible with the original parameter type, but rather a local copy of parameter imported in the scope of the module.

If I remove the include at the start of the module, I can’t do using .Parameters: parameter, Parameter because Parameters is not defined.

See Need to include one file multiple times, how to avoid warning - #5 by rdeits or Dependencies of src files inside a package - #2 by rdeits for how to avoid including the same file multiple times, or see Trouble importing a module that depends on another globally imported module - #7 by rdeits or Error with modules sharing types - #4 by rdeits for how to avoid needing include at all.

3 Likes

Thanks for these links @rdeits! They solved my problem. However, I wonder what implications this has for testing. If the accepted style is to includes() separate files into a monolithic module (albeit using few lines of code), the the test file for that monolithic file will be large. From what I’ve seen, a lot of Julia packages have test files which are >2000 LOC, because the individual files which get included in the module can’t be tested on their own, as they aren’t standalone, so to speak. This is unlike what I’ve seen in Python packages.

Even if all the code to be tested lives in a single module, nothing prevents you from structuring the tests so that tests for subsets of the code can be run independently.
I typically have one big @testset in runtests.jl that just consists of a bunch of include statements. In your case, you might include("parameters_test.jl"), which in turn consists of a @testset that calls a bunch of functions. Each function contains yet another @testset the focuses on one feature of the code.
That way I can include("test/parameters_test.jl") from the REPL to just run those tests. And the functions provide some isolation of the tests from each other.
Perhaps I am overcomplicating things this way, but it has worked well for me.

2 Likes