-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implicit module M
wrapping
#23619
Comments
|
Packages don't have to be registered to have a |
To keep the module definition explicit, which I personally prefer, we could also disallow having any code outside of the module definition. The package file would have to start with |
I'm curious why you prefer keeping the module name explicit – what's the benefit? |
The benefit of keeping it explicit is that I think users may be confused if the "same" code creates a module in a file vs. global definitions if pasted into the REPL. On the other hand, it doesn't seem to confuse Python people too much? |
I thought it created an asymmetry/inconsistency with submodules, for which you still would need to write out the keyword. I also liked that |
I think we could make |
Julia is a safe language by default, and |
I don't think there should be any safety issues with it that are specific to it, just additional warnings / errors. |
I guess you could take the position that any code using There is also the fact that new users creating modules probably don't want precompiling, because it slows things down if you are continually changing the module. Precompiling is mainly for experienced developers of larger packages. |
That's a good point. |
I think this was solved by Revise.jl. I don't think there's any particular need to distinguish experienced and novice developers via some arbitrary keyword anymore.
I'm not aware of any And making |
@vtjnash, once you start using Revise doesn't completely solve the problem because it can't handle e.g. changes in type definitions. In general, I wouldn't recommend using precompilation initially when starting new packages. |
@stevengj: AFAICT #22721 should resolve the issue with changed type definitions (timholy/Revise.jl#18 for |
@lucatrv: I'm not seeing the issue. Calling |
@StefanKarpinski: ok, but in this case how would one decide whether to put an explicit IMHO an optional string passed to
|
I'm not sure what the use case for being able to either load code via Your proposal looks both more complicated and less backwards compatible than what's discussed in #4600. Relative using should not look in the current working directory, nor is the fact that the module path is relative the most salient point. Did you read through the latest proposal in #4600? If one wants to simulate the behavior of |
Sorry I mistakenly wrote "current working directory" while I meant "current source file directory", so I am going to report here the examples above corrected (with a few additions):
After lots of reading and thinking on how Julia code should be organized into modules to be reusable, in my mind I got the idea that
while A module source file could either:
When I read the latest proposal in #4600, I though that it covers cases 1 and 2, but not 3. So my intent was actually to extend your proposal, with the following two differences:
IMHO this proposal is still in line with #4600, and with similar degree of backwards compatibility (just more features). In case you do not like it, there can be of course other options, but in general I think that a way to provide absolute paths to |
Would this proposal prevent |
It seems like several independent issues are getting mixed together here: (1) whether Personally, I tend to agree with @jebej: module loading is much less magical if the module code looks the same no matter where you load it from. Code before and after the |
@stevengj: I think that points (1) and (3) are interdependent. If Regarding @jebej comment:
on the other hand I subscribe the 13th aphorism of the Zen of Python:
which has been a main general goal of Python 3. I think that having a clear distinction on what |
This is not the case –
Yet your above argument is that implicit module wrapping is bad because it prevents you from using |
@StefanKarpinski sorry if I was not able to express myself clearly. I actually like very much the implicit module wrapping proposal, for the reasons outlined in your first post of this thread. My position however is that together with the implicit module wrapping proposal, the capability to load modules from absolute paths (case 3 of my Oct 31st post above) should be added to the I will try to better detail my position in the following. Please consider that all this is based
Now that I should have fully explained my opinion, if you do not agree with it, for my understanding I would like to ask why instead in your opinion it is better that the Sorry for the long post but I hope it clarifies. |
I don't think it's the business of the code that loads a module via
The new package manager provides the ability to put absolute (or relative) paths in a project manifest file, telling Julia to load Even with that mechanism, I don't really think using absolute paths for this sort of thing is a great idea. Relative paths are ok since you may want to refer to a resource defined within the same project which is updated in sync with the code that uses it. Otherwise, you want to specify the identity of a package (i.e. package UUID) that you'd like to use and the identity of a particular state of that package (i.e. version tree hash) that you'd like to load. As long as it gets the right version of the right package, code shouldn't care where it came from or lives on disk. |
@StefanKarpinski: this clarifies all my questions, now that I see the full picture I perfectly agree with you, thanks! |
I think this will be out of scope for 1.0. |
This could be added in a non-breaking way by just making the inner module in |
Problem
Currently, when you do
using M
and the code forM.jl
is automatically loaded, the file is evaluated inMain
and expected to define a moduleM
. It can, however, evaluate arbitrary code inMain
before or after the definition ofM
and can fail to defineM
entirely: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 ofM
evaluated in?Proposal
The simplest solution would be for the code in the file
M.jl
to be evaluated inside ofM
instead of definingM
. In other words, the fileM.jl
would be reduced to this:When
using M
orimport M
ends up loading this file, it would implicitly wrap it in the equivalent ofmodule M; include("M.jl"); end
. This way the moduleM
cannot help but be defined and the boilerplatemodule M
and correspondingend # 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 ofmodule M; module M; end; end
– the innermodule M; end
would have no effect, simply continuing with the definition of the outerM
. To encourage people to change their code and eliminate the boilerplate, we can emit a warning that themodule 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 aprecompile = [true|false]
entry in theProject.toml
file. This metadata would automatically be propagated to the Pkg3 registry metadata for various versions of each package.The text was updated successfully, but these errors were encountered: