In the package Geant4 I have a couple of extension modules (G4Vis and G4Hist). To trigger the loading of G4Vis I need to explicitly load a list of weakdeps packages (Makie, Colors, StaticArrays, Rotations, LinearAlgebra, IGLWrap_jll). This is not very user friendly since people need to explicitly add a using statement with this long list of modules.
I tried to define a function in the module Geant4 like this:
function enableG4Vis()
for pkg in (:Makie, :Colors, :StaticArrays, :Rotations, :LinearAlgebra, :IGLWrap_jll)
@eval using $(pkg)
end
end
However it does not work since these packages are not direct dependencies of Geant4. Is there a way to achieve this hiding of the long list of weakdeps modules?
This is the error I get:
julia> enableG4Vis()
ERROR: ArgumentError: Package Geant4 does not have Makie in its dependencies:
- Note that the following manifests in the load path were resolved with a different
julia version, which may be the cause of the error. Try to re-resolve them in the
current version, or consider deleting them if that fails:
/Users/mato/.julia/environments/v1.11/Manifest.toml (v1.11.0-rc1)
- You may have a partially installed environment. Try `Pkg.instantiate()`
to ensure all packages in the environment are installed.
- Or, if you have Geant4 checked out for development and have
added Makie as a dependency but haven't updated your primary
environment's manifest file, try `Pkg.resolve()`.
- Otherwise you may need to report an issue with Geant4
Stacktrace:
[1] macro expansion
@ ./loading.jl:2158 [inlined]
[2] macro expansion
@ ./lock.jl:273 [inlined]
[3] __require(into::Module, mod::Symbol)
@ Base ./loading.jl:2130
[4] #invoke_in_world#3
@ ./essentials.jl:1088 [inlined]
[5] invoke_in_world
@ ./essentials.jl:1085 [inlined]
[6] require(into::Module, mod::Symbol)
@ Base ./loading.jl:2123
[7] eval
@ ./boot.jl:430 [inlined]
[8] enableG4Vis()
@ Geant4 ~/Development/Geant4.jl/src/Geant4.jl:49
[9] top-level scope
@ REPL[2]:1
I guess the question is in which environment users are expected to execute that function, that environment needs to include all those packages, which is not the case if they only ever appear as weak deps. As a user, I’d be quite upset if some function tries to load code into my Main namespace.
I think there are two alternative options: reduce the number of weak dependencies: Makie for example already contains Colors and StaticArrays, you could piggy back on that by using Makie.Colors and so on inside your extension. However, those are internal objects to Makie so it might not be advised.
The best option might be to create Geant4Viz as a separate package rather than an extension with explicit deps. Then, users who want to use the visualization features can add/using Geant4Viz explicitly to get all those additional packages installed into their environment.
Besides, while skimming your code, I’ve noticed this part:
This is severe type piracy and should be avoided at all costs. Especially since broadcasted operators like .* seem to cover some of those definitions already.
Thanks for the suggestion to use a separate package. I’ll do it.
Concerning the type piracy, I agree this was a shortcut I took to avoid to define my own Vector3 type. I think is easy to correct.
Note that const Vector3 = SVector{3} was likely sufficient to accomplish this already (except for your definition of *(::Vector3, ::Vector3) which was already covered by .* and unitize which already exists as LinearAlgebra.normalize, although defining your own new unitize function like you did is not piracy and is fine). You didn’t define a new type Vector3, you simply made Vector3 an alias to SVector{3}. Anywhere you could have written SVector{3} you can now interchangeably write Vector3. This is basically the same relationship that const Vector{T} = Array{T,1} has.
julia> const Vector3 = SVector{3}
SVector{3} (alias for SArray{Tuple{3}, T, 1, 3} where T)
julia> Vector3{Float64} # still an `SVector{3}`
SVector{3, Float64} (alias for SArray{Tuple{3}, Float64, 1, 3})
So, for example, your Base.:*(x::Vector3, n::Number) definition does not define a function on Vector3 but rather pirates the SVector{3} definition (which already existed and did what you want).
If you want a distinct new type, consider wrapping a SVector in another struct or define your own StaticArrays.FieldVector subtype.