The following code gives me an error with Julia v1.4
# M1.jl
module M1
export M1Type
struct M1Type
data::Real
end
end
# M2.jl
module M2
using ..M1
export f
function f(x::M1Type)
end
end
# At the REPL (or main module)
using .M1
using .M2
f(M1Type(1))
and the error is
MethodError: no method matching f(::M1Type) Closest candidates are: f(::Main.M1.M1Type) Stacktrace:..
Currently the workaround I use is to have the main module only have using .M1, and use Reexport.jl to reexport everything in M1 from M2, but I shouldn’t need to do that, right?
Pasting exactly the code you provided into the REPL works as expected:
julia> # M1.jl
module M1
export M1Type
struct M1Type
data::Real
end
end
Main.M1
julia> # M2.jl
module M2
using ..M1
export f
function f(x::M1Type)
end
end
Main.M2
julia> # At the REPL (or main module)
using .M1
julia> using .M2
julia> f(M1Type(1))
julia>
Huh I just tried it again and it worked fine. Weird, sorry about that.
The results you’re seeing are consistent with having called include() on the same file in multiple different modules, which you not ever do
Yes, that’s exactly what I was doing. More precisely, this replicates the error:
(each section in its own file this time)
# module_1.jl
module M1
export M1Type
struct M1Type
data::Real
end
end
# module_2.jl
module M2
include("module_1.jl")
using .M1
export f
function f(x::M1Type)
end
end
#main.jl
include("module_1.jl")
include("module_2.jl")
using .M1
using .M2
f(M1Type(1))
If I don’t use the include statements in this way, the compiler complains about not being able to recognize certain functions/types. From what I’ve read, I could organize them into their own projects, and import them by modifying LOAD_PATH, but is that the only way to have local modules? It seems unnecessarily complex.
Yeah, you definitely don’t want to do that–you are creating two completely unrelated modules called M1 by calling include() twice. If you’re familiar with C++, this would be like including the same header outside of and inside of a namespace.
You don’t need to use projects for this (although projects are incredibly useful). Just add the current directory (“.”) to your LOAD_PATH and get rid of all your include() calls:
(Performance Tips · The Julia Language)
As far as I know, there is no reason at all to declare abstract types for immutable struct fields: since an immutable struct’s data fields cannot be changed, binding the value to a concrete type at construction incurs no restriction. There might only be a reason to do that for mutable types, where you might indeed need to change the data in object during its lifetime.