# How to trigger loading an extension module programatically?

**URL:** <https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485>\
**Category:** General Usage\
**Tags:** question\
**Created:** [September 17, 2024, 9:20am UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485 "2024-09-17T09:20:28Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [September 17, 2024, 9:20am UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485/1 "2024-09-17T09:20:28Z")

</div>

In the package [Geant4](https://github.com/JuliaHEP/Geant4.jl) 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:

```julia
    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
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

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 17, 2024, 9:42am UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485/2 "2024-09-17T09:42:41Z")

</div>

Use another, wrapper, package.

---

<div class="post-metadata">

**Author:** ![hexaeder](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hexaeder/32/24403_2.png) [@hexaeder](https://discourse.julialang.org/u/hexaeder)\
**Post date:** [September 17, 2024, 9:43am UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485/3 "2024-09-17T09:43:08Z")

</div>

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:

> <https://github.com/JuliaHEP/Geant4.jl/blob/c792a50981f59b921f20d11cc58055c597c5b47d/ext/G4Vis/Transformation3D.jl#L4-L14>

This is severe [type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy) and should be avoided at all costs. Especially since broadcasted operators like `.*` seem to cover some of those definitions already.

---

<div class="post-metadata">

**Author:** ![peremato](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peremato/32/29128_2.png) [@peremato](https://discourse.julialang.org/u/peremato)\
**Post date:** [September 17, 2024, 11:06am UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485/4 "2024-09-17T11:06:49Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [September 17, 2024, 2:23pm UTC](https://discourse.julialang.org/t/how-to-trigger-loading-an-extension-module-programatically/119485/5 "2024-09-17T14:23:33Z")

</div>

> [@peremato](#):
>
> this was a shortcut I took to avoid to define my own Vector3 type

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-repl
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.
