No worries, these are all great questions and certainly ones which are best to have answered at the beginning of your Julia journey, it’s a wonderful paradigm that I think you will enjoy. And regarding your experience so far, I certainly agree that littering the code with display
is overly tedious, hopefully the information below can help you get to a smoother workflow.
It would help a lot if you could elaborate on your statement ‘and then iteratively test the functions as I build them out in the REPL’.
Of course. And before I get going, I’ll say that this discussion is as much about how your code is organized (as files and modules) as it is about the REPL itself; the REPL is the place where evaluation actually happens, and the variety of workflows people have usually fall out from that fact. In other words, despite the many different approaches you’ve already seen (and will inevitably see), you will find that they almost always boil down to some variation of “edit there, evaluate here” where “there” is a text editor of some sort and “here” is the REPL.
Say you have just added the line line y = exp(x)
on the following file, named simple.jl
module simple
x = 0
y = exp(x)
end
You have the REPL open. What do you do to check that y has been correctly assigned the value 1.0? One way to do that is to add the extra line display(y)
and then invoke include("simple.jl")
. This solution forces me to litter the code with all the ‘display’ statements.
Modules are a useful abstraction to aggregate related features under one umbrella, but what you likely want here is a function:
# simple.jl
function simple()
x = 0
y = exp(x)
end
Then, from the REPL, you can call the function simple
directly; the function is evaluated and its last expression is returned, in this case y = exp(x)
.
julia> include("simple.jl")
simple (generic function with 1 method)
julia> simple()
1.0
Let’s say you want to edit the function in the file, for example changing x = 5
:
# simple.jl
function simple()
x = 5
y = exp(x)
end
Once that is saved, include
the file again and the changes are applied:
julia> include("simple.jl")
simple (generic function with 1 method)
julia> simple()
148.4131591025766
From this you can build significant complexity while interactively checking the functions one by one, writing new functions which use your previously defined functions, etc. This is the essence of the REPL workflow.
Lastly, it can become tedious to call include
over and over again, and this is where the package Revise comes in. When you use Revise’s alternate function includet
instead of the built-in include
, the REPL actually determines which files have changed and automatically include
s them. Then, your workflow is to edit and save the functions, and the next time you run them the REPL uses your newest version, no loading necessary.