Import struct from other module as a parameter

I’ve following dir structure:

-> Calc (root dir)
        -> src
            -> Calc.jl
            -> Controls.jl
            -> Models.jl

Below are the content of the files:
Calc.jl:

module Calc

    include("Models.jl")
    include("Controls.jl")

    export Models,Controls

end # module

Models.jl

module Models
    struct Position{P <: Real}
        x::P
        y::P
    end

    struct Size{P <: Int}
        width::P
        height::P
    end
    struct Widget{N <: String,P <: Position,S <: Size}
        name::N
        postion::P
        size::S
    end
end

Controls.jl

module Controls
    move_up!(widget::Models.Widget, velocity) = widget.position.x + velocity
end

I get errors when I try to add Widget as a parameter to my function defined in Controls.jl file.

How can I properly define my parameter ?

Please note the following constraints:

  • Should use Modules
  • Should not merge Controls and Models content in one single file

Please help thanks

Maybe, this thread helps:

If you want to work with submodules, you could do something like:

# calc.jl
module Calc

export myWidget, useMyWidget

include("models.jl")
include("controls.jl")

using .Models, .Controls

end

and

# models.jl
module Models

export myWidget

struct myWidget
    x::AbstractString
end

end

and

# controls.jl
module Controls

using ..Models
export useMyWidget

function useMyWidget(w::myWidget)
    println(w.x)
end

end

then:

julia> include("calc.jl")
Main.Calc

julia> using .Calc

julia> useMyWidget(myWidget("test"))
test

see: Submodules and relative paths in the manual.

3 Likes

Thanks for the responding at code level.

I’m from a python background and the way I import modules/functions is based on root directory. Example:

Dir:
src
    -> A.py
    -> B.py

# A.py
def bar():
    pass

#B.py
import A
def foo():
    A.bar()

It’s really confusing to understand the submodules path added in the main file and then import in the other file according to it.

The confusion comes because we mix here two things: include and sub modules. Think of it as one big source file where the submodules are defined like in the manual example.

Submodules are necessary if you want to have different namespaces inside your main module and where you want to control explicitly what is visible in each namespace. Normally you don’t use them because one module namespace is sufficient for most libraries.

Therefore I recommend to use the approach outlined in the other thread linked to in my first response: have one module where you include your source files. It makes a programmer’s life much easier.

4 Likes

Thanks for the response.

I have went through the post you wrote, but still I don’t get this from a user experience point:

If I’m a maintainer of the repo I do understand that src/A.jl is included in main namespace and I can define my parameters without an explicit import.

But for the first time viewer don’t you think this would be a nightmare to understand that AbstractA is a part of main namespace.

Ref Link:

AbstractA is declared in the namespace of MyPackage. It is exported and gets into Main namespace if a user does a using MyPackage there.

You as the module owner decide if it gets exported. In that case you export it since you want your users to be able to use my_func and my_other_func.

Why is that a nightmare? You write a nice docstring and everything should be clear. No?

Just chiming in here with a guess, but perhaps the OP is referring to the common practice when using Julia packages to inject all kinds of symbols into the current namespace. The more-or-less equivalent form in Python would be from M import *, which is used far less often as the import M form, precisely because the former pollutes the namespace of the importing scope with (part of the) contents of M. The second form only introduces M in the current scope and the Python user then picks the symbols he/she wants with M.func or similar. There’s also from M import func (or even from M import func as m_func to rename on importing), to further control what gets imported and to avoid clashes with existing symbols. But in Julia adding methods to existing functions is kind of fundamental (plus having using pollute the importing scope by default) and was something I really needed to get used to as a long-time Python user myself.

Edit: Python import clearified further