# Namespacing of methods

**URL:** <https://discourse.julialang.org/t/namespacing-of-methods/72677>\
**Category:** Internals & Design\
**Tags:** namespaces\
**Created:** [December 6, 2021, 8:14pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677 "2021-12-06T20:14:03Z")\
**Posts on this page:** 9\
**Page:** 1

<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:** [December 6, 2021, 8:14pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/1 "2021-12-06T20:14:03Z")

</div>

After a couple of months of using Julia, I’m still a little confused about how methods interact with packages/namespaces. That is, situations where a package adds additional methods to a function originally defined in another package.

If I have a package `A` that defines (and exports) `func` and another package `B` that defines additional methods for `func`, it seems like doing `using A` and `using B` in the REPL, I get the combined methods from `A` and `B`. This does not seem to depend on whether `B` also exports `func`. Is that officially how things are supposed to work: If I’m `using A`, do all methods for `func` defined in _other_ packages that I might use directly or indirectly get merged in automatically? With “indirect” I mean if I’m `using C` and the package `C` has a `uses B`, do I get the methods that `B` defines for `A.func` automatically?

Is there any way to use (parts of) `B` but not use the methods that `B` defines for `A.func`? One might expect that if I do `using A` and `using B: func2` (where `func2` is some unrelated function), I wouldn’t get `B`’s method for `A.func`, but in fact I do.

Second, while an explicit `export` of `func` in `B` doesn’t seem to affect whether `B`’s method for `A.func` gets used or not, it does seem to have some effect when I’m not _directly_ using the package `A` that originally defines `func`. If my package `B` looks like this:

```julia
module B
import A
A.func(i::Int) = i
end

```

and I’m only `using B` in the REPL but not `using A`, then neither `func` not `B.func` is available. However, if my package `B` reads

```julia
module B
import A: func
func(i::Int) = i
end

```

then `using B` (without `using A`) in the REPL does give me access to `B.func`, and `B.func` includes both the methods from `A` and from `B`.

If I further export `func`, that is,

```julia
module B
import A: func
export func
func(i::Int) = i
end

```

then `using B` in the REPL (again without `using A`), gives me access to both `func` and `B.func`, again using the methods from both `A` and `B`.

Also, in that case, if I’m both `using A` and `using B` explicitly in the REPL, I can address `func` as `func`, `A.func`, or `B.func`, with all three being completely equivalent.

Lastly, if I define the package `B` as

```julia
module B
import A
export func
A.func(i::Int) = i
end

```

I don’t get any complaints from Julia, but the REPL autocompletion thinks that both `func` and `B.func` exist, but then gives me an `UndefVarError: func not defined`.

This last one seems like a bug. As for all the previous examples, they all seem okay, but I can’t say that I have a good mental model for why exactly they behave the way they do. Is there one?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 6, 2021, 8:32pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/2 "2021-12-06T20:32:25Z")

</div>

Nice resume, all that seems perfectly correct (and helpful).

I think the way to think about these things is about namespaces.

`import A: func` brings `func` to the namespace where that was executed. If that namespace is `module B`, then `B.func` is available. If inside `module B` you add `export func` now, `func` is available where `using B` was executed.

`using A` will put then `func` into the current namespace if it is exported in `A` (the same thing as above). If that was executed inside `module B`, now `B.func` exists.

`import A` does not bring `A.func` into the namespace, thus if that was executed inside `module B`, there will be no `B.func`.

(I don’t think you can import or export one method but not the other, of the same function. That is one of the reasons type piracy is highly discouraged).

Concerning the “bug”: actually the problem there is that Julia does not complain of a module exporting something that is not defined (it can’t really do that, because the module is parsed sequentially, thus it cannot know if there will be a definition later). A linter could possibly do that. But here the REPL does not seem to try to autocomplete, while `B.<tab>` does (with a stranger name that does not overlap with any other function that is clearer):

```julia
julia> module B
           export foobar
       end
Main.B

julia> foo # tab (nothing appears)

julia> B.foobar # does autocomplete
ERROR: UndefVarError: foobar not defined
Stacktrace:
 [1] getproperty(x::Module, f::Symbol)
   @ Base ./Base.jl:35
 [2] top-level scope
   @ REPL[2]:1

```

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [December 6, 2021, 8:52pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/3 "2021-12-06T20:52:36Z")

</div>

I started this post before @lmiq completed his post, so sorry for any overlap.

* * *

> [@goerz](#):
>
> This last one seems like a bug.

There’s an error because you’re `export`ing a function that doesn’t exist (`A.func` exists, but not `func`). So I would say that’s an error on the package developer’s part, not on Julia’s part.

> [@lmiq](#):
>
> `import A` does not bring `A.func` into the namespace, thus if that was executed inside `module B` , there will be no `B.func` .

But there will be `B.A` (and `B.A.func` by extension) because `import A` brings `A` into the namespace.

> [@lmiq](#):
>
> I don’t think you can import or export one method but not the other, of the same function.

The way I think about it is that functions (and other global objects) belong to modules, while methods belong to functions. So adding a method to an existing function will not create a new function but will add to the function’s method table. So even in this setting:

> [@goerz](#):
>
> If I’m `using A` , do all methods for `func` defined in _other_ packages that I might use directly or indirectly get merged in automatically? With “indirect” I mean if I’m `using C` and the package `C` has a `uses B` , do I get the methods that `B` defines for `A.func` automatically?

one would get the methods that `B` defines for `A.func` automatically because `B` defines methods for `A.func`, not `B.func` (or some other function).

* * *

EDIT:

> [@goerz](#):
>
> However, if my package `B` reads
> 
> ```julia
> module B
> import A: func
> func(i::Int) = i
> end
> 
> ```
> 
> then `using B` (without `using A` ) in the REPL does give me access to `B.func` , and `B.func` includes both the methods from `A` and from `B` .

Just to be extra clear, the `B.func` that is accessible from the REPL is the same object as the `func` defined in `A`. Even though `B` is used to access the function, `B` does not have it’s own `func`, it just refers to `A`’s `func`.

* * *

EDIT 2:

I guess if you wanted `B` to have `func` with methods from `A` and `B` without adding methods to `A.func` you could do something like

```julia
module B
import A
func(args...) = A.func(args...)
func(i::Int) = i
end

```

In this case, `A.func` and `B.func` would be different objects, so adding methods to `B.func` would not add methods to `A.func`.

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [December 6, 2021, 8:54pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/4 "2021-12-06T20:54:09Z")

</div>

> [@lmiq](#):
>
> But here the REPL does not seem to try to autocomplete

It does if you add

```julia
julia> using .B

```

---

<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:** [December 6, 2021, 9:12pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/5 "2021-12-06T21:12:29Z")

</div>

> [@StevenWhitaker](#):
>
> > [@goerz](#):
> >
> > This last one seems like a bug.
> 
> There’s an error because you’re `export` ing a function that doesn’t exist ( `A.func` exists, but not `func` ). So I would say that’s an error on the package developer’s part, not on Julia’s part.

Oh, yeah, I agree that this didn’t make much sense in the first place. I think I would have expected Julia to complain that I’m exporting a non-existing object, either while parsing `B` or if it can’t do that due to [“sequential parsing”](https://discourse.julialang.org/t/namespacing-of-methods/72677/2) then when I’m importing `B`.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [December 6, 2021, 9:20pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/6 "2021-12-06T21:20:13Z")

</div>

> [@goerz](#):
>
> then when I’m importing `B` .

I have the impression that that problem falls into the same category as the usual complain that module dependencies are not parsed automatically. For instance, this errors:

```julia
julia> module A
           module B
               using ..C
           end
           module C
           end
       end
ERROR: UndefVarError: C not defined

```

one can ask: why can’t the the module be completely parsed before throwing the error? This has been exhaustively discussed in that “proper modules” thread, but I don’t remember the answer 😛 .

---

<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:** [December 6, 2021, 9:35pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/7 "2021-12-06T21:35:30Z")

</div>

So it seems like it comes down to this:

I should think of the “object” canonically referred to as `A.func` basically as the methods table. This object is a singleton, in the sense that there can be an arbitrary number of references to it with different names (`using A: func as foo`) and in different namespaces (`using A` in module `B` → `B.func`), but they’re all pointing to the same object. The methods table gets filled with any method definition that Julia comes across under any name, anywhere. There is no way to to prevent methods from being added to the methods table: if the compiler can see them, they’ll be added. I’m glossing over some details like the [“world age counter”](https://docs.julialang.org/en/v1/manual/methods/#Redefining-Methods).

Does that sound right?

The `export` statement has nothing do with any of this. It’s only meaning is to inject names into a namespace when importing.

Oh, and there’s some questionable behavior of Julia checking or not checking whether exported names actually exist, but that’s an unrelated discussion 😉

---

<div class="post-metadata">

**Author:** ![StevenWhitaker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevenwhitaker/32/9749_2.png) [@StevenWhitaker](https://discourse.julialang.org/u/StevenWhitaker)\
**Post date:** [December 6, 2021, 9:57pm UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/8 "2021-12-06T21:57:41Z")

</div>

> [@goerz](#):
>
> Does that sound right?

As far as I understand, yes.

> [@goerz](#):
>
> There is no way to to prevent methods from being added to the methods table: if the compiler can see them, they’ll be added

Hence

> [@lmiq](#):
>
> That is one of the reasons type piracy is highly discouraged

If everyone avoids type piracy, it probably doesn’t matter that a function gets methods added to it even in packages that are not directly used.

---

<div class="post-metadata">

**Author:** ![josePereiro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josepereiro/32/17322_2.png) [@josePereiro](https://discourse.julialang.org/u/josePereiro)\
**Post date:** [December 7, 2021, 1:34am UTC](https://discourse.julialang.org/t/namespacing-of-methods/72677/9 "2021-12-07T01:34:30Z")

</div>

I think having access to all the methods of a function is an unavoidable design decision (even ignoring compiler’s stuff). Imaging I do `import CoolArrays: CoolArray`, should I be forced to explicitly import all the methods from the `Iteration`, `Indexing`, `Abstract Arrays`, etc “interfaces” into scope every time? Even if most of their functions (but not `CoolArray` specific methods) are already into base and are usually available? Should all developers be forced to re-export them? And that’s just one type.
