Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

module

julia

2018 Update: Be sure to check all the responses, as the answer to this question has changed multiple times over the years. At the time of this update, the Revise.jl answer is probably the best solution.

I have a file "/SomeAbsolutePath/ctbTestModule.jl", the contents of which are:

module ctbTestModule
export f1
f1(x) = x + 1
end

I fire up Julia in a terminal, which runs "~/.juliarc.jl". The startup code includes the line:

push!(LOAD_PATH, "/SomeAbsolutePath/")

Hence I can immediately type into the Julia console:

using ctbTestModule

to load my module. As expected f1(1) returns 2. Now I suddenly decide I want to edit f1. I open up "/SomeAbsolutePath/ctbTestModule.jl" in an editor, and change the contents to:

module ctbTestModule
export f1
f1(x) = x + 2
end

I now try to reload the module in my active Julia session. I try

using ctbTestModule

but f1(1) still returns 2. Next I try:

reload("ctbTestModule")

as suggested here, but f1(1) still returns 2. Finally, I try:

include("/SomeAbsolutePath/ctbTestModule.jl")

as suggested here, which is not ideal since I have to type out the full absolute path since the current directory might not be "/SomeAbsolutePath". I get the warning message Warning: replacing module ctbTestModule which sounds promising, but f1(1) still returns 2.

If I close the current Julia session, start a new one, and type in using ctbTestModule, I now get the desired behaviour, i.e. f1(1) returns 3. But obviously I want to do this without re-starting Julia.

So, what am I doing wrong?

Other details: Julia v0.2 on Ubuntu 14.04.

like image 472
Colin T Bowers Avatar asked Jul 30 '14 04:07

Colin T Bowers


2 Answers

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
like image 131
waTeim Avatar answered Nov 28 '22 17:11

waTeim


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.

like image 43
miguelmorin Avatar answered Nov 28 '22 18:11

miguelmorin