Writing a package in Julia
Nov 3, 2021
In tandem with one of my projects, I wrote a Julia package implementing its central solution methods. This undertaking was the first time I wrote a Julia package (the larger project itself the first time I really used Julia).
Since I had never written a package in Julia (or indeed in any other language), it was a learning experience — especially for the under-the-hood processes with which software engineers are undoubtedly familiar: wrangling workflows; git and version control; packages and dependencies; documenting and testing. While I learned a lot, I will focus only on the mechanics of starting and developing a Julia package here. (Maybe more to come on the other topics later!)
A package is functionally no different from any code project in the sense that it just runs code. Conceptually, packages tend to be centred around building and making available a core set of functionalities to use repeatedly — hopefully for yourself, your collaborators, or even strangers trying to solve similar problems. For this reason, code for a package should be written in Julia modules, exporting only the key functionalities for general use.
For brevity, I'll first list the basic steps to get a new package going, then discuss them in more detail.
- Open Julia, enter Pkg mode (by typing
]
). - Initiate your package, say "NewPackage", by typing
generate NewPackage
. Doing so will create a NewPackage folder in the current working directory. - Create a git repository at some online host like GitHub, probably called NewPackage.jl, and push the contents of the NewPackage folder.
- NewPackage can now be added to Julia's default environment — tell Julia about it by typing something like
add https://github.com/your_username/NewPackage.jl
in Pkg mode. Julia now knows to get NewPackage from the online git repository. - We probably want to make changes to NewPackage locally before publishing them online. In Pkg mode, type
dev NewPackage
. Julia will copy the package files for local development (usually somewhere like ~/.julia/dev/NewPackage), then tell the default environment to load NewPackage from this local version rather than the version hosted online. - We now have two local versions on the package: one we created with
generate
and one we created withdev
. At this point, the first serves no purpose (it isn't being watched by Julia, for example) so we can delete it. I personally created a symbolic link from this location to the local development copy, since the original location was more convenient for my file management purposes. - Now, we can make any changes we want to the local copy. To incorporate the changes, update the package by typing something like
up NewPackage
in Pkg mode, then restart Julia. When satisfied with changes, commit and push them so they can be available for everyone from the online hosted location.
The process above is a bit convoluted. For me, the multiple copies (created with generate
and dev
) were very confusing. I am not sure if there is a way to get the balling rolling in a more efficient way in Julia, or if it's standard with other languages to create multiple local copies of a project during the initiation process.
I'll close with a few final comments on the practicalities of package development.
Dependencies
Each time before working on the package, activate its environment by typingactivate .
in Pkg mode while in the package's directory. If done correctly, the Pkg prompt will switch to(NewPackage) pkg>
and track dependencies. For example, suppose the package relies on LinearAlgebra.jl. After activating the package's environment, typingadd LinearAlgebra
in Pkg mode means that Julia will automatically record that your package depends on LinearAlgebra. When others download your package, Julia will know to also download LinearAlgebra.Prototyping
I like using Pluto.jl to prototype small snippets of changes before directly editing the package contents. Its reactivity is a real convenience for quickly seeing whether ideas will work.Revise.jl
A package recommended by essentially everyone, it allows real-time updates to local packages rather than having to open a fresh Julia session to see changes reflected.Testing
Nearly every serious package has run tests to check its functionality. To test a package, write a "NewPackage/test/runtests.jl" file (creating the test directory if necessary). Then, you can ask Julia to run the runtests.jl file by typingtest NewPackage
in Pkg mode.