Pedro G.
Pedro G.

Reputation: 405

Including a module and calling one of its functions from within another module in Julia

Let's say I have a module, Module1 defining a struct and a fit() function. I have another module, call it Parent, that includes Module1 and defines a test() function that also calls fit(). If I define the structure from Module 1 and then call test() from Parent I'm having trouble with the namespaces. Here's the code for this example:

#this module would be in a separate file
module Module1
    struct StructMod1
    end
    export StructMod1
    function fit(s::StructMod1)
    end
    export fit
end

module Parent
    #including the module with include("Module1.jl")
    module Module1
        struct StructMod1
        end
        export StructMod1
        function fit(s::StructMod1)
        end
        export fit
    end
    #including the exports from the module
    using .Module1
    function test(s::StructMod1)
        fit(s)
        return s
    end
    export test
end

using .Parent, .Module1

s = Parent.Module1.StructMod1()
@show test(s)
s2 = StructMod1()
@show test(s2)

And the output

test(s) = Main.Parent.Module1.StructMod1()
ERROR: LoadError: MethodError: no method matching test(::StructMod1)
Closest candidates are:
  test(::Main.Parent.Module1.StructMod1) 

Alternatively, if I replace using .Module1 with using ..Module1 then the definition of s2 works. But then, when calling using .Parent I have to make sure that Module1 is already loaded.

What is the best way to define a struct with one module and then use it with another module's functions?

Upvotes: 3

Views: 1370

Answers (1)

David Sainez
David Sainez

Reputation: 6956

The double include is causing the error. In your example, Parent.Module1 is not the same as Module1. Its useful to think of include as a dumb copy/paste. Even though they share the same source file, the double include makes them appear as two different modules (as your example shows).

The solution is to include only once and use relative imports to refer to the module.

As for organizing the whole set of modules, I like to include all the modules sequentially in the main module and then use relative imports where needed. I find this to be the simplest approach.

The final version would look something like this:

# Module1.jl
module Module1
    struct StructMod1
    end
    export StructMod1
    function fit(s::StructMod1)
    end
    export fit
end
# Parent.jl
module Parent
    using ..Module1
    function test(s::StructMod1)
        fit(s)
        return s
    end
    export test
end
#Main.jl
include("Module1.jl")
include("Parent.jl")

using .Parent, .Module1

s = Parent.Module1.StructMod1()
@show test(s)
s2 = StructMod1()
@show test(s2)

Upvotes: 2

Related Questions