`using` and `import` can load files from the CWD? Surprising because it's not documented?

A colleague of mine has just noticed some behavior relating to using and import which we found surprising.

include will load a file from disk and (effectively) insert the code at the point where the include line ran.

We were not aware that using and import could load code files from disk.

It seems that they can. I don’t recall reading anything about this in the documentation and having a quick search through the section on modules I didn’t find anything about this either.

Here is an example which shows what we have discovered.

Directory structure

tmp/
  JuliaProject/
    main.jl
    MyModule.jl

Example

# MyModule.jl
println("my module")
julia> using MyModule
my module

Is anyone able to clarify? Should we have found this behavior surprising?

From my point of view, I thought that the way to combine multiple source files together was using an include statement. In other words, this statement allows splitting one source file into multiple files.

I also thought that import and using were statements which related to the importing of modules (namespaces) from one namespace path to another.

  • include → file behaviour
  • import, using → module behaviour

Please let me know! Thanks

It’s in a different spot talking about packages, which uses modules for the necessary encapsulation:
Code Loading · The Julia Language
The import statements for packages do not use leading dots.

2 Likes

To be frank, I’ve never used this form of defining a package, where the main “entry file” is just in some directory. It’s specifically the first point for the “Package Directories” list:

I always use an explicit src/X.jl form, to keep things more consistent and easier to navigate.

Thanks for the replies, I think there’s two pieces of information which are useful to know. (The following is quoted from the docs.)

  1. A package directory is a directory containing the source trees of a set of packages as subdirectories, and forms an implicit environment. If X is a subdirectory of a package directory and X/src/X.jl exists, then the package X is available in the package directory environment and X/src/X.jl is the source file by which it is loaded.

  2. Package loading: e.g. import X or using X. The import mechanism allows you to load a package—i.e. an independent, reusable collection of Julia code, wrapped in a module—and makes the resulting module available by the name X inside of the importing module. If the same X package is imported multiple times in the same Julia session, it is only loaded the first time—on subsequent imports, the importing module gets a reference to the same module. Note though, that import X can load different packages in different contexts: X can refer to one package named X in the main project but potentially to different packages also named X in each dependency. More on this below.

However this is not the complete story. Perhaps someone can help fill in the gaps?

If I run using MyModule, then Julia will search for several things:

  • MyModule.jl/src/MyModule.jl
  • MyModule/src/MyModule.jl
  • MyModule.jl

I think all of the above are searched (from the current working directory).

However, I think there are also other alternative paths - but I don’t recall the details.

Can anyone help to fill in the gaps or direct me to a doc page about this?

This only works if you’ve done push!(LOAD_PATH, "."), right?

4 Likes

Good questions - I am not sure actually. Let me check again…

I’ve just checked and found that I do not have any environment variable containing the word LOAD.

When in Julia ENV does not have a key LOAD_PATH.

I can still run using MyModule and get MyModule.jl to load.

However the following does not work:

  • using MyModule2 for MyModule2.jl/src/MyModule2.jl
  • using MyModule3 for MyModule3/src/MyModule3.jl

LOAD_PATH is just a global variable, not an environmental variable.

I strongly suspect you have something akin to push!(LOAD_PATH, ".") in a startup.jl file or similar.

1 Like

Thanks I’ll check.

Just found this too:

Package directories
Package directories provide a simpler kind of environment without the ability to handle name collisions. In
a package directory, the set of top-level packages is the set of subdirectories that “look like” packages. A
package X exists in a package directory if the directory contains one of the following “entry point” files:
• X.jl
• X/src/X.jl
• X.jl/src/X.jl

So I wasn’t imagining this. Let me check my LOAD_PATH.

Yes! You’re correct. . is in my load path.

Is there a convenient way to print all the global variables? I’d like to check something else…

Julia related environment variables typically start with “JULIA_”, e.g. “JULIA_LOAD_PATH” or “JULIA_NUM_THREADS”. And versioninfo() does display all environment variables with this prefix.

2 Likes