I wanted to structure my code by dividing it into several files. But I ran into some problem. So, in its simplest form, I have 3 files:
main.jl
module main
include("structs.jl")
include("functions.jl")
first_point = structs.Point(1.5, 1.5)
print(functions.distance(first_point))
end
functions.jl
module functions
include("structs.jl")
export distance
function distance(point)
return (point.x^2+point.y^2)^0.5
end
end
structs.jl
module structs
export Point
mutable struct Point
x::Float64
y::Float64
Point(x, y) = new(x, y)
end
end
And when i try to run main file I get this error:
ERROR: LoadError: MethodError: no method matching distance(::Main.main.structs.Point)
Closest candidates are: distance(::Main.main.functions.structs.Point)
So what’s the problem?
Alternatively remove the include statement from functions.jl
and only include structs.jl from main.
That depends a little bit on your desired program structure.
Do you want doubly nested modules by making structs a submodule of functions which itself lives in main?
Alternatively both functions and structs could live in main directly.
Note however that all these modules are not necessary at all in your case here. In particular your main module does not seem to serve an purpose.
Maybe you know this, but Julia doesn’t care what files your code lives in, nor what folders those live in, include is just like pasting the code into that file. (I forget whether there are edge cases, but this is the rough idea.) So you can split or combine them in whatever way you like.
But it does care about module a lot. And generally you shouldn’t be making sub-modules within other modules without a good reason. You appear to have two sub-modules main.structs and main.functions.structs which just happen to be defined with identical source code.
I’ve ran into the same problem.
My solution was to make Functions and Structs modules aware of each other.
main.jl:
module main
include("structs.jl")
include("functions.jl")
...
end # module
structs.jl:
module structs
using ..functions : ...
...
end # module
functions.jl:
module functions
using ..structs : ...
...
end # module
That way, functions loads structs module from the main namespace, and the error goes away. The downside is, of course, that modules functions and structs cannot be used in a stand-alone fashion.
I think, that I misunderstand, when there is necessary to create modules, because I have not met this in other languages. With the help of modules I can hide some functions from user. I have only one analogy - private methods and private attributes in OOP languages, but it isn’t good analogy
Yeah, this could be the case.
In my eyes modules are never necessary and in julia there is no way to truly hide functions from a user.
One typically exports public API but one can always access nonexported functions via MyModule.functionname.
Modules can be used to group various function/type definitions into a (potentially) separate name space
that allows you to easily include and reuse them.
As an example: In research projects I have one module that contains all my utility function definitions and machinery that I use in multiple places. My scripts load that module and work from there.
Namespaces are overrated, lets do less of those.
It is a bit of a mind-twist, I know.
Took me a while to get use to it.
Goal is to seperate functionality that is independent.
If it is truely independent, then it can be its own package.
If it isn’t then it can just go in the main module of the package.
Submodules work really poorly if the code isn’t independent, as importing things from the parent or sibling namespaces has to be done explictly.
Some valid uses of submodules modules:
You think it is independent, but you are not sure yet. Then a submodule lets you try it out. If you can indeed do it without suffering and importing from the parent namespace then it is independent, and you can later make a new package for it when you have time.
as a hack to allow all your enums to be referred to as EnumMod.enumval, by just putting the @enum as the only thing inside module EnumMod.
You are writing julia itself and making a submodule of Base, thus your parent module is inscope because it is Base and Base’s exports are always inscope. Also you don’t have the option of a standalone package (or even a stdlib) as Base can’t depend on those.
While I agree with most of what you say, I’m not sure about this bit. Well, I do agree that independent sets of features can go into separate packages, but why would they have to? If a given piece of code provides functionality that is independent, but so specific that it is only ever going to be used in a single application, why bother separate it into a package?
Developing two packages at the same time, one depending on the other, is much more cumbersome IMO than having two submodules in the same package, one using or importing the other. For example, when there is only one package, there is only one set of sources in a git repository, which means you don’t have to worry about which specific version of your application package depends on which specific version of your library package.
I fully agree with that, but I would add: “you can later make a new package for it when you have time and you have a use for this set of functionality in an other context”.