Intro to Julia package development

Principles and examples

Mathieu Besançon
Twitter: @MathieuBesancon
mbesancon.github.io

Julia Montréal February Meetup

Outline

  • Modules, packages, why bother?
  • Package structures
  • Live-coding our first package(s)
  • Publishing our work on Github

Packages & modules, why bother?

Julia modules define a scope for variables, functions, ...

  • Solves the "two-language problem" ==> Develop libraries as you use them
  • Tools make it easy to create, develop, publish (Pkg, PkgDev)
In [1]:
import JuMP
@show JuMP.solve
JuMP.solve = JuMP.solve
Out[1]:
solve (generic function with 1 method)
In [3]:
import DifferentialEquations
@show DifferentialEquations.solve
DifferentialEquations.solve = DiffEqBase.solve
Out[3]:
solve (generic function with 34 methods)

Now getting messy...

In [4]:
using JuMP # all things from JuMP imported in scope
using DifferentialEquations # same for DifferentialEquations
In [5]:
# solve?
@show solve
WARNING: both DifferentialEquations and JuMP export "solve"; uses of it in module Main must be qualified
UndefVarError: solve not defined

Stacktrace:
 [1] include_string(::String, ::String) at ./loading.jl:522

When identifier source is ambiguous, call explicit

import MyModule
y = MyModule.func(x)

Package structure

Code regrouped for a specific purpose.

  • Easily sharable and publishable
  • Re-usable for different projects

structure

Main elements

src/

Contains the source code you develop, wrapped in at least a module

test/

Used to import your package and test its expected behavior as a user would.
How well did you test your package? This can't be cheated by coveralls.
Example with LGFlows

REQUIRE

  • Manages dependency in Julia up to v0.6
  • julia v1.0 brings Pkg3 with behavior similar to Cargo

docs

Detailed documentation of the package built however you like.
The Documenter.jl package is a common choice.

Live coding a package

FuncMat.jl

Matrix elements $m_{ij}$ often defined as a function of the index.

Identity matrix $I$

  • $I_{ij} = 1$ if $i = j$
  • $I_{ij} = 0$ otherwise

\begin{bmatrix} 1 & 0 & 0 &...\\ 0 & 1 & 0 &...\\ 0 & 0 & 1 &...\\ & & ... & \\ ... & & & 1\\ \end{bmatrix}

Unit lower triangular matrix $L$

  • $L_{ij} = 1$ if $i \geq j$
  • $L_{ij} = 0$ otherwise

\begin{bmatrix} 1 & 0 & 0 &...\\ 1 & 1 & 0 &...\\ 1 & 1 & 1 &...\\ & & ... & \\ 1 & 1 & ... & 1\\ \end{bmatrix}

ClippedVector.jl

Errors in scientific computing:

In [ ]:
vec = [3, 5, 7]
i = 2
j = 1
elem = vec[length(vec)*i + j] # oh no!
> BoundsError: attempt to access 3-element Array{Int64,1} at index [7]

Occurs in signal / image filter, time-series analysis, ...
A solution would be a "clipped access" to the vector:

vec = [3, 5, 7]
vec[1] # returns 3
vec[0] # would return 3
vec[3] # returns 7
vec[4] # would return 7

Thank you for listening!
Questions?