[ANN] Higher productivity (fewer Julia restarts) with Revise.jl



I’m announcing a new package that may speed up your development: https://github.com/timholy/Revise.jl. Revise makes it easier to update code and have the changes take effect immediately, without having to restart Julia. Please see the README for more information.

How do you develop a package without having to commit, push and pull all your changes all the time
__precompile__() is not resulting in precompiled code
Julia development workflow
Module with include
1.0 progress/status
Deployment questions: AOT and Portability

This package revolutionized my workflow in a few days. Thanks!


Glad to hear it! I find that old habits die hard—I still sometimes restart Julia unnecessarily—but it’s been very good for my workflow too.

Thanks to good feedback from users, v0.0.3 has been released with better support for vim, IJulia, and a broader collection of Julia packages. If it doesn’t work for your use-cases, please continue to report issues.


Suggestion for even smoother workflow if you are working with Juno:
Besides working with Revise or CloberringReload(if you are on 0.5), set Juno to cycler mode
this way it makes a Julia instance ready in the background.

Moreover add a .junorc.jl in your home folder and have it import any commonly used packages.
This saves additional few seconds of start-up time

I also added an asynchronous task with many yields , that does a “workout” for commonly used functions
that are slow the first time… many yields because I want it to be responsive even if it didn’t finish its workout.

This way when I do restart Julia , it starts in a nice warm and nimble state.


To break my habit I wanted ctrl-d to ask Exit? [Y/n] before exiting. I came up with this .juliarc.jl bit but it hangs at the readline. Anyone know how to do this?

    ctrl_d_ask = Dict{Any,Any}(
        "^D" =>
        function (s,o...)
            if Base.LineEdit.buffer(s).size > 0
                println("Exit? [Y/n]")
                answer = readline(STDIN)
                if answer=="" || lowercase(answer)=="y"
                    return :abort
                    return nothing
    function customize_keys(repl)
        repl.interface = Base.REPL.setup_interface(repl; extra_repl_keymap = ctrl_d_ask)


I really like the idea of this package, even though it currently only works for the first few file changes. I’m not really sure what is going on, need to test it some more.
EDIT: It seems to be working now. Yay.

Anyway, I’m kind of curious why you have to do:

@schedule begin
    @eval using Revise

in .juliarc.jl?


Do you mean, "as opposed to simply using Revise in .juliarc.jl"? The @schedule is needed because .juliarc.jl gets executed before the REPL code is fully initialized. Revise’s __init__ function alters an important component of the REPL code (shutting down one “service” and starting a modified one), so you have to do something to wait until the REPL code is initialized.


Thanks for this trick!! I have a function to change the prompt (to include the current branh-name, to no be lost when I have a handful of open prompts to compare e.g. performances for a PR), but never could find a way to call this function from my “.juliarrc.jl”. This is really neat, you solve one of my longstanding problems (although I believe there should eventually be a cleaner to achieve the same).


If you know for certain that you’re using the REPL, something like wait(Task(() -> while !isdefined(Base, :active_repl_backend) end)) might be even better than sleep(0.1). In Requires I want to make sure I support Juno/IJulia too, so there may never be a REPL. So I chose the more braindead solution.


Looks neat, but after playing a bit with it, I can’t make it work (I will need to read more about tasks to understand); it’s looks like the task is never run.


Even with @schedule I have to manually call revise().


That’s unexpected. Is there an error message? What happens if you increase the sleep time? Are you loading any other packages in your .juliarc.jl? If so, they won’t get tracked unless you make sure you load Revise first.


No error message. Here’s my current rc:

@schedule begin
    @eval using Revise



Maybe TeminalExtensions does its own messing with things, perhaps try commenting that one out.


It wasn’t TerminalExtensions, it was MiscGraphUtils which depended on LightGraphs (which was what I was revising). This seems to indicate that atreplinit happens BEFORE @schedule, right?

Also: if you remove a function from the source, it persists even after a revise() (this is not terribly surprising, I guess):

julia> LightGraphs.foo(g)

# remove foo from source, save.
julia> revise()

julia> LightGraphs.foo(g)


This seems to indicate that atreplinit happens BEFORE @schedule, right?

Well, technically the @schedule happens immediately, but then execution progresses. Meanwhile the Task’s first action is to sleep 0.1s; if that takes longer than REPL initialization, then Revise gets loaded after those other packages. If you never use IJulia/Juno, you could just add Revise to the atreplinit list.

if you remove a function from the source, it persists even after a revise

Yes, this is documented in the README.


If you never use IJulia/Juno, you could just add Revise to the atreplinit list.

I don’t, but it doesn’t work as I might expect:

  @eval using Revise

requires me to use revise() for LightGraphs (after a using LightGraphs typed into the REPL), and


doesn’t load Revise at all.


This is a lifesaver! How hard would it be to make it a part of standard Julia REPL?


I personally think it’s worth considering, but the scary thing would be that if it doesn’t work for everyone then it could handicap the REPL (which would be pretty catastrophic). If we want to make progress towards such a future, the most important thing is for anyone who experiences trouble with the package to please report bugs!

(Along these lines, OSX users please upgrade to the 0.0.4 release once the METADATA tag gets merged.)


Just found out about this… This will change my life ! Thank you @tim.holy for doing this.