# "Under the hood" difference between import and using

**URL:** <https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741>\
**Category:** Internals & Design\
**Tags:** question, module\
**Created:** [September 11, 2023, 2:24pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741 "2023-09-11T14:24:35Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![deaminase](https://avatars.discourse-cdn.com/v4/letter/d/b2d939/32.png) [@deaminase](https://discourse.julialang.org/u/deaminase)\
**Post date:** [September 11, 2023, 2:24pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/1 "2023-09-11T14:24:36Z")

</div>

So, based on the docs I know that eg. `import` doesn’t bring in any exported identifiers to your namespace when importing a module, and if you want to add a method to a function without using its fully qualified name, you have to do eg. `import Base: show` before defining `function show(io, x::MyType) …`, but I’d like to know what the difference between `using` and `import` really is under the hood.

`Base` [docs](https://docs.julialang.org/en/v1/base/base/#import) say this for `using`:

> `using Foo` will load the module or package `Foo` and make its [`export`](https://docs.julialang.org/en/v1/base/base/#export)ed names available for direct use.

and this for `import`:

> `import Foo` will load the module or package `Foo` . Names from the imported `Foo` module can be accessed with dot syntax (e.g. `Foo.foo` to access the name `foo` ). See the [manual section about modules](https://docs.julialang.org/en/v1/manual/modules/#modules) for details.

For modules the difference between `using` and `import` is pretty clear, but `using Foo: corge` and `import Foo: corge` seem to do the same thing _except_ that you can’t add methods to a function that was brought into the namespace with `using`, so this left me wondering what the difference of those two forms is from the compiler’s / runtime’s standpoints

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [September 11, 2023, 2:46pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/2 "2023-09-11T14:46:41Z")

</div>

You might want to add “under the hood” or “from the compiler’s / runtime’s standpoints” to the title. Otherwise, the people most qualified to answer this might skip over it thinking it’s asking about the basic difference between `using` and `import` that you already have an idea about.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 11, 2023, 3:39pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/3 "2023-09-11T15:39:49Z")

</div>

How deep do you want to go here? At a high level, Julia keeps track of the two things separately. There’s a list of bindings (things that have been explicitly assigned to or `import`’ed) and a list of modules that have been brought in by `using` (which are used to looked up things as needed).

You can see one half of this difference at the user-level with `names(Main, imported=true)`. `import`’ed and explicitly assigned names will appear in that list, but all the things available with `using` aren’t. That `usings` list is tracked separately and internally and isn’t exposed directly in Julia-land. Tab completion, for example, traverses both lists, combining the bindings `names` returns with all the exports from the `using`s.

---

<div class="post-metadata">

**Author:** ![deaminase](https://avatars.discourse-cdn.com/v4/letter/d/b2d939/32.png) [@deaminase](https://discourse.julialang.org/u/deaminase)\
**Post date:** [September 11, 2023, 3:52pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/4 "2023-09-11T15:52:40Z")

</div>

> How deep do you want to go here?

How much free time do you have? 😁

Interesting that `using`’d names are stashed away deeper in the runtime, but `import`ed ones are easily available. Sort of makes it feel like if I want to simply eg. bring a function into my package’s namespace so that users of the package can call `MyPakidge.foo()` instead of `SomeDependency.foo()`, `import SomeDependency: foo` might be preferable, although I assume that really wouldn’t make much of a difference except for eg. tooling that uses `Base.names` to see what names are available in a module.

---

<div class="post-metadata">

**Author:** ![jishnub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jishnub/32/33620_2.png) [@jishnub](https://discourse.julialang.org/u/jishnub)\
**Post date:** [September 11, 2023, 3:55pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/5 "2023-09-11T15:55:41Z")

</div>

> [@mbauman](#):
>
> Tab completion, for example, traverses both lists, combining the bindings `names` returns with all the exports from the `using`s.

This doesn’t appear to be the case:

```julia
julia> using Base: OneTo

julia> OneT<tab> # no completion

```

whereas the completion works if one uses `import Base: OneTo`

---

<div class="post-metadata">

**Author:** ![deaminase](https://avatars.discourse-cdn.com/v4/letter/d/b2d939/32.png) [@deaminase](https://discourse.julialang.org/u/deaminase)\
**Post date:** [September 11, 2023, 3:59pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/6 "2023-09-11T15:59:40Z")

</div>

Aha-ha, I didn’t even think to check that. Also, interestingly neither of these completes:

```julia
module Corge
  bleb(x) = 2x
end

module ModWithUsing
  using ..Corge: bleb
end

module ModWithImport
  import ..Corge: bleb
end

```

Both `ModWithUsing.<tab>` and `ModWithImport.<tab>` just give `eval include`, so I guess if I want to just “surface” names from other packages, using a `const` might make them more discoverable for REPL users?

```julia
module ModWithConst
    import ..Corge
    const bleb::typeof(Corge.bleb) = Corge.bleb
end

```

Also, side question, how necessary is the type annotation `::typeof(Corge.bleb)` for that `const`? I’ve seen some packages do that in similar cases but I have no idea if it’s just a leftover from older Julia versions or what. The manual does impress on you that typing even `const` globals is important, but it honestly feels funny to have to explicitly type `const`s

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 11, 2023, 4:04pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/7 "2023-09-11T16:04:42Z")

</div>

Yeah, I’m honestly not sure where the `using Foo: X` bindings go. Tab completion only traverses the two lists I mentioned (the bindings and the usings), which is why those aren’t showing up there.

If you want to go deeper, it’s the module itself that keeps track of all this… and modules are one of the few portions of Julia implemented in C:

> <https://github.com/JuliaLang/julia/blob/10974814b3faa1dea140062cfe1f3e63962074d5/src/julia.h#L610-L617>

The bindings field is what `names` uses. The `usings` field are those modules that are brought in wholesale by `using` (you can see this list with `@ccall jl_module_usings(Main::Any)::Any`).

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 11, 2023, 4:10pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/8 "2023-09-11T16:10:14Z")

</div>

> [@deaminase](#):
>
> Both `ModWithUsing.<tab>` and `ModWithImport.<tab>` just give `eval include`, so I guess if I want to just “surface” names from other packages, using a `const` might make them more discoverable for REPL users?

You you can also explicitly `export` them for them to show up in those tab-completed lists. The tab-completion for modules uses `names(Mod, imported=false)`.

---

<div class="post-metadata">

**Author:** ![deaminase](https://avatars.discourse-cdn.com/v4/letter/d/b2d939/32.png) [@deaminase](https://discourse.julialang.org/u/deaminase)\
**Post date:** [September 11, 2023, 4:12pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/9 "2023-09-11T16:12:54Z")

</div>

Ah derr, of course `export` would work for names brought in from other modules too 🤦

**Edit:** I guess the `const` version above could be useful if you want to rename your “export”?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [September 11, 2023, 5:27pm UTC](https://discourse.julialang.org/t/under-the-hood-difference-between-import-and-using/103741/10 "2023-09-11T17:27:36Z")

</div>

Yeah, you can also use [Reexport.jl](https://github.com/simonster/Reexport.jl).

The special case of `using Mod: X` and its lack of tab-completion is issue [#29275](https://github.com/JuliaLang/julia/issues/29275).
