-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
Description
Problem
Currently, when you do using M
and the code for M.jl
is automatically loaded, the file is evaluated in Main
and expected to define a module M
. It can, however, evaluate arbitrary code in Main
before or after the definition of M
and can fail to define M
entirely:
# M.jl
@show @__MODULE__ # => Main
module M # can not do this bit
@show @__MODULE__ # => Main.M
end # module M
@show @__MODULE__ # => Main
With #23579 and the plan outlined in #4600 (comment), this becomes increasingly awkward. Modules will no longer live inside of Main
so what module is code before and after the definition of M
evaluated in?
Proposal
The simplest solution would be for the code in the file M.jl
to be evaluated inside of M
instead of defining M
. In other words, the file M.jl
would be reduced to this:
# M.jl
@show @__MODULE__ # => Main.M
When using M
or import M
ends up loading this file, it would implicitly wrap it in the equivalent of module M; include("M.jl"); end
. This way the module M
cannot help but be defined and the boilerplate module M
and corresponding end # module
at the beginning and end of most files is eliminated.
Transition
One fact makes this transition surprisingly straightforward: modules automatically have a constant, internal self-binding. Thus, module M; module M; end; end
causes a warning to be printed: WARNING: replacing module M
. Because of this, we can safely implement the above proposal and simply change the behavior of module M; module M; end; end
– the inner module M; end
would have no effect, simply continuing with the definition of the outer M
. To encourage people to change their code and eliminate the boilerplate, we can emit a warning that the module M
is no longer necessary and should be deleted.
The most common and official case of code evaluated in Main
before module code is __precompile__
calls in packages, controlling/indicating whether a package is precompilable or not. This would no longer work as expected, so we need an alternative. Since precompilability is a package-level property, it would make sense for this bit to be recorded in the new Pkg3-style as a precompile = [true|false]
entry in the Project.toml
file. This metadata would automatically be propagated to the Pkg3 registry metadata for various versions of each package.