Difference between "using" and "include"?


The documentation on Modules and the usage of “using” vs “include” is a not crystal clear I think.
I have a main Julia script and three scripts in separate .jl files (in the same directory).


<some code>
end of script

The code executes as I anticipate.

I think if the “include” statement as a proxy for the the code in the “sub-scripts”. I.e. the include(“script1.jl”) represents the code in the sub-scripts line by line in the main script. It is as if the code in the script1.jl is actually in the main.jl script. Is this the right way of thinking of the include statement?
The scope of variables in the main.jl seem to include the ones in the “sub-scripts” when I run main.jl

What is then the difference of using the “using” statement vs the include statements? (I am aware of the necessity to specify the load path for modules in JULIA_LOAD_PATH). Is it same but different? Or same same?
It seems to be same but different, in the sense that in a module you need to use the export statement for variables and functions that you want to be in the main scope. But in the “include” statement all variables and functions are in the main scope by default. Am I right?



using (and import or importall) are completely different from include. They lookup a module in a list of predefined paths and load a module globally (which has nothing to do with the current scope) and then import bindings from that module to current scope.


Julia’s include is a function, not a simple input redirector (as in C, Fortran, or Matlab). The documentation says (emphasis mine)

Evaluate the contents of a source file in the current context.

“The current context” means the global scope of the current module when the evaluation takes place. Continuing,

This function is typically used to load source interactively, or to combine files in packages that are broken into multiple source files.

and for those purposes the distinction usually doesn’t matter.

Another use for the textual “include” in other languages is reuse of code blocks in local contexts (where the Julia include function may do surprising things). A Julian pattern for this would use macros. A nice example is the @def macro used inside the DifferentialEquations.jl ecosystem. There, one includes a file containing @def macro definitions, the definitions are evaluated right then, and the macros are used to paste in blocks of code at parsing time.


It seems using/import is equivalent to include when loading a file in LOAD_PATH:

#test.jl in pwd()
x = 1
module Foo
  y = 2
  export y

julia> push!(LOAD_PATH,pwd())
julia> import test
WARNING: requiring "test" in module "Main" did not define a corresponding module.
julia> whos()
                          Base  34459 KB     Module
                          Core  12386 KB     Module
                           Foo   1194 bytes  Module
                          Main  41327 KB     Module
                           ans      0 bytes  Void
                             x      8 bytes  Int64


This is an side effect of module loading/evaling in the Main module, which is also where the REPL runs. Doing things other than defining a module and expect those side effects be preserved will not work in general.