Tips for the Julia startup.jl file
I have lately spent some time switching between an editor, paper and the Julia REPL, which made me realize how much more pleasant I have made this workflow for myself by stuff I have in the startup file.
What is the
startup.jlfile?!
For those who are not accustomed with the concept of the startup file in Julia, briefly, it is a script that is run once you enter the REPL. It is stored at$JULIA_DEPOT_PATH/config/startup.jlor if theJULIA_DEPOT_PATHenvironment variable is not set, the default on GNU/UNIX is$HOME/.julia/. Here you can find more about thestartup.jlfile.
Some of the changes that I made may be useful to you as well!
Loading Packages for Interactive Use Only
Most people use it for loading packages that they use often enough that they value of having the package functionality available at startup is higher than the price of the REPL startuptime. The library packages that meet this criterium for me are BenchmarkTools and Makie. It is always a good idea when loading packages for interactive use to include them conditionally only when the session is interactive with
try
if isinteractive()
using Makie
end
catch e
@warn "Error initializing Makie" exception = (e, catch_backtrace())
endThe
try/catchcontrol sequence is here, since I switch between different versions of Julia and I do not always make sure that everything is installed.
This way you are only paying the expense when you actually need it and not when running scripts or generating documentation for example.
Other Useful Packages
Non-library packages that may improve your experience with the Julia REPL when using it interactively which I also are important to me are these…
Revise- It has become more of a must have in the community and is also recommended by the official Julia documentation. It manges the changes that you make in your loaded packages and allows the REPL environment to reflect changes that you make in real time.
OhMyRepl- Features include syntax highlighting in your REPL, markdown syntax for documentation and fuzzy searching with
fzfof the REPL history. VimBindings- Enables editing the command line with modal Vim bindings.
Additional Functions
It is also useful to define some functions that you can use for exploration and debugging purposes. For example, I have a subtypetree function which allows me to see all of the subtypes of a particular abstract type to decide on what interfaces I should use for my own implementations.
julia> subtypetree(Integer)
Integer
Bool
GeometryBasics.OffsetInteger
Signed
BigInt
Int128
Int16
Int32
Int64
Int8
Unsigned
UInt128
UInt16
UInt32
UInt64
UInt8Definition of subtypetree
function subtypetree(roottype, level=1, indent=2)
level == 1 && println(roottype)
for s in subtypes(roottype)
println(join(fill(" ", level * indent)) * string(s))
subtypetree(s, level + 1, indent)
end
endChange the Pages for @less
What is this
@lessthat you are talking about?
If you do not use@lessand@edit, you should definitely check them out! These are tools that allow you to inspect the source code of functions implemented in some package (or defined earlier within the REPL). Usually when I have the editor and the REPL open and any of my calls to library functions have unexpected outputs, I would like to inspect what is happening in its implementation. You could surely useGoToImplementionfrom the language server if you are within the editor context, but I find@lessand@editto be useful in the REPL as well. Most importantly, I use this when I want to look up how some function is implemented in the JuliaBaseor in some external package, because I want to implement something similar myself.
Also you might want to integrate some tools that you use on your system and use them instead of the defaults. One nice enhancement that I have in this category is using bat instead of less as the pager for in the InteractiveUtils.less function. You can achieve this by including the code
try
if isinteractive()
using InteractiveUtils
function InteractiveUtils.less(file::AbstractString, line::Integer)
run(`bat --paging=always --line-range $(line): $file`)
nothing
end
end
catch e
@warn "Error initializing InteractiveUtils" exception = (e, catch_backtrace())
endin your startup.jl file. This allows me to switch context between reading code that is run and running the code while staying in the REPL using @less instead of @edit which opens the code in the terminal. It gives you syntax highlighting of the output Julia source of the function that you are inspecting.
Imagine that you want to see how the split function is implemented from Base. Perhaps you want to see if there is an iterator with the same behaviour and suspect that it would be present in the implementation. For this reason, you call
julia> @less split("a,b", ",")From the default InteractiveUtils.less definition that uses the less (or the $PAGER environment variable) command to page the output you can expect something similar to this:
function split(str::T, splitter;
limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString}
collect(eachsplit(str, splitter; limit, keepempty))
end
# a bit oddball, but standard behavior in Perl, Ruby & Python:
It has the correct output but it is not very pleasant to read. You can imagine that you are analysing the implementation of a larger function… This would be quite a pain.
If you change the InterativeUtils.less function definition to use bat as described above, you can expect something like this:
File: /home/kunzaatko/.julia/juliaup/julia-1.12.3+0.x64.linux.gnu/share/julia/base/strings/util.jl
function split(str::T, splitter;
limit::Integer=0, keepempty::Bool=true) where {T<:AbstractString}
collect(eachsplit(str, splitter; limit, keepempty))
end
# a bit oddball, but standard behavior in Perl, Ruby & Python:
which is way nicer to read…
I hope you enjoyed this non-exhaustive view into the contents of my startup.jl and that you perhaps found something useful for your own that could make the beautiful experience of writing Julia code a little less frustrating…