I recently started thinking about conditional modules, while working on making sure Requires.jl
works on 0.6 and I thought it would be helpful to recap discussions I had with @jameson and @tkelman. This follows in similar veins to https://github.com/JuliaLang/julia/issues/6195 and https://github.com/JuliaLang/julia/issues/15705#issuecomment-254264419
Status quo: Requires.jl
In Requires.jl
you can defer the loading of a piece of code with the @require
macro.
using Requires
@require DataFrames begin
println("DataFrames loaded")
end
println("Before using")
using DataFrames
println("After using")
In order to provide this feature (which is quite heavily used to provide some notion of optional dependencies), Requires.jl
currently has to overwrite Base.require
which is frowned upon and requires jumping through some major hoops in order to call the original version of Base.require
that does all the heavy lifting. The dynamic nature of this also makes it impossible to precompile these codeblocks.
First alternative approach: Keeping it dynamic
The minimal change to Requires.jl
would be to extend Base.require
to notify through a callback that a module was finished loading. I experimented with this a little bit in https://github.com/JuliaLang/julia/tree/vc/loading_callbacks and https://github.com/vchuravy/Requires.jl/tree/vc/patchedbase, but this still runs into the problem that it is not precompile friendly and so if an optional dependency is later installed we won’t invalidate the cache file.
Second alternative approach: Static and precompile friendly
The second approach that is a lot more involved in terms of required base changes is to change Requires.jl
dynamic delayed loading to a more straight-forward, check if module is loadable, if yes compile code, if not don’t compile code, but record that dependency and invalidate the cache if that dependency gets installed.
@require mod expr
will evaluate to something akin to:
if Base.find_in_node($(String(mod)), nothing, 1) !== nothing
return expr
else
return quote
register_optional_dependency(mod)
end
end
The big question mark for this approach is register_optional_dependency
. I started experimenting a little bit in that direction, but currently that code crashes and burns when precompiling.
- https://github.com/vchuravy/julia/tree/vc/better_requires
- https://github.com/vchuravy/Requires.jl/tree/vc/static
mostly because I tried to use uuid == 0
to mean optional in the cache file module list.
I would be keen on hearing thoughts from others.