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
Requires.jl you can defer the loading of a piece of code with the
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.
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.