How do I reload a module in an active Julia session after an edit?

Solution 1:

The basis of this problem is the confluence of reloading a module, but not being able to redefine a thing in the module Main (see the documentation here) -- that is at least until the new function workspace() was made available on July 13 2014. Recent versions of the 0.3 pre-release should have it.

Before workspace()

Consider the following simplistic module

module TstMod
export f

function f()
   return 1
end

end

Then use it....

julia> using TstMod

julia> f()
1

If the function f() is changed to return 2 and the module is reloaded, f is in fact updated. But not redefined in module Main.

julia> reload("TstMod")
Warning: replacing module TstMod

julia> TstMod.f()
2

julia> f()
1

The following warnings make the problem clear

julia> using TstMod
Warning: using TstMod.f in module Main conflicts with an existing identifier.

julia> using TstMod.f
Warning: ignoring conflicting import of TstMod.f into Main

Using workspace()

However, the new function workspace() clears Main preparing it for reloading TstMod

julia> workspace()

julia> reload("TstMod")

julia> using TstMod

julia> f()
2

Also, the previous Main is stored as LastMain

julia> whos()
Base                          Module
Core                          Module
LastMain                      Module
Main                          Module
TstMod                        Module
ans                           Nothing

julia> LastMain.f()
1

Solution 2:

Use the package Revise, e.g.

Pkg.add("Revise") # do this only once

include("src/my_module.jl")
using Revise
import my_module

You may need to start this in a new REPL session. Notice the use of import instead of using, because using does not redefine the function in the Main module (as explained by @Maciek Leks and @waTeim).

Other solutions: Two advantages of Revise.jl compared to workspace() are that (1) it is much faster, and (2) it is future-proof, as workspace() was deprecated in 0.7, as discussed in this GitHub issue:

julia> VERSION
v"0.7.0-DEV.3089"

julia> workspace()
ERROR: UndefVarError: workspace not defined

and a GitHub contributor recommended Revise.jl:

Should we add some mesage like "workspace is deprecated, check out Revise.jl instead"?

Even in Julia 0.6.3, the three previous solutions of workspace(), import, and reload fail when a module called other modules, such as DataFrames. With all three methods, I got the same error when I called that module the second time in the same REPL:

ERROR: LoadError: MethodError: all(::DataFrames.##58#59, ::Array{Any,1}) is ambiguous. Candidates: ...

I also got many warning messages such as:

WARNING: Method definition macroexpand(Module, ANY) in module Compat at /Users/mmorin/.julia/v0.6/Compat/src/Compat.jl:87 overwritten in module Compat at /Users/mmorin/.julia/v0.6/Compat/src/Compat.jl:87.

Restarting the Julia session worked, but it was cumbersome. I found this issue in the Reexport package, with a similar error message:

MethodError: all(::Reexport.##2#6, ::Array{Any,1}) is ambiguous.

and followed the suggestion of one contributor:

Does this happen without using workspace()? That function is notorious for interacting poorly with packages, which is partly why it was deprecated in 0.7.

Solution 3:

In my humble opinion, the better way is to use import from the very beginning instead of using for the reported issue.

Consider the module:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v1.0") 
  end
  println("v1.0 loaded")
end

Then in REPL:

julia> import ModuleX1
v1.0 loaded

julia> ModuleX1.produce_text()
v1.0

Update the code of the module and save it:

module ModuleX1
  export produce_text
  produce_text() = begin
    println("v2.0")  
  end
  println("v2.0 loaded")
end

Next, in the REPL:

julia> reload("ModuleX1")
Warning: replacing module ModuleX1
v2.0 loaded

julia> ModuleX1.produce_text()
v2.0

Advantages of using import over using:

  • avoiding ambiguity in function calls (What to call: ModuleX1.produce_text() or produce_text() after reloading?)
  • do not have to call workspace() in order to get rid of ambiguity

Disadvantages of using import over using:

  • a fully qualified name in every call for every exported name is needed

Edited: Discarded "full access to the module, even to the not-exported names" from "Disadvantages..." according to the conversation below.