Introducing Julia/Modules and packages

From Wikibooks, open books for an open world
Jump to navigation Jump to search
« Introducing Julia
Modules and packages
»
Metaprogramming DataFrames

Modules and packages[edit]

Julia code is organized into files, modules, and packages. Files containing Julia code use the .jl file extension.

Modules[edit]

Related functions and other definitions can be grouped together and stored in modules. The structure of a module is like this:

module MyModule
 
end

and in between these lines you can put functions, type definitions, constants, and so on.

One or more modules can be stored in a package, and these are managed using the git version control system. Most Julia packages, including the official ones, are stored on GitHub, where each Julia package is, by convention, named with a ".jl" suffix.

Installing modules[edit]

To use an official (registered) Julia module on your own machine, you download and install the package containing the module from the main GitHub site. There's a big list of official packages available at pkg.julialang.org.

To download and install a package, you can use Julia's package manager. Start by typing a right bracket ] into the REPL to enter the package manager, then use the add command. You don't have to use quotes or the ".jl" suffix.

julia> ]
(v1.0) pkg> add Calculus
... messages
(v1.0) pkg>

(If you are not directly connected to the internet, you need to give the name of a proxy before calling the package installer.)

The (v1.0) in the prompt tells you that you're working in the default project, "v1.0", in ~/.julia/environments/.

If you want to update the packages you have, use the up command:

(v1.0) pkg> up
... messages
(v1.0) pkg>

For more information about Julia's powerful package management system, refer to the extensive documentation.

To leave the package manager mode, press the Backspace/Delete key.

Using modules[edit]

After installation, to start using functions and definitions from the module, you tell Julia to make the code available to your current session, with the using or import statements, which accept the names of one or more installed modules:

julia> using Calculus

julia>

On success, all the definitions in the Calculus module are available for use. If the definitions inside Calculus were exported by the module's author, you can use them without the module name as prefix (because we used using):

julia> derivative(sin, pi/2)
0.0

If the package author(s) don't export the definitions, or if we use import rather than using, you can still access them, but you have to type the module name as a prefix:

julia> Calculus.derivative(sin, pi/2)
0.0

but that's unnecessary in this example, as we've seen.

When you write your own modules, the functions that you choose to export can be used without the module name as prefix. Those that you don't export can still be used, but only if they are prefixed with the module name. For example, in the module called MyCoolModule, the mycoolfunction() was exported. So the prefix is optional:

julia> using MyCoolModule

julia> MyCoolModule.mycoolfunction()
"this is my cool function"

julia> mycoolfunction()
"this is my cool function"

Inside the module, this function was exported, using the export statement:

module MyCoolModule
export mycoolfunction

function mycoolfunction()
   println("this is my cool function")
end

end

using and import[edit]

import is similar to using, but differs in a few ways, for example, in how you access the functions inside the module. Here's a module with two functions, one of which is exported:

module MyModule
export mycoolfunction

function mycoolfunction()
   println("this is my cool function")
end

function mysecretfunction()
   println("this is my secret function")
end

end

Use import to import the module:

julia> import MyModule

julia> mycoolfunction()
ERROR: mycoolfunction not defined

julia> MyModule.mycoolfunction()
"this is my cool function"

Notice that mycoolfunction() could be accessed only when you use the module prefix. This is because the MyModule module was loaded using import rather than using. Similarly for mysecretfunction():

julia> mysecretfunction()
ERROR: mysecretfunction not defined

julia> MyModule.mysecretfunction()
this is my secret function

You can specify a set of modules:

julia> using Color, Calculus, Cairo

Another important difference is when you want to modify or extend a function from another module. You can't use using, you have to import the specific function.

Include[edit]

If you want to use code from other files that aren't contained in modules, use the include() function. This evaluates the contents of the file in the context of the current module, searching relative to the path of the source file from which it is called. It's like you just pasted the code in. This is useful for building code from a number of smaller files.

How does Julia find a module?[edit]

Julia looks for module files in directories defined in the LOAD_PATH variable.

julia> LOAD_PATH
3-element Array{Any,1}:
 Base.CurrentEnv()                                                                                                                     
 Any[Base.NamedEnv("v1.0.0"), Base.NamedEnv("v1.0"), Base.NamedEnv("v0"), Base.NamedEnv("default"), Base.NamedEnv("v1.0", create=true)]
 "/Applications/Julia-1.0.app/Contents/Resources/julia/share/julia/stdlib/v1.0"                                    

To make it look in other places, add some more using push!:

julia> push!(LOAD_PATH, "/Users/me/myjuliaprojects")
4-element Array{Any,1}:
 Base.CurrentEnv()                                                                                                                     
 Any[Base.NamedEnv("v1.0.0"), Base.NamedEnv("v1.0"), Base.NamedEnv("v0"), Base.NamedEnv("default"), Base.NamedEnv("v1.70, create=true)]
 "/Applications/Julia-1.0.app/Contents/Resources/julia/share/julia/stdlib/v1.0"                                                        
 "/Users/me/myjuliaprojects"      

And, since you don't want to do this every single time you run Julia, put this line into your startup file ~/.julia/config/ startup.jl, which runs each time you start an interactive Julia session.

Julia looks for files in those directories in the form of a package with the structure:

ModuleName/src/file.jl

Or, if not in Package form (see below), it will look for a filename that matches the name of your module:

julia> using MyModule

and this would look in the LOAD_PATH for a file called MyModule.jl and load the module contained in that file.

Packages[edit]

To see all the packages you've installed:

julia> ]
(v1.0) pkg> status
   Status `~/.julia/environments/v1.0/Project.toml`
 [c7932e45] AstroLib v0.3.0
 [9e28174c] BinDeps v0.8.8
 [159f3aea] Cairo v0.5.2
 [49dc2e85] Calculus v0.4.0
 [3da002f7] ColorTypes v0.6.7
 [5ae59095] Colors v0.8.2
 [861a8166] Combinatorics v0.6.0
 [34da2185] Compat v0.68.0
 [864edb3b] DataStructures v0.8.3
 [5789e2e9] FileIO v0.9.0
 [53c48c17] FixedPointNumbers v0.4.6
 [28b8d3ca] GR v0.31.0
 [a2bd30eb] Graphics v0.3.0
 [9fb69e20] Hiccup v0.2.1
 [a4bce56a] Iterators v0.3.1
 [e5e0dc1b] Juno v0.4.1
 ... messages 
 ...
(v1.0) pkg> 

Structure of a package[edit]

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.jl. This is how the Calculus package is organized in terms of files on disk:

Calculus.jl/                                       # this is the main package directory for the Calculus package
  src/                                             # this is the subdirectory containing the source
    Calculus.jl                                    # this is the main file - notice the capital letter
      module Calculus                              # inside this file, declare the module name
        import Base.ctranspose                     # and import other packages
        export derivative, check_gradient,         # export some of the functions defined in this package
        ...
        include("derivative.jl")                   # include the contents of other files in the module
        include("check_derivative.jl")             
        include("integrate.jl")
      end                                          # end of Calculus.jl file
    derivative.jl                                  # this file contains code for working with derivatives, 
      function derivative()                        #      and is included by Calculus.jl
        ...
      end
        ...
    check_derivative.jl                            # this file concentrates on derivatives, 
      function check_derivative(f::...)            #      and is included by "include("check_derivative.jl")" in Calculus.jl
        ...
      end
      ...
    integrate.jl                                   # this file concentrates on integration, 
      function adaptive_simpsons_inner(f::Funct   # and is included by Calculus.jl
        ...
      end
      ...
    symbolic.jl                                    # concentrates on symbolic matters; included by Calculus.jl
      export processExpr, BasicVariable, ...       # these functions are available to users of the module
      import Base.show, ...                        # some Base functions are imported, 
      type BasicVariable <: AbstractVariable       # ... so that more methods can be added to them
        ...
      end
      function process(x::Expr)
        ...
      end
      ...     
  test/                                            # this directory contains the tests for the Calculus module
    runtests.jl                                    # this file runs the tests
      using Calculus                               # obviously the tests use the Calculus module... 
      using Base.Test                              # and the Base.Test module... 
      tests = ["finite_difference", ...            # the test file names are stored as strings... 
      for t in tests
        include("$(t).jl")                         # ... so that they can be evaluated in a loop 
      end
      ...
    finite_difference.jl                           # this file contains tests for finite differences, 
      @test ...                                    # ... its name is included and run by runtests.jl
      ...