Background: what are implicit and explicit imports?
An explicit import is a statement like using SomePkg: foo
or import SomePkg: foo
which explicitly brings the name foo
into your module (often another package). In contrast, an implicit one is a statement like using SomePkg
, which brings all names exported by SomePkg into your module.
Implicit imports can be convenient, but they occasionally have issues in which another package OtherPkg
starts exporting the same name foo
(pointing to a different function, say), which makes it ambiguous which function should be associated to the name foo
in your module.
Some also criticize that with implicit imports, if you only have access to the source code, you can’t see where each name is coming from. (If you are in a REPL, use @which
to easily do so).
Explicit imports, on the other hand, can be quite inconvenient. You need to manually specify each name that you want to import. You also need to maintain this list as you use more names or stop using some names.
The choice of implicit vs explicit exports can be somewhat contentious, and I think in general the right choice depends on the specific usage (and your preference). I would prefer if folks don’t use this thread to debate which to use, and focus on the functionality ExplicitImports.jl provides (or fails to provide, as the case may be).
What does ExplicitImports.jl do?
ExplicitImports.jl attempts to make it easier to use and maintain lists of explicit imports. The main interactive entrypoint is:
using ExplicitImports, MyPackage
print_explicit_imports(MyPackage)
For example:
julia> using ExplicitImports
julia> print_explicit_imports(ExplicitImports)
Module ExplicitImports is relying on implicit imports for 6 names. These could be explicitly imported as follows:
```julia
using AbstractTrees: AbstractTrees
using AbstractTrees: Leaves
using AbstractTrees: TreeCursor
using AbstractTrees: children
using AbstractTrees: nodevalue
using JuliaSyntax: JuliaSyntax
```
Additionally, ExplicitImports has stale explicit imports for these unused names:
- GreenNode
This allows one to develop some code using implicit imports, then call print_explicit_imports
to get a list of explicit import statements to copy into their code.
Additionally, if one would like to only rely on explicit imports, you can add ExplicitImports as a test dependency, and add check_no_implicit_imports(ExplicitImports)
to your tests. ExplicitImports is registered in General to make it convenient to add as a test dependency.
There’s a bit more discussion and a few more features in the docs, so please check those out for more!
And if you run into any bugs or problems, please file an issue. ExplicitImports works by parsing your code and trying to re-implement Julia’s scoping rules to figure out whether any given name refers to a global that may be implicitly imported, or just a local variable. There’s a ton of edge cases and it’s very possible there are common failure modes. I am hoping we can squash those as they arise, and rely on the ignore
kwarg in check_no_implicit_imports
in the meantime to manually suppress false positives. (And if you know about parsing and have ideas about how I can do it better, please file an issue or PR!).