NOTE: this page is for Julia 0.7-DEV and higher. For Julia 0.6 see this branch
Revise.jl may help you keep your sessions running longer, reducing the
need to restart Julia whenever you make changes to code.
With Revise, you can be in the middle of a session and then issue a Pkg.update()
and/or edit the source code; typically, the changes will be incorporated
into the very next command you issue from the REPL.
This can save you the overhead of restarting, loading packages, and waiting for code to JIT-compile.
julia> Pkg.add("Example")
INFO: Installing Example v0.4.1
INFO: Package database updated
julia> using Revise # importantly, this must come before `using Example`
julia> using Example
julia> hello("world")
"Hello, world"
julia> Example.f()
ERROR: UndefVarError: f not defined
julia> edit("Example.jl") # add a function `f() = π` and save the file
julia> Example.f()
π = 3.1415926535897...It's even possible to use Revise on code in Julia's Base module: just say Revise.track(Base).
Any changes that you've made since you last built Julia will be automatically incorporated.
By default, Revise processes any modified source files every time you enter
a command at the REPL.
However, there might be times where you'd prefer to exert manual control over
the timing of revisions. Revise looks for an environment variable
JULIA_REVISE, and if it is set to anything other than "auto" it
will require that you manually call revise() to update code.
For example, on Linux you can start your Julia session as
$ JULIA_REVISE=manual juliaand then revisions will be processed only when you call revise().
If you prefer this mode of operation, you can add that variable to your bash
environment or add ENV["JULIA_REVISE"] = "manual" to your
.juliarc.jl before you say using Revise (see below).
If you like Revise, you can ensure that every Julia session uses it by
adding the following to your .juliarc.jl file:
@schedule begin
sleep(0.1)
@eval using Revise
endThis should work the REPL, Juno, and IJulia. For VSCode see these instructions.
Revise is based on the fact that you can change functions even when they are defined in other modules. Here's an example showing how you do that manually (without using Revise):
julia> convert(Float64, π)
3.141592653589793
julia> # That's too hard, let's make life easier for students
julia> @eval Base convert(::Type{Float64}, x::Irrational{:π}) = 3.0
convert (generic function with 714 methods)
julia> convert(Float64, π)
3.0Revise removes some of the tedium of manually copying and pasting code
into @eval statements.
To decrease the amount of re-JITting
required, Revise avoids reloading entire modules; instead, it takes care
to eval only the changes in your package(s), much as you would if you were
doing it manually.
To accomplish this, Revise uses the following overall strategy:
- add a callback to Base so that Revise gets notified when new
packages are loaded or new files
included - prepare source-code caches for every new file. These caches
will allow Revise to detect changes when files are updated. For precompiled
packages this happens on an as-needed basis, using the cached
source in the
*.jifile. For non-precompiled packages, Revise parses the source for eachincluded file immediately so that the "starting point" is known before you start saving changes. - monitor the file system for changes to any of the dependent files; it immediately appends any updates to a list of file names that need future processing
- intercept the REPL's backend to ensure that the list of files-to-be-revised gets processed each time you execute a new command at the REPL
- when a revision is triggered, the source file(s) are re-parsed, and
a diff between the cached version and the new version is
created.
evalthe diff in the appropriate module(s). - replace the cached version of each source file with the new version, so that
further changes are
diffed against the most recent update.
Revise only tracks files that have been required as a consequence of
a using or import statement; files loaded by include are not
tracked, unless you explicitly use Revise.track(filename).
There are some kinds of changes that Revise cannot incorporate into a running Julia session:
- changes to type definitions
- function or method deletions
- file or module renames
- changes to macros that affect method definitions, or to functions that affect generated
function expansion. To work around this issue, you may explicitly call
revise(module)to force reevaluating every definition inmodule.
These kinds of changes require that you restart your Julia session.
Revise became possible because of Jameson Nash's fix of Julia issue 265.