# How can an user load a package extension?

**URL:** <https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323>\
**Category:** General Usage\
**Tags:** package, plotting, package-extensions\
**Created:** [July 22, 2024, 5:52am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323 "2024-07-22T05:52:43Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![K5Julien](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/k5julien/32/210626_2.png) [@K5Julien](https://discourse.julialang.org/u/K5Julien)\
**Post date:** [July 22, 2024, 5:52am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/1 "2024-07-22T05:52:43Z")

</div>

I have read [Julia’s documentation about package extensions](https://docs.julialang.org/en/v1/manual/code-loading/#man-extensions) as well as this [GitHub example](https://github.com/pebeto/julia_extensions_example) and though I first thought it was suitable for my use case, it seems it isn’t.

I have in my package a mutable struct [SolveParameters](https://github.com/jkhamphousone/RingStarProblems.jl/blob/main/src/options.jl) that is used by the user so he can declare what he wants to do.

i.e., he could run the following in the REPL:

```julia
julia> import RingStarProblems as RSP
julia> using JuMP
julia> pars = RSP.SolverParameters(
        solve_mod = RSP.BranchBendersCut(), # ILP or B&BC
[...] Some other parameters
        do_plot = false, # plot_results (to debug)
[...] Some other parameters
       )

```

When using the paramter `do_plot = false`, everything is fine. However, I would like that the user could run `do_plot = true` and only when he does so:

```julia
module PlottingSol #
    if pars.do_plot
        using RingStarProblems, GraphPlots, Compose
    
       # Do some plotting and saving to .pdf
    end
end ### /!\ this generates errors as you can't have `using` inside a function!

```

I tried to put the module `PlottingSol` into an extension as mentioned in Julia documentation, i.e., my Project.toml contains, among other dependencies removed for brevity:

```julia
[weakdeps]
Compose = "a81c6b42-2e10-5240-aca2-a61377ecd94b"
GraphPlot = "a2cc645c-3eea-5389-862e-a155d0052231"

[extensions]
PlottingSol = ["Compose", "GraphPlot"]

[compat]
Compose = "0.8, 0.9"
GraphPlot = "0.4.1, 0.5, 0.6"

[test] # For testing
Compose = "a81c6b42-2e10-5240-aca2-a61377ecd94b"
GraphPlot = "a2cc645c-3eea-5389-862e-a155d0052231"

```

However, at this point, I do not understand how the user is supposed to ask for package PlottingSol with `do_plot = true`.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 22, 2024, 6:01am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/2 "2024-07-22T06:01:50Z")

</div>

Package extension should add methods to existing functions. So you should do something like:  
In the main part of `RingStarProblems`:

```julia
....
function perform_plot end # create function but do not add methods

function solve(...)
    # ...
    if do_plot
        # will error if no methods are defined
        perform_plot(...)
    end
end

```

In the extension `PlottingSol` (I think `PlottingExt` or `PlottingSolutionExt` would be slightly more preferred as name) you define a method:

```julia
module PlottingSol
using RingStarProblems, GraphPlots, Compose

function RingStarProblems.perform_plot(...)
    # do the plotting here
end

```

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [July 22, 2024, 7:06am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/3 "2024-07-22T07:06:03Z")

</div>

But this answer does not explain when an extension is loaded and when not.

---

<div class="post-metadata">

**Author:** ![K5Julien](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/k5julien/32/210626_2.png) [@K5Julien](https://discourse.julialang.org/u/K5Julien)\
**Post date:** [July 22, 2024, 7:10am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/4 "2024-07-22T07:10:03Z")

</div>

Indeed! Thank you @abraemer, I coded what you suggested and now have the error:

```julia
ERROR: MethodError: no method matching perform_plot(::SolverParameters, ::RingStarProblems.RRSPInstance, ::Symbol, ::RingStarProblems.BDtable, ::Bool)
Stacktrace:
 [1] main(pars::SolverParameters, instdataname::Tuple{Symbol, Tuple{String, Int64}}, optimizer::MathOptInterface.OptimizerWithAttributes, solutionchecker::Bool)
   @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:126
 [2] rspoptimize(pars::SolverParameters, symbolinstance::Symbol, optimizer::MathOptInterface.OptimizerWithAttributes, solutionchecker::Bool)
   @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:36
 [3] rspoptimize(pars::SolverParameters, symbolinstance::Symbol, optimizer::MathOptInterface.OptimizerWithAttributes)
   @ RingStarProblems ~/Documents/Travail/Julia/RingStarProblems.jl/src/main.jl:18
 [4] top-level scope

```

Maybe because I do not know when to load the extension, as mentioned by @ufechner7?

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [July 22, 2024, 7:11am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/5 "2024-07-22T07:11:34Z")

</div>

For extensions usually the point is that the user should be the one to do `using PlottingSol`. I would take @abraemer’s solution and just throw an error telling the user to do `using`. You can’t do `using` in non-top level statements (unless there’s some way to safely hack it using `@eval` I guess…).

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 22, 2024, 7:20am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/6 "2024-07-22T07:20:26Z")

</div>

> [@K5Julien](#):
>
> Maybe because I do not know when to load the extension, as mentioned by @ufechner7?

Sorry I thought that this is rather clear in the documentation you linked. First sentence

> A package “extension” is a module that is automatically loaded when a specified set of other packages (its “extension dependencies”) are loaded in the current Julia session.

So you never load a package extension manually. Package extensions are loaded automagically if the user adds the corresponding packages to the environment. So in your case, the extension is loaded if and only if the user added both Compose.jl and GraphPlot.jl to the environment either as a direct dependency (i.e. using `Pkg.add`) or indirectly by `Pkg.add`ing packages that depend on Compose.jl and GraphPlot.jl. Note that the users also needs to load the load these other packages themselves in the current session to make the extension available.

Your usecase seems to not reflect this. So a package extension in the Julian sense is probably not what you want. It sounds more like you should just make a second, full package, e.g. RingStarProblemsPlotting.jl, that includes the functionality.

---

<div class="post-metadata">

**Author:** ![K5Julien](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/k5julien/32/210626_2.png) [@K5Julien](https://discourse.julialang.org/u/K5Julien)\
**Post date:** [July 22, 2024, 7:21am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/7 "2024-07-22T07:21:48Z")

</div>

Thank you for your reply 🙂  
Do you mean `include("ext/PlottingExt.jl")` instead of `using PlottingExt`? Because the latter throws the error:

```julia
julia> using PlottingExt
ERROR: ArgumentError: Package PlottingExt not found in current path.
- Run `import Pkg; Pkg.add("PlottingExt")` to install the PlottingExt package.

```

I am sorry but how to use an extension is still unclear to me. I have carefully read the Julia’s documentation about it without succeeding to make it works for the moment.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [July 22, 2024, 7:26am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/8 "2024-07-22T07:26:07Z")

</div>

The extension will be automatically loaded when the user does `using Compose, GraphPlot` (I meant this instead of `using PlottingSol` in the previous reply). I would just throw an error telling the user to load in those two packages to have access to your package’s plotting functionality.

Or indeed if this is something you want to be automatically loaded when the user tries to plot, maybe an extension is not the way to go as @abraemer mentions.

---

<div class="post-metadata">

**Author:** ![K5Julien](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/k5julien/32/210626_2.png) [@K5Julien](https://discourse.julialang.org/u/K5Julien)\
**Post date:** [July 22, 2024, 8:05am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/9 "2024-07-22T08:05:06Z")

</div>

Alright, everything works perfectly now! Thank you for all your replies 😃

---

<div class="post-metadata">

**Author:** ![aris](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@aris](https://discourse.julialang.org/u/aris)\
**Post date:** [July 27, 2024, 9:46am UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/10 "2024-07-27T09:46:45Z")

</div>

I was playing around with an extension recently and I have some questions about this:

> [@abraemer](#):
>
> ```julia
> ....
> function perform_plot end # create function but do not add methods
> 
> function solve(...)
> # ...
> if do_plot
> # will error if no methods are defined
> perform_plot(...)
> end
> end
> 
> ```

For users of the package who are potentially unfamiliar with the nuances of julia, I was thinking the following;  
Instead of defining the “perform\_plot” functon without an argument, which would lead to some “method not matching” error when called, we could define

```julia
function perform_plot(::whatevertype)
    @warn("The function perform_plot is not available unless you load the x package by typing 'using x' " )
end

```

to make it more user-friendly.

Would that be sensible, or am I getting something wrong?  
I was planning to go down some metaprogramming rabbit hole, defining all possible extension functions will all their potential argument combinations using some eval loops, but it sound like a very cheesy solution.  
Is there a more elegant way to achieve the same perhaps?

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 27, 2024, 1:03pm UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/11 "2024-07-27T13:03:13Z")

</div>

> [@aris](#):
>
> I was planning to go down some metaprogramming rabbit hole, defining all possible extension functions will all their potential argument combinations using some eval loops, but it sound like a very cheesy solution.

This does not sound like a good solution to me. I have two ideas how to improve the `MethodError`.

1. You can check whether an extension is available with `Base.get_extension(parent::Module, extension::Symbol)`. So you could simply do a check before trying to call `perform_plot` and error appropriately. This check could perhaps be made more convenient with a macro e.g. `@with_extension PlottingExt perform_plot(...)`
2. There is `Base.Experimental.register_error_hint` which allows you tack an additional message onto the `MethodError` that occurs.

Edit: I am not sure whether one could simply define a method in the main module that warns and then _overwrite_ that method in the extension. This could potentially lead to recompilation/break precompilation or just not work at all. I am not sure.

---

<div class="post-metadata">

**Author:** ![aris](https://avatars.discourse-cdn.com/v4/letter/a/258eb7/32.png) [@aris](https://discourse.julialang.org/u/aris)\
**Post date:** [July 27, 2024, 1:27pm UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/12 "2024-07-27T13:27:17Z")

</div>

Thanks a lot for the suggestions!

I think I prefer 1. , since 2. would still result in the code crashing, which is not good if there’s anything after calling the empty function.  
Just to clarify, do we have any documentation on the functions/macro you recommend? I would like do a bit of homework before throwing these into my package.

> [@abraemer](#):
>
> I am not sure whether one could simply define a method in the main module that warns and then _overwrite_ that method in the extension.

It seems to work okay for some toy examples I was messing around with. But perhaps things could go wrong in more complicated cases.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [July 27, 2024, 1:35pm UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/13 "2024-07-27T13:35:40Z")

</div>

> [@aris](#):
>
> Just to clarify, do we have any documentation on the functions/macro you recommend?

`Base.get_extension` is documented. The macro was a suggestion from my side to make it more convenient if you have a lot of places where you would write something like:

```julia-auto
if isnothing(Base.get_extension(@ __MODULE__ , :Extension))
    @error "To use myfunction you need to ensure that the extension Extension is loaded"
end
myfunction(..)

```

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [July 27, 2024, 4:57pm UTC](https://discourse.julialang.org/t/how-can-an-user-load-a-package-extension/117323/14 "2024-07-27T16:57:48Z")

</div>

That depends a bit, how 2 errors. you could do soomething like

```julia
if isdefined(Base.Experimental, :register_error_hint)
        Base.Experimental.register_error_hint(MethodError) do io, exc, argtypes, kwargs
            if exc.f === convex_bundle_method_subsolver
                print(
                    io,
                    "\nThe `convex_bundle_method_subsolver` has to be implemented. A default is available currently when loading QuadraticModels.jl and RipQP.jl. That is\n",
                )
                printstyled(io, "`using QuadraticModels, RipQP`"; color=:cyan)
            end
    end
end

```

(I might be biased, it is from my own package, see [here](https://github.com/JuliaManifolds/Manopt.jl/blob/21dd64608d8a1853fcf37835a0942ca67c88b1ef/src/Manopt.jl#L228-L245))

Then it does crash but clearly reports what to load. For me the advantage is, that a MethodError is thrown, which itself also provides alternatives available (compared to a error you throw yourself) – but the message you see above also tells about what to load to get a working variant.
