Skip to content

Commit

Permalink
recommend explicit using Foo: Foo, ... in package code (was: "using…
Browse files Browse the repository at this point in the history
… considered harmful") (#42080)

I feel we are heading up against a "`using` crisis" where any new
feature that is implemented by exporting a new name (either in Base or a
package) becomes a breaking change. This is already happening
(JuliaGPU/CUDA.jl#1097,
JuliaWeb/HTTP.jl#745) and as projects get bigger
and more names are exported, the likelihood of this rapidly increases.

The flaw in `using Foo` is fundamental in that you cannot lexically see
where a name comes from so when two packages export the same name, you
are screwed. Any code that relies on `using Foo` and then using an
exported name from `Foo` is vulnerable to another dependency exporting
the same name.
Therefore, I think we should start to strongly discourage the use of
`using Foo` and only recommend `using Foo` for ephemeral work (e.g. REPL
work).

---------

Co-authored-by: Dilum Aluthge <[email protected]>
Co-authored-by: Mason Protter <[email protected]>
Co-authored-by: Max Horn <[email protected]>
Co-authored-by: Matt Bauman <[email protected]>
Co-authored-by: Alex Arslan <[email protected]>
Co-authored-by: Ian Butterworth <[email protected]>
Co-authored-by: Neven Sajko <[email protected]>
  • Loading branch information
8 people authored Oct 26, 2024
1 parent f6a38e0 commit ee09ae7
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 1 deletion.
8 changes: 8 additions & 0 deletions base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ kw"help", kw"Julia", kw"julia", kw""
available for direct use. Names can also be used via dot syntax (e.g. `Foo.foo` to access
the name `foo`), whether they are `export`ed or not.
See the [manual section about modules](@ref modules) for details.
!!! note
When two or more packages/modules export a name and that name does not refer to the
same thing in each of the packages, and the packages are loaded via `using` without
an explicit list of names, it is an error to reference that name without qualification.
It is thus recommended that code intended to be forward-compatible with future versions
of its dependencies and of Julia, e.g., code in released packages, list the names it
uses from each loaded package, e.g., `using Foo: Foo, f` rather than `using Foo`.
"""
kw"using"

Expand Down
9 changes: 8 additions & 1 deletion doc/src/manual/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ VERSION >= v"1.11.0-DEV.469" && eval(Meta.parse("public a, b, c"))

### Standalone `using` and `import`

Possibly the most common way of loading a module is `using ModuleName`. This [loads](@ref
For interactive use, the most common way of loading a module is `using ModuleName`. This [loads](@ref
code-loading) the code associated with `ModuleName`, and brings

1. the module name
Expand Down Expand Up @@ -172,6 +172,13 @@ Importantly, the module name `NiceStuff` will *not* be in the namespace. If you
julia> using .NiceStuff: nice, DOG, NiceStuff
```

When two or more packages/modules export a name and that name does not refer to the
same thing in each of the packages, and the packages are loaded via `using` without
an explicit list of names, it is an error to reference that name without qualification.
It is thus recommended that code intended to be forward-compatible with future versions
of its dependencies and of Julia, e.g., code in released packages, list the names it
uses from each loaded package, e.g., `using Foo: Foo, f` rather than `using Foo`.

Julia has two forms for seemingly the same thing because only `import ModuleName: f` allows adding methods to `f`
*without a module path*.
That is to say, the following example will give an error:
Expand Down

0 comments on commit ee09ae7

Please sign in to comment.