Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Julia: use cases for `import` and `using`

Tags:

julia

So I read the documentation for using and import in Julia. However what this does not tell me is how I should be using these two statements in practice (and, given the lack of orthogonality, this is not too easy).

Case in point: let's put the following trivial code in "myfile.jl":

module MyModule
f() = 1
export f
end
import .MyModule # or: using .MyModule
  • if I use import on the last line, then f is not exported to Main namespace. However, when I change "myfile.jl" (e.g. modifying the return value of f) and then re-include it, the function is replaced (this is the behaviour I wish for). (Note that I could explicitly import .MyModule: f, but this introduces unneeded redundancy; also, the real-life case will involve a long list of functions with long names. OK, I might also write a macro that uses names(Main.MyModule), but I somehow feel that this ought to be simpler.)

  • if I replace import by using, then this is reversed: f is now exported, but changing anything in the module now requires re-starting the Julia interpreter.

  • using both import and using exports only the first version of f() to the main namespace: when I update the code, only the first return value is used.

So my question is not about the behaviour of both statements import and using, which are documented (if not explained) in the linked page, but about the intent behind these. Why two statements when one would be enough? Why does one of these ignore all export directives? In which case am I supposed, in practice, to use each statement?

(version is 1.1.0. Also, this runs on a system without easy Pkg access, so I did not try Revise yet.)

like image 220
Circonflexe Avatar asked Oct 08 '20 10:10

Circonflexe


People also ask

What is the difference between import and using in Julia?

My guess based on reading the docs: using is used to bring another module into the name-space of the current module. import is used to bring specific types/functions/variables from other modules into the name-space of the current module.

Where does Julia Look for packages?

Julia uses git for organizing and controlling packages. By convention, all packages are stored in git repositories, with a ". jl" suffix. So the Calculus package is stored in a Git repository called Calculus.

What is the difference between using and import in Julia?

Question: What is the difference between using and import in Julia when I'm building my own module? My guess based on reading the docs: using is used to bring another module into the name-space of the current module. import is used to bring specific types/functions/variables from other modules into the name-space of the current module.

How does @Julia package export functions?

Julia is using multiple dispatch and typically packages export functions that operate on typed arguments (those are however usually abstract types so functions functionality is not limited).

How is module code organized in a Julia package?

Typically, in larger Julia packages you will see module code organized into files, eg Files and file names are mostly unrelated to modules; modules are associated only with module expressions. One can have multiple files per module, and multiple modules per file. include behaves as if the contents of the source file were evaluated in its place.

How do I avoid using exports in Julia?

We can avoid using exports by directly importing the types or functions that we want to use in Julia: A direct import will load the code we are targeting without including all of the other ingredients inside of the package.


Video Answer


2 Answers

The convention in Julia is to use using PackageName unless you have some specific reason to do otherwise.

This language design decision is motivated simply by users' comfort. Julia is using multiple dispatch and typically packages export functions that operate on typed arguments (those are however usually abstract types so functions functionality is not limited).

With this design all functions and methods implementing them can be in the same namespace since they differ on parameter types that are specific for their packages. Hence, a scenario where using brings a package to the namespace that overrides existing method implementations are very rare (and then Julia reports a warning). This process is additionally controlled by package authors through using the export keyword.

I think that it looks strange to you because you are accustomed to languages like Python. For an example numpy has the exactly the same function names as the default functions and there is no good way to name them differently (e.g. try to think what would be a good alternative for a function named sin :-) ). Hence, in Python you always need to import functions into their own namespaces perhaps with an alias such as import numpy as np. After having several years of experience with both languages I would say that the way Julia does it is natural and the Pytonish way is strange :-)

Regarding import and possibilities of bringing single functions from a package to your namespace, I see it as workarounds for situations where a name clash occurs. Also you need to explicitly do that if you want to add new method implementations to some other package (like defining a new meaning for the + operator). Other than that you just type using and never look back.

like image 192
Przemyslaw Szufel Avatar answered Oct 10 '22 11:10

Przemyslaw Szufel


One thing to add, in addition to Przemyslaw Szufel's answer. When you are extending a method, it's possible to do that without using import for the function that you are extending. For example, if I want to extend f from the module Foo, I can do using Foo and then define a new method for Foo.f. Here's a complete example:

module Foo
    struct A
        x::Int
    end

    f(a::A) = a.x + 1

    export A, f
end

using .Foo

struct B
    x::Int
end

Foo.f(b::B) = b.x + 2

The advantage of this approach is that when you are reading the code it is easier to see the origin of the function that you are extending.

like image 43
Cameron Bieganek Avatar answered Oct 10 '22 10:10

Cameron Bieganek