# Accessing non-exported package extension functions

**URL:** <https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058>\
**Category:** General Usage\
**Tags:** package-extensions\
**Created:** [January 20, 2024, 10:39pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058 "2024-01-20T22:39:48Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Brad\_Carman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brad_carman/32/17631_2.png) [@Brad\_Carman](https://discourse.julialang.org/u/Brad_Carman)\
**Post date:** [January 20, 2024, 10:39pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/1 "2024-01-20T22:39:48Z")

</div>

If module `A` has an extension `B` with a function `b_fun()`, how can I call this function? I was assuming I could do:

```julia
using A
using A.B: b_fun

b_fun()

```

The namespacing for package extensions has me a little confused.

---

<div class="post-metadata">

**Author:** ![Brad\_Carman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brad_carman/32/17631_2.png) [@Brad\_Carman](https://discourse.julialang.org/u/Brad_Carman)\
**Post date:** [January 20, 2024, 10:42pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/2 "2024-01-20T22:42:47Z")

</div>

Ahh, I guess the answer is I need to do

```julia
ext = Base.get_extension(A, :B)
ext.b_fun()

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 20, 2024, 11:44pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/3 "2024-01-20T23:44:24Z")

</div>

Key takeaways:

- extensions are not submodules of their dependency packages
- extensions are intended to extend names in packages, not to be imported and expose new names. If you want that, make a new package with the same dependency packages.
- `get_extension` and assigning an extension’s properties to variables do not behave like imports and are not intended for routine use. Reflection and select testing seems fine.

---

<div class="post-metadata">

**Author:** ![Alec\_Loudenback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alec_loudenback/32/278_2.png) [@Alec\_Loudenback](https://discourse.julialang.org/u/Alec_Loudenback)\
**Post date:** [January 30, 2024, 4:17am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/4 "2024-01-30T04:17:04Z")

</div>

Is it that package extensions aren’t _intended to_ or _can’t_ export new names?

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [January 30, 2024, 4:28am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/5 "2024-01-30T04:28:42Z")

</div>

They can’t

---

<div class="post-metadata">

**Author:** ![Alec\_Loudenback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alec_loudenback/32/278_2.png) [@Alec\_Loudenback](https://discourse.julialang.org/u/Alec_Loudenback)\
**Post date:** [January 30, 2024, 4:32am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/6 "2024-01-30T04:32:52Z")

</div>

Thanks, a workaround I found was to do something like this where `A` is the base package and `B` is the extension:

```julia
module A
  newfunction() = error("This function is available
   after importing B and calling `newfunction` with 
  arguments x/y/z...")

export newfunction
end

```

And in `B`:

```julia
module B
using A
A.newfunction(x,y,z) = ...
end

```

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [January 30, 2024, 4:35am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/7 "2024-01-30T04:35:21Z")

</div>

That’s not a workaround, that’s exactly how package extensions are supposed to work 😉

---

<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:** [January 30, 2024, 7:21am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/8 "2024-01-30T07:21:45Z")

</div>

To extend Michaels answer – that is how packages are supposed to work – you could also leave the error-part to Julia itself (leading to a nicer `Method not found` error including suggestions in case you just misspelled it or missed a signature)

```julia
module A
    @doc """
    newfunction()

    This function is meant to provide functionality when both A and (package-from-extension) are loaded and then provides the functionality that... 
    """ 
    newfunction()

export newfunction
end

```

in my experience the error messages you get this way are more helpful.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 30, 2024, 7:49am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/9 "2024-01-30T07:49:35Z")

</div>

> [@kellertuer](#):
>
> `newfunction()`

Shouldn’t that rather be:

```julia-auto
function newfunction end

```

?

---

<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:** [January 30, 2024, 7:57am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/10 "2024-01-30T07:57:26Z")

</div>

I think both should work, but yours is indeed nicer.

I came to my solution, since usually I document a certain signature of a function.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 30, 2024, 3:00pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/11 "2024-01-30T15:00:11Z")

</div>

> [@Alec\_Loudenback](#):
>
> ```julia
> newfunction() = error("This function is available
> after importing B and calling `newfunction` with 
> arguments x/y/z...")
> 
> ```

I’d suggest not doing this. It’s not unusual for another package or extension to add methods to a public function originating in a package, but it’s not great for the original package alone to expose a public function that uses up the zero-argument method only to advise the user to import something else. Note that a call with more arguments will only throw a `MethodError`, so a user would have to guess at an atypical practice of interactively calling the listed zero-argument method for the advice. The name and implementation seem more appropriate in a separate package that depends on the packages that the extension depended on. The intention wasn’t irrational; it is cleaner to limit the number of importable packages when many methods depend on various mixes of packages, and extensions accomplish that smoothly in addition to loading them only when needed. But going too far can erode the principle of module independence (at the extreme, you merge everything into one package), and no feature can substitute careful module design.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [January 30, 2024, 7:08pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/12 "2024-01-30T19:08:22Z")

</div>

`newfunction(args...; kwargs...)` as a universal fallback might not be an absolute no-go, though. It all depends on the API of your package, how the error message gets displayed to the user, and whether you can come up with something more informative than a `MethodError` in the specific context of your package.

I’ve done something similar in my own package:

> <https://github.com/JuliaQuantumControl/QuantumPropagators.jl/blob/1946cd60f1a22a2e7f022f6ee32a14f7e681b3b6/src/propagator.jl#L259-L262>

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 31, 2024, 8:18pm UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/13 "2024-01-31T20:18:26Z")

</div>

The important difference there is your package does provide implementation in addition to the erroring fallback.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 20, 2024, 9:56am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/14 "2024-02-20T09:56:55Z")

</div>

I think it would make sense to document how extensions interact with namespacing and the practical implications (ie that they can’t export new symbols into their parent module, so different strategies are needed, as outlined in this thread).

I don’t see an open issue for this, I will wait for feedback before opening one though.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [February 20, 2024, 11:17am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/15 "2024-02-20T11:17:35Z")

</div>

The correct way to think about them is like they are a separate package that gets automatically `import`ed once all the “triggers” of it has been loaded and that you can get a handle to with `get_extension`.

So if you want you can do

```julia
BExt = Base.get_extension(A, :B)
using .BExt

```

if you want to get the exported things from the extension. But (just like with a separate package) it is not like its exported symbols will just appear somewhere else (like in the parent package)

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [February 20, 2024, 11:32am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/16 "2024-02-20T11:32:32Z")

</div>

> [@kristoffer.carlsson](#):
>
> So if you want you can do
> 
> ```julia
> BExt = Base.get_extension(A, :B)
> using .BExt
> 
> ```
> 
> if you want to get the exported things from the extension.

I was under the impression that this was discouraged because the extension name (`:B` in this example) was not meant to be part of the public API of the “extended” package (`A` in the example). Am I mistaken?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [February 20, 2024, 11:49am UTC](https://discourse.julialang.org/t/accessing-non-exported-package-extension-functions/109058/17 "2024-02-20T11:49:27Z")

</div>

> [@ffevotte](#):
>
> I was under the impression that this was discouraged because the extension name (`:B` in this example) was not meant to be part of the public API of the “extended” package (`A` in the example). Am I mistaken?

Yes, you are “allowed” do this from the same places as you are allowed to use the internals of `A`.
