-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Clarify and streamline paths and visibility #2126
Conversation
Once again, thanks so much to @aturon and everyone involved here for continuing to push on this! I was personaly quite happy with the previous iteration so it's only natural that I'm also quite happy with this version! This version of the RFC persists my favorite feature from before, requiring a keyword for local crate imports. It also allows obvious-in-retrospect things like I'd primarily like to advocate for the RFC 2088-like approach to the Otherwise I've got a few high-level comments but they're relatively nit-picky, so I don't mind resolving many of them during the implementation phase!
|
Huge 👍! I feel that this RFC is definitely a benefit for Rust, and improves the language. And I'm saying this as someone who has been opposing many of the previous module system proposals. I fully agree that thanks to this proposal, the Rust module system will be more clear and easier to use while still being as powerful and versatile as we know it today. I want to thank @cramertj, @withoutboats and @aturon for their awesome work in making this RFC happen. |
Under the RFC as-is, I think the replacement would be something like this: #![no_std]
#[cfg(feature = "std")]
crate use std;
fn main() {
// in some other cfg'd code:
let foo = crate::std::boxed::Box::new(5);
} Edit: note, though, that you probably wouldn't need this. Just writing the following would conditionally import #![no_std]
#[cfg(feature = "std")]
mod my_mod {
use std::<something>;
} Edit 2: I'm seeing lots of "confused" reactions-- can someone respond and explain what is confusing here? The idea is to import the |
text/0000-path-clarity.md
Outdated
- Second, one benefit of `crate` is that it helps reduce confusion about paths | ||
appearing in `use` versus references to names elsewhere. In particular, it | ||
serves as a reminder that `use` paths are absolute. | ||
|
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.
Another alternative might be to improve error messages.
Using example from Motivation, rather than just saying "Use of undeclared type or module futures
", as rustc does now, it could add a note to the effect of "...but I did find an extern crate of this name. You can use an absolute path to refer to it as ::futures::Poll
, or you can bring it into the current scope with use futures;
".
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.
The asymmetry between lib.rs and all other files doesn't just show up in the extern crate;
declarations, it also appears when you do use std::mem; use mem::swap;
. You can only do this in the crate root and as probably your first steps in Rust are by coding stuff inside the crate root and after that moving stuff from there into modules, it gives you this moment of surprise right at the start when you realize that submodules work differently. You can fix this inconsistency in two ways: either change how the crate root works, or change how use
works to be always like the crate root, aka relative. Previous proposals wanted to do precisely this change to use
, but I think this approach is nicer because its more conservative. Usually most of a crate's code is not inside lib.rs/main.rs.
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.
My point was that rather than revamping the module system, we could simply provide better error messages, like we do in other circumstances when the compiler can reasonably guess what went wrong. If we can't find module 'foo' in the current scope, but there is one in crate root, it's probably what the user wanted.
I don't think I've seen this option mentioned anywhere (at least lately). If it had been considered, maybe it should be mentioned among the alternatives along with why this isn't a good idea.
text/0000-path-clarity.md
Outdated
|
||
Another drawback is that imports from within your crate become more verbose, | ||
since they require a leading `crate`. However, this downside is considerably | ||
mitigated if [nesting in `use`] is permitted. |
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.
... or the compiler could search both the global namespace and the crate root (for relative use
's only, use ::...
would still be absolute).
I have been loosely following these different proposals and none of them really got me excited. However this feels like a great compromise! Nice job! Nice job @aturon, @withoutboats, and @cramertj! 👍 |
Really, everybody please do! Speaking as somebody who could barely even stand to hear the word "module" any more, I can attest that this proposal is different. It is short, has a single, clear focus, and will take maybe 5-8 minutes of your time to read through from start to finish. (I'm not sure; I should've used a stopwatch!) |
A huge thank-you to @aturon, @withoutboats, @cramertj, and everyone else who's worked on this series of RFCs – I know it's been an incredibly difficult process for so many people, but I'm really happy to see that it looks like we're close to reaching a compromise that seems acceptable both in improving the ergonomics story for beginners and not breaking existing code too drastically. Thank you all for your hard work! ❤️ |
I like it. Unlike most other proposals, I have no major reservation/pain point with this one. Looks like a clear improvement on all fronts to me. I'm happy about it, and kinda relieved to be honest (looking back on other proposals). It's been really hard to follow, so a big thank to all that worked on this for reaching this great consensus. |
I'm not a fan of crate being used in the place of pub and the companion linter. I fail to see it bringing a net benefit. Edit: does the crate/pub also apply for struct fields? Overall this is great! A lot of those for all involved so far ❤️ |
Great work! Some comments and questions:
I don't think so, first without it we reduce need for fixing perfectly fine code, and second I personally like that to rename/move module you just need to rename/move folder and fix
I prefer What about inline modules? As I understand they will be left untouched?
In your example you forgot to add If possible I think ideal solution would be to allow use of use core::ops::Add;
#[cfg(feature = "std")]
use std::io::Read; And issue compilation errors if |
edit: nevermind, I forgot that epochs are explicit opt-in If I understand correctly, the second epoch requires migrating all There's probably a long tail of crates on crates.io that are not maintained. Are they going to be left broken? Forcefully |
The epochs system means that they will not break; they'd be on epoch 2015. |
@pornel Maybe I've missed something, but I thought a major highlight of the epochs proposal was that crates written for different epochs are fully intercompatible, so that abandoned crates for old epochs will |
I think this is the right change. I would really like to see exploration of a closer mapping of modules to the filesystem. But I feel like doing that cleanly may require removing I would also like to see some syntax sugar for crate/self/super: something to visually distinguish them from module identifiers like |
So I take this to mean that in Epoch 2 it will be possible to use an external library named |
Yes, that's the idea! And in particular, there's no way to get there without a new epoch. |
text/0000-path-clarity.md
Outdated
```rust | ||
// Either of these work, because we brought `std` into scope: | ||
fn make_vec() -> Vec<u8> { ... } | ||
fn make_vec() -> std::vec::Vec<u8> { ... } |
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 the comment be
// Either of these work because we brought both `std` and `std::vec::Vec<u8>` into scope
?
text/0000-path-clarity.md
Outdated
``` | ||
|
||
All `use` declarations are interpreted as fully qualified paths, making the | ||
leading `::` optional for them. |
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.
Yes, the guide is describing how things will look under the full implementation, which means a future epoch.
text/0000-path-clarity.md
Outdated
|
||
- Cargo will provide a new `alias` key for dependencies, so that e.g. users who | ||
want to use the `rand` crate but call it `random` instead can now write `rand | ||
= { version = "0.3", alias = "random" }`. |
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.
Perhaps I'm missing something obvious, but how does rustc get this alias
information? Does it get passed by cargo or does rustc parse the Cargo.toml? The RFC says that the interface between rustc and cargo doesn't change, so I'm a bit confused here...
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.
Cargo already passes --extern rand=path/to/rand.rlib
, all it has to do is change the first rand
to be random
, but the interface remains the same. Maybe the RFC should be more explicit here?
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.
It's not spelled out here, but in previous proposals, the idea was for cargo to pass --extern foo=.../libbar.rlib
. This form of aliasing is already supported by rustc, so the only change is to let cargo make use of it.
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.
Ah, that makes sense. Perhaps this could be added to the RFC, please, @aturon ?
Just a quick question from me: This RFC states that Everything else looks fantastic and is what I had hoped for when I began reading and writing Rust. Edit: Actually, mostly everything looks good. I do not like implicitly bringing things into scope. |
This RFC has now been merged! Thank you, all, for what has surely been the most extensive continuous design discussion in Rust history (considering the prior RFCs and internals threads). This discussion helped shape a huge number of iterations, and the final design is much stronger for it -- besides which, it is also appealing to a much wider array of stakeholders. And in particular, I believe that all major points that have been raised on the final design have been addressed, either through changes or discussion about the tradeoffs. As per recent comments, there are two formal Unresolved Questions left:
Discussion on those points will continue on the tracking issue. |
I have opened a new RFC to discuss |
I just realised that |
Do you mean safety as in Privacy is an integral part of safety, no doubt about that; but I suspect that most usage of
Assuming you mean the |
@aturon, it looks like the "rendered" link in this issue's description is broken. Any chance you can update it? It looks like it's just a case of changing the placeholder |
@aturon your "rendered" link is unfortunately still broken |
@Lokathor Thanks for the reminder - I went ahead and fixed it. |
I've been searching for that experimental RFC regarding "the possibility of determining modules from the file system" (as mentioned in OP) but can't find it anywhere... Any pointers, please? :) |
@dlukes I don't believe that particular facet ever got as far as an eRFC, only discussion. That may get revisited after the 2018 edition. |
@joshtriplett Oh OK, thanks :) Sorry, I guess this must've been discussed somewhere at some point, but as a newcomer to the discussion, it's a bit daunting to comb through the sheer volume of comments in the various threads devoted to the subject. @aturon Please maybe remove "The experimental RFC will be posted soon." from OP then, if you have a bit of spare time, so as not to confuse latecomers? :) In any case, thanks for the huge amount of intellectual and emotional energy you guys spent on this! For a casual user such as myself, it was fairly hard to translate the seemingly simple rules behind Rust's original module system into the right set of intuitions and habits. |
Read this first
This is the latest RFC in the ongoing saga around Rust's module system. For those of you who have stopped following due to fatigue 😩: this is almost certainly the final iteration, and I'd like to ask you one last time to take a fresh look -- almost all of the text here is new. ❤️
Relative to earlier discussion, this proposal is drastically more conservative. It does not include any changes to
mod
(i.e., it does not propose to determine module structure from the file system). It does not require epochs.The lang team does still want to explore the possibility of determining modules from the file system, but plans to do that through an experimental RFC -- i.e., to seek just for consensus that we can land a prototype implementation to gather more data and experience; a full RFC must subsequently be accepted prior to any stabilization. The experimental RFC will be posted soon.
How to give feedback
A word about feedback. I'm eager for feedback from the entire community, but am also conscious that the comment velocity on this topic has been very large. Thus I would ask:
Summary
This RFC seeks to clarify and streamline Rust's story around paths and visibility for modules and crates. That story will look as follows:
crate
refers to the current crate (other forms are linted, see below)extern crate
is no longer necessary, and is linted (see below); dependencies are available at the root unless shadowed.crate
keyword also acts as a visibility modifier, equivalent to today'spub(crate)
. Consequently, uses of barepub
on items that are not actually publicly exported are linted, suggestingcrate
visibility instead.foo.rs
andfoo/
subdirectory may coexist;mod.rs
is no longer needed when placing submodules in a subdirectory.These changes do not require a new epoch. The new features are purely additive. They can ship with allow-by-default lints, which can gradually be moved to warn-by-default and deny-by-default over time, as better tooling is developed and more code has actively made the switch.
This RFC incorporates some text written by @withoutboats and @cramertj, who have both been involved in the long-running discussions on this topic.
Rendered