Modules - BenoitKnecht/julia GitHub Wiki
The simple view is that a module is a global variable space, together with features for sharing and hiding global definitions with other modules.
Every piece of code exists within some module. The REPL places you inside the User module by default. Built-in definitions are in the System module.
You can create a new module at any point like so:
module MyModule import OtherModule import SpecialFunctions: gamma export foobar myglobal = 3 function foobar(x) return 2*gamma(x) + myglobal*OtherModule.bar(x) end end
The first import statement makes OtherModule's exported symbols available as OtherModule.something. The second import statement imports a specific binding from another module, which can then be used unqualified. The export statement specifies which symbols will be visible outside MyModule. Nothing else will be visible to others.
In more detail, a module consists of:
- A name
- A list of exported bindings
- A set of bindings
- A list of imported modules
- Macro definitions
- A name, used as its lookup key
- A value
- A type
- Whether it is constant
Given an expression A.B, if A is not defined as a local or global variable, and the current module has an import for a module called A, then A.B refers to the B in module A. Otherwise it is a field reference expression.
These all have fairly obvious meanings
import Module import Module as Mod import Module: * import Module: func1, func2 import Module: func* import Module: func1 as func
Note that source files and the load function have nothing to do with modules. load is just a way to make the system look at a piece of code. When it sees a module Foo expression, it creates and registers a new module, and imports it into the current module (the module we were "in" when the module expression was encountered). A file may contain multiple module expressions. Module expressions may be nested, but this doesn't have any bearing on their meaning—inner modules cannot see bindings in their enclosing module(s) without importing them. Modules may import each other.
We might allow a module to span multiple files somehow.
It is possible to imagine a mechanism for automatically loading the correct file when an import statement is encountered. For example, import Foo might look for Foo.j in some standard directory.
Note that it is possible to further organize and isolate functions by creating many small modules and combining them into a "container" module:
module MyLibrary import MyLib_piece1: * import MyLib_piece2: * import MyLib_piece3: * end
My first instinct is to disallow changing bindings from other modules:
import Module: foo foo = 2
I feel this should add a foo binding to the current module, shadowing the imported binding.
That makes sense, but do we want bindings to change around based on what code has run? For example
import Module: foo function f1() foo(x) end function f2() global foo = 2 end
Does f1() fail only if f2() has already run? This makes me think the "foo = 2" should be an error.