-
-
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
recommend explicit using Foo: Foo, ...
in package code (was: "using considered harmful")
#42080
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also say that you can just do import Foo
instead of using Foo: Foo
?
What's the status of tooling support here? I'd say that's required before we make any such proclamation. |
Good point about tooling. Something very nice that Racket's IDE DrRacket does is that it shows you the source of a binding when you hover over it. That very nicely mitigates any confusion when reading code over the source of a particular binding. Also note that my suggested change to the verbiage makes this more informative and less prescriptive, which could be worthwhile regardless. |
Personally, I think we should be more prescriptive. As Kristoffer points out, this kind of use of |
I think it should be left up to code authors how they want to write their code. We can provide information that may inform their decision, but saying "Julia provides a way for you to do this but don't do it lul" isn't helpful. People find and fix breakages on the (in my experience, rare) occasions that they occur, users can qualify bindings or do explicit loads if they choose. When Base adds a new export, we should probably run PkgEval to see what effect it has. It would also be nice if packages with many dependants had reverse testing on new tags. That way package authors can be better equipped to work together to provide a good experience for users. |
People (including me) don't read documentation carefully always. Starting with a concise recommendation followed by reasoning seems to be the best practical strategy. If they disagree with the recommendation and understand the reasoning, it is of course "left up to code authors how they want to write their code." One missing reasoning step in the current version is that, adding features 1 is not considered breaking and can be done without incrementing the major version according to semver. So, if you only bound the major version and not minor version, you simply cannot 2 use Footnotes |
In many situations, I favor In any case, I haven't seen a good defense for The admonition seems like it belongs in some kind of style guide. And tooling might include an option in linters, with an option at some level to error on warnings. I don't see why it needs a certain level of tooling support before the recommendation is published. But, without tooling, I suspect adoption will remain weak. I'm thinking of the ways PEPs and pylint work in Python projects and clippy in rust. I not suggesting the big administrative burden of the whole PEP system, just that starting to adopt styles and tooling to handle complexity as the amount of code increases is wise. |
It could be an option for |
Arguably, there's nothing new in this PR. It has been (more or less) possible to derive this from the semver specification. While discussion on tooling is important on its own, I believe a more fundamental aspect is the interaction of semver and Julia's package/module system. Making it crystal clear even for those who haven't read the semver specification will help to reduce "controversies" of choosing the behavior of such tools. (I'm sorry for RTFM'ing. But I feel that this is an important point here.) |
I would instead recommend the other side: be conservative on what you should export and think about the naming ambiguity. For instance, exporting a From a maintenance perspective, exporting a function at will also makes it very difficult to deprecate and remove the symbol. |
I think this is perhaps stronger advice than required. How about pointing out the problem and proposing a way to address it without prescribing that "you shouldn't do this." Personally I'm OK with a rare breakage if I get to write nicer code internally in my packages. |
Out of curiosity, why? The presence or absence of tooling doesn't change any of the facts. |
Sure, this is why this is only a recommendation and this section just states the recommendation and the reason for it (exporting new names becomes a breaking change). |
But the language is still quite prescriptive: "X is not recommended, do Y instead" vs "X can be messed up by Z, you can prevent this by doing Y". Subtle difference, but one that I think affects perception. |
Just to give you an example of what this leads to (JuliaWeb/HTTP.jl#745 (review)). HTTP.jl now does type piracy on And with "nicer" code you mean to avoid the annoyance of having to spell out where your names come from. While you might be smart enough to remember exactly where all the names come from, I am not, so trying to look up where certain names come from is one of the main annoyances I have while reading code. Explicit mentioning where names come from would be a nice help to future contributors who don't have the namespace of all the dependencies in their head. |
Yes, the "axiom" here is that assuming everyone following semver and declares compatibility correctly, then we want to encourage coding in a way that keeps the code after a package update. That's why we discourage the use of type piracy, we discourage using internals of packages/Base. And as you say, an assumption is that adding a new export is not considered a breaking change (which I think is quite uncontroversial, looking at how Base does it). The conclusion from that is that since |
Any particular reason for not backporting this? I imagine that people using the LTS will be reading the 1.6 docs, and it would be good for them to see this recommendation. |
I agree that having tooling is not a pre-requisite for merging this PR. |
I'd be okay with a descriptive warning without there being tooling support. I don't like having a prescriptive admonition without tooling support. With tooling support, I'm 100% for it (hence my conflicting thumbs). Perhaps I'm in the minority, but I don't think this is a minor point. To make a (poor) analogy, some new governmental regulations are accompanied by tax credits/grants/assistance to offset their implementation cost. We should make it easy for folks to address. Without that, it's just words that core devs will point at to blame packages for breaking. |
Similarly, I think a descriptive warning (like Alex's suggestion) could be back ported to 1.6/1.7, but a prescriptive one should not be. |
The point is that the "regulation" (= semver) already exists. (I don't believe tooling should be a prerequisite but I'd also point out creating one is straightforward thanks to JuliaFormatter.jl. Here's my POC I experimented a while ago for automatically generating |
Co-authored-by: Alex Arslan <ararslan@comcast.net>
Looks like someone just needs to commit @ararslan 's suggestion and then merge |
Co-authored-by: Alex Arslan <ararslan@comcast.net>
I'm marking for merge, but a review approval wouldn't hurt |
Co-authored-by: Neven Sajko <s@purelymail.com>
@ararslan can you remove your block on merging? |
… 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 <dilum@aluthge.com> Co-authored-by: Mason Protter <mason.protter@icloud.com> Co-authored-by: Max Horn <max@quendi.de> Co-authored-by: Matt Bauman <mbauman@juliahub.com> Co-authored-by: Alex Arslan <ararslan@comcast.net> Co-authored-by: Ian Butterworth <i.r.butterworth@gmail.com> Co-authored-by: Neven Sajko <s@purelymail.com> (cherry picked from commit ee09ae7)
… 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 <dilum@aluthge.com> Co-authored-by: Mason Protter <mason.protter@icloud.com> Co-authored-by: Max Horn <max@quendi.de> Co-authored-by: Matt Bauman <mbauman@juliahub.com> Co-authored-by: Alex Arslan <ararslan@comcast.net> Co-authored-by: Ian Butterworth <i.r.butterworth@gmail.com> Co-authored-by: Neven Sajko <s@purelymail.com> (cherry picked from commit ee09ae7)
* writeVTK is exported by ExtendableGrids and not by VoronoiFVM. Newer versions of VoronoiFVM rely on explicit imports (see discussion on JuliaLang/julia#42080), so writeVTK is not visible anymore through VoronoiFVM. * Canged the data path to the one relative to the script (using joinpath anf @__DIR__
Backported PRs: - [x] #50832 <!-- Subtype: bug fix for bounds with deeper covariant var --> - [x] #51782 <!-- Fix remove-addrspaces pass in the presence of globals with addrspaces --> - [x] #55720 <!-- Fix `pkgdir` for extensions --> - [x] #55773 <!-- Add compat entry for `Base.donotdelete` --> - [x] #55886 <!-- irrationals: restrict assume effects annotations to known types --> - [x] #55867 <!-- update `hash` doc string: `widen` not required any more --> - [x] #56148 <!-- Make loading work when stdlib deps are missing in the manifest --> - [x] #55870 <!-- fix infinite recursion in `promote_type` for `Irrational` --> - [x] #56252 <!-- REPL: fix brace detection when ' is used for transpose --> - [x] #56264 <!-- inference: fix inference error from constructing invalid `TypeVar` --> - [x] #56276 <!-- move time_imports and trace_* macros to Base but remain owned by InteractiveUtils --> - [x] #56254 <!-- REPL: don't complete str and cmd macros when the input matches the internal name like `r_` to `r"` --> - [x] #56280 <!-- Fix trampoline warning on x86 as well --> - [x] #56304 <!-- typeintersect: more fastpath to skip intersect under circular env --> - [x] #56306 <!-- InteractiveUtils.jl: fixes issue where subtypes resolves bindings and causes deprecation warnings --> - [x] #42080 <!-- recommend explicit `using Foo: Foo, ...` in package code (was: "using considered harmful") --> - [x] #56441 <!-- Profile: mention `kill -s SIGUSR1 julia_pid` for Linux --> - [x] #56511 <!-- The `info` in LAPACK calls should be a Ref instead of a Ptr --> - [x] #55052 <!-- Fix `(l/r)mul!` with `Diagonal`/`Bidiagonal` --> - [x] #52694 <!-- Reinstate similar for AbstractQ for backward compatibility -->
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 onusing Foo
and then using an exported name fromFoo
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 recommendusing Foo
for ephemeral work (e.g. REPL work).