Different modules with nested structures

Consider two functions, function Y and function Z. The parameter values of these functions are stored in two different structures, ParametersY and ParametersZ. Suppose the functions are nested, where Z uses Y. Then it seems logical to nest the structures as well, where ParametersY is included as a field in ParametersZ. Suppose the structures ParametersY and ParametersZ are defined in two separate modules.
The first module is:

module ModuleY
struct ParametersY
	a::Int64
end
export ParametersY
end

The second module is:

module ModuleZ
include(“ModuleY.jl”)
using .ModuleY
struct ParametersZ
	parent::ParametersY
	b::Int64
end
export ParametersZ
end

If you then do the following:

include(“ModuleY.jl”)
using .ModuleY
include(“ModuleZ.jl”)
using .ModuleZ
parsY = ParametersY(5)
parsZ = ParametersZ(parsY,3)

you get the following error message:

ERROR: MethodError: Cannot `convert` an object of type ParametersY to an object of type Main.ModuleZ.ModuleY.ParametersY

This can be solved by adding ParametersY to the export of ModuleZ, and then defining parsY and parsZ as follows:

parsY = ModuleY.ParametersY(5)
parsZ = ParametersZ(ModuleZ.ParametersY(5),3)

But with complex code, with several functions that are nested in each other, this may easily become very cumbersome. Isn’t there an easier way to go ahead? The ultimate goal is to get a library of functions that may refer to other functions and structures to store their parameter values (some of which may therefore be used by other functions if functions are nested).

If you do this, it becomes a bad idea to try to include ModuleY independently of ModuleX, generally only ModuleX would be included in such a case. That’s because independent includes run the source code again and create independent copies in different global scopes. If you want to reuse code, include once and import repeatedly.

The typical possibility is to make ModuleZ dependent on ModuleY existing in the same scope so your include statements can all be in the same place:

# ModuleY.jl
module ModuleY
...
end

# ModuleZ.jl
module ModuleZ
  using ..ModuleY # this assumes ModuleY exists in same scope as ModuleZ
...
end

# main file
include(“ModuleY.jl”)
using .ModuleY
include(“ModuleZ.jl”)
using .ModuleZ

Another possibility is to nest ModuleY in ModuleZ as before, but you chain exports out of ModuleZ like this. Then the following works just fine:

julia> include(“ModuleZ.jl”) # includes ModuleY inside

julia> using .ModuleZ

julia> parentmodule(ParametersY), parentmodule(ParametersZ)
(Main.ModuleZ.ModuleY, Main.ModuleZ)

julia> parsY = ParametersY(5)
ParametersY(5)

julia> parsZ = ParametersZ(parsY,3)
ParametersZ(ParametersY(5), 3)
2 Likes

Exactly, when you include the file twice you are creating two modules with the same name. Never include a file twice, it only creates problems.

1 Like

Yes, works smoothly and is very logical. Thank you very much!