-
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
Prelude additions #3090
Prelude additions #3090
Conversation
# Motivation | ||
[motivation]: #motivation | ||
|
||
While types and free functions can be added to the prelude independent of edition boundaries, the same is not true for traits. Adding a trait to the prelude can cause compatibility issues because calls to methods named the same as methods of the newly in scope traits can become ambiguous. Because editions are opt-in, they represent an opportunity to add new traits to the prelude. |
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.
Adding a trait to the prelude can cause compatibility issues
This is true, but AFAIK T-libs doesn't actually consider that a breaking change (since otherwise every time they added an inherent method, or a new method to a trait, it could break code). Not sure if you want to mention that or not.
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.
I think the official terminology is that it's a "minor change": https://rust-lang.github.io/rfcs/1105-api-evolution.html#minor-change-adding-a-defaulted-item
So allowed despite the breakage.
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.
I think it's still worth keeping this explanation, and just expanding it to make it clear that while we can make such a change, we may choose not to due to the possibility of breakage.
The explanation should also make clear that many traits we might want to add are especially likely to cause breakage, because they may conflict with similar traits from the crate ecosystem that exist to fill the same need that the standard library trait would.
- `std::fmt::Display`: users of this trait generally don't need to import it because the `ToString` trait which relies on the `Display` implementation is already in the prelude. Implementers of the `Display` trait however need several other items from `std::fmt` to do so; therefore, just importing `Display` into the prelude does not help much. This RFC suggests adding `fmt` to the prelude to improve this use case. | ||
- `std::fmt::Debug`: similar to `Display`, although there's no `to_debug()`. However, usage will usually go through `dbg!()` or the formatting mechanism (as a `{:?}` format string). | ||
- `std::future::Future`: `Future`'s `poll()` method is usually not called directly, but most often used via `async`/`await`, therefore including `Future` in the prelude does not seem as useful. | ||
- `std::error::Error`: while this is commonly implemented, calling its methods directly does not seem to be common enough that adding this is as useful. |
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 drawback: this would be ambiguous with std::io::Error
.
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.
yeah calling both types Error was a big flub :/
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.
@Lokathor it's a rather common design choice to reuse names in different modules. This means that you have to write io::Error
instead of something like IoError
, which I actually prefer. Another example is fmt::Write
and io::Write
. However, I don't like that the write!
macro requires importing one of them, but that's another topic.
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.
A common misconception. Only std::io and std::fmt do that weird thing where you're supposed to use the module name as a prefix. Every other error in the standard library just has a sensible name that doesn't need a prefix.
Either way, it's a bad plan at this point to put something called Error
directly in the prelude.
It's possible that the confusion wouldn't be too high because one is a trait and the others are structs, but better to avoid the possibility.
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.
Why not add std::sync to the prelude like it was proposed for std::mem?
I think sync
is probably as reasonable as the other proposed modules, but I honestly think you could make that argument for almost every module in the stdlib. I htink for that it's a compelling example of where having some sort of policy here would help.
(EDIT: When I replied to this it was in the thread about the std::sync
changes... That said, that thread still seems out of order, so maybe github will fix itself?)
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.
I don’t think it’s useful to blame users for following the standard library’s pattern of io::Error
and fmt::Error
.
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.
True, but the standard library has since moved away from that pattern (AllocError, Utf8Error, etc).
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.
AllocError is not stable and there's an open point about renaming it. Utf8Error is not in an utf8 module, so it's not changing any conventions. I believe I've heard some Error was accidentally stabilized not following that convention though. But I'm pretty sure there's no real precedent for changing that convention.
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.
Personally I find it annoying that I have to write std::sync::atomic::{AtomicU8, AtomicU16}
instead of use std::sync::atomic
and then atomic::U8
and atomic::U16
(it's even worse to write atomic::AtomicU8
and atomic::AtomicU16
). I think it is quite idiomatic in the current state of Rust that we always prefix external items with their module (or crate if it's top-level), similar to the package.Item
convention in golang (in which you can't even avoid that).
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.
Yeah, I kind of wish atomics were just in std::sync::AtomicU8
instead of std::sync::atomic::AtomicU8
. I don't think atomic::U8
would be an improvement though, honestly I feel that would be worse. (This isn't on-topic though. These discussions get long enough as is)
I think it is quite idiomatic in the current state of Rust that we always prefix external items with their module
I don't think this bears out in practice. Most of the code I see and interact with isn't written this way. Additionally, autoimport functionality in IDEs doesn't work this way.
[prior-art]: #prior-art | ||
|
||
<details> | ||
<summary markdown="span">RFC template</summary> |
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.
leftover?
Co-authored-by: est31 <[email protected]>
|
||
The new prelude will be named after the edition that introduces it to make the link to the edition more obvious. Each edition will have a separate prelude, whether the contents are actually different or not. | ||
|
||
Importantly, we'll need to make the upgrade path to an edition containing new traits in the prelude as smooth as possible. To that end, cargo fix will update code that calls `try_from()` or `try_into()` in a scope that does not have the std traits in scope to use the explicit disambiguation syntax. |
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.
Speaking from experience from the 2018 edition, this is extremely underspecified.
I'm going to leave a comment there as well, but each edition RFC that has breakages should have a section that:
- Lists out all the potential breakages, big and small
- Has an in-depth design for a migration lint that will migrate code such that it compiles on both editions. Make sure to get sign off from the compiler team that such a lint is feasible
- Optionally has an in-depth design for an idiom lint that will clean up the migrated code (potentially making it compile on the new edition only)
The 2018 edition RFCs tended to handwave about migration, and when the time came to implement it I realized that there wasn't actually a workable plan and as an implementor I had to come up with it at the last moment, trying to quickly build consensus. We should strongly avoid this situation recurring.
- `std::path::{Path, PathBuf}` | ||
- `std::sync::{Arc, Mutex, RwLock}` | ||
- `std::borrow::Cow` | ||
- `std::fs::File` |
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.
File
doesn't seem very useful without Read
or Write
. It also has the same problem with async as Mutex
and RwLock
.
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.
Though on that note, having Read
/Write
in the prelude would make a lot of APIs a lot easier to use. Socket and File IO are frequently annoying to use due to having to import both the traits and the concrete type (File/TcpStream).
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.
I would second adding Read
/Write
to the std::prelude
, yes
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.
Maybe Read/Write but actually not the types? Unsure considering the AsyncRead concern, but
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.
If std::io::Write
is added to the prelude, using std::fmt::Write
becomes more difficult because of name conflicts. Not sure how many people use that trait, tho.
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.
They could be added as use std::io::{Read as _, Write as _};
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.
If the prelude includes std::io::Write
, how do I write!
using std::fmt::Write
to a String
?
Sorry to pop in with random questions, but would it be possible to provide evidence for these by looking at how often these types (and other std types) are used, and imported, over a large set of code (like cargo packages)? |
|
||
Apart from the 2021-specific prelude, this RFC also proposes to add several items to preludes for all editions. These changes do not have to be aligned with an edition boundary, since there is no compatibility hazard (explicitly imported names always shadow prelude names). | ||
|
||
- `std::{mem, fmt}` |
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.
I feel like modules are a pretty large change here, so far we've only ever had types, traits, and functions in the prelude, if modules are included then people may think they are crates. This drawback should be called out and addressed.
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.
Given that e2018 makes all cratenames implicitly present in every scope, I personally am very skeptical of having any other source of implicit inclusion of lowercase symbols.
Currently, the preludes only import one function: core::mem::drop
. All other lowercase symbols imported by the preludes are macros, which can only be used with macname!
or #[macname]
, and are not able to visually collide with crate, module, or function names in source. I tentatively would not disagree with placing additional functions in the prelude, but I firmly believe that placing module names in the prelude is a mistake for exactly the reason you outline.
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 RFC specify what happens if the module name collides with a crate? There are already mem
and fmt
crates (that have no reverse dependencies).
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.
No, the prelude is just a glob import, glob imports have well-defined behavior around this.
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.
@mbartlett21 it's also possible that other packages explicitly specify the cargo lib.name
to be mem
or fmt
. Not sure if there are any of those, but it's quite likely that this happens in private (as in not released on crates.io) monorepo projects. For example, when I write a binary that uses some ad-hoc procedural macros, I would create a my-codegen
package in the same workspace with lib.name
as a very short word, e.g. mac
or gen
. I am unsure whether other people would name their crates mem
or fmt
in a similar manner.
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.
While adding mem/fmt to the prelude could be pragmatic, I think the drawback of introducing a "separate root" (apparently, effectively) like mem
makes the whole thing harder to understand for users. I'd argue for lifting these functions to std::swap
etc (as mentioned elsewhere) or other solutions, like no change.
|
||
However, it is reasonably common that type inferencing fails to infer the full type of the target type, in which case an explicit type annotation or turbofishing is needed (such as `iter.collect::<HashMap<_, _>>()` -- the type of the iterator item is available, so wildcards can be used for this). In these cases, `HashMap::from_iter(iter)` can be a more concise and readable way to spell this, which would be easier if the trait was in scope. | ||
|
||
## `std::{mem, fmt}` |
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.
A bunch of stuff for these is also applicable to other modules, like io::Result
or ops::Add
or whatever. Or one could argue for cmp::min
to parallel with f64::min
.
So I'm not convinced by the justification in here that specifically these two is the right thing to do.
Maybe also mention whether or not this does/should affect the core prelude. IMO, the core prelude should contain the same things as the std prelude minus the std-specific stuff. |
|
||
## `std::{mem, fmt}` | ||
|
||
It is reasonably common to use functions from the `mem` module such as `replace()` or `swap()`. These method names are generic enough that it is useful to keep the `mem::` prefix explicitly. Providing a `mem` name as part of the prelude makes this pattern more obvious and, given the short module name, will not require any imports to make use of the items in this module. |
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.
Could you justify why this means that this module should be added to the prelude? I don't think that an item being imported a lot actually justifies adding it to the prelude. Especially given that we have no way of actually knowing whether "imported a lot" is true. (You can prove it for your code, and maybe for some of the code in public online, but there is so much more Rust code than that.) It is also worth discussing what we think the prelude should even be for. It's hard to discuss which particular items should go in before we've all agreed on that.
In general, I don't think saving people from writing something like use std::mem;
is worth the confusion of people trying to figure out whether that name is an external crate or in the prelude.
I am reasonably in favor of adding some common traits like TryFrom
/TryInto
but types and modules should generally be imported explicitly so people can figure out where the name comes from when they read the code. The reason this is less of a problem for traits is because people generally call the trait methods themselves. They don't commonly refer to the trait name.
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.
You can prove it for your code, and maybe for some of the code in public online, but there is so much more Rust code than that.
We can, and in my opinion should (because I think it would be cool as well as educational), grep crater for the proportion of Rust modules that use symbols from the distribution libraries, whether by use
or by fully qualified path at the use site.
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, I guess my point is that not only is that data not complete (because it ignores a huge swath of non-open source code), it also embeds the assumption that usage is sufficient justification. We'd need to define what the prelude is actually for before we get there.
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.
because it ignores a huge swath of non-open source code
In the absence of raised evidence to the contrary, I think that assuming closed-source code has the same statistical shape as open-source code, especially given the volume to which crater has access, is a fairly safe thing to do.
A clearer philosophical decision about what the prelude is and should be is certainly worth doing regardless of whether its contents change.
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.
In the absence of raised evidence to the contrary, I think that assuming closed-source code has the same statistical shape as open-source code, especially given the volume to which crater has access, is a fairly safe thing to do.
I think this is probably not that true, since AFAIK crater has overwhelmingly more library crates than binaries. My experience is that this distribution isn't the same for private code.
That said, I don't know that we can do much here. At the end of the day, we use the data we have access to.
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
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.
I feel like a thing that's missing here is a general policy for what we consider prelude-worthy. We don't have one right now, and my gut feeling is that this RFC goes many steps too far in expanding the prelude. Having an actual policy we can verify proposals against seems to be better than having a grab bag of things that people think should be in the prelude.
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, it would help future edition changes make choices about the prelude, even if it's just a ponce... a policy only used once, I mean. We should be later able to revisit and see if the rationales were Bad, Actually. ( I am speaking from an assumption that, by sheer weight of inertia, people will think additions are good and subtractions are bad, so there will be a felt need of active justifications to undo a decision but not to make further expansive decisions. )
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.
👍 to this. Without an agreed philosophy I suspect this will get bogged down substantially by all the details, since every single possible edition addition (doh!) could be its own long conversation.
Operationally, to get it in for the edition, I think it would make sense to focus this to a small number of minimally-controversial changes that very clearly fit the philosophy and need to be edition tied. Then future RFCs can be about specific additions to focus the conversation about 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.
I think it would make sense to focus this to a small number of minimally-controversial changes that very clearly fit the philosophy and need to be edition tied
Strong agree.
I'd imagine this goes along the lines of:
- Figure out a policy (disallow discussing individual items until we have one, perhaps revert to pre-rfc until we have one)
- Figure out items which the policy clearly applies to
- People can disagree with the policy or disagree that the policy applies to an included element.
I'm not sure if
|
|
||
- `std::ops::Not`: for chaining purposes, it is sometimes useful to have an trailing `.not()` call rather than the prefix `!` operator. Therefore, [it has been suggested](https://internals.rust-lang.org/t/pre-rfc-adding-bool-not-method/13935) that the `Not` trait which brings that method in scope could be added to the prelude. This RFC author feels this use case is better served by adding an inherent impl to `bool`, since that serves the majority of the same use case with less complexity. | ||
- `std::fmt::Display`: users of this trait generally don't need to import it because the `ToString` trait which relies on the `Display` implementation is already in the prelude. Implementers of the `Display` trait however need several other items from `std::fmt` to do so; therefore, just importing `Display` into the prelude does not help much. This RFC suggests adding `fmt` to the prelude to improve this use case. | ||
- `std::fmt::Debug`: similar to `Display`, although there's no `to_debug()`. However, usage will usually go through `dbg!()` or the formatting mechanism (as a `{:?}` format string). |
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.
Caveat: The fmt
method will collide where the user originally only imported one of the traits.
E.g:
use core::fmt;
use core::fmt::Display;
struct MyStruct(u32);
impl Display for MyStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f) // Just delegate to the inner impl
}
}
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.
I'm not sure I understand what you're getting at. That code seems to compile just fine?
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.
If you have a prelude that then implicitly imports Debug
, this will then fail:
// The prelude with Debug:
mod prelude {
pub(super) use core::fmt::Debug;
}
// Prelude import
use prelude::*;
use core::fmt;
use core::fmt::Display;
struct MyStruct(u32);
impl Display for MyStruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f) // Just delegate to the inner impl
}
}
If we're adding std modules (but I'm not sure if we should), I'd add |
I like a lot of what this RFC proposes, but I think it might be easier to split it into multiple RFCs. I think it would be easier to think about and discuss trait additions separately from other additions, since trait additions would be 2021-specific, and have separate concerns. Additionally, I think that the non-trait additions ( As an example, I think I personally would like Also, each prelude-addition RFC could be very streamlined, so doing an RFC for each might not be so much extra work. |
I agree that while the traits are all an easy "yes", the rest is a lot of "oh, uh, maybe... not?" |
I wonder, for things like this, whether it would make sense for more of the WGs to define their own "sub-preludes" in crates, like for async things there's https://docs.rs/futures/0.3.13/futures/prelude/index.html A CLI one of those could be great, for example, and be more aggressive about including lots of little things. Like I don't think And that would avoid the obvious objections from other domains that just never use files, or don't want |
|
||
The compiler currently brings all items from `std::prelude::v1` into scope for each module (for code using `std`). Crates that declare usage of the 2021 edition will instead get items from `std::prelude::edition2021` imported into scope. | ||
|
||
This RFC proposes to add the following traits to `std::prelude::edition2021`, but not `std::prelude::v1`: |
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.
While most users will never see it, it's still odd to have the modules be named v1
and edition2021
. Is it viable to rename v1
to edition2015
and have edition2018
and v1
(for compatibility) as aliases?
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.
I've updated this to explain the plan a bit more, see also the initial implementation PR. Does that make things sufficiently clear?
|
||
> `FromIterator::from_iter()` is rarely called explicitly, and is instead used through `Iterator::collect()` method. See `Iterator::collect()`'s documentation for more examples. | ||
|
||
However, it is reasonably common that type inferencing fails to infer the full type of the target type, in which case an explicit type annotation or turbofishing is needed (such as `iter.collect::<HashMap<_, _>>()` -- the type of the iterator item is available, so wildcards can be used for this). In these cases, `HashMap::from_iter(iter)` can be a more concise and readable way to spell this, which would be easier if the trait was in scope. |
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.
???
use std::iter::FromIterator;
use std::collections::HashMap;
fn main() {
dbg!(HashMap::from_iter(vec![(1_u64, 2_u64), (3, 4)].into_iter()));
}
Compiling this gives an error:
error[E0282]: type annotations needed
--> src/main.rs:6:10
|
6 | dbg!(HashMap::from_iter(vec![(1_u64, 2_u64), (3, 4)].into_iter()));
| ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `S` declared on the struct `HashMap`
error: aborting due to previous error
So no you still need to write HashMap::<_, _>::from_iter(iter)
to set S = RandomState
.
@ChrisJefferson I collected some evidence about this a while ago, if it helps. |
Could you shortly elaborate and clarify what I am missing? |
Trivially if at all. This is not a concern here.
The language shouldn't rely on people using r-a. Also, this won't help in all cases. For example, the cases like the |
The motivation/drawbacks talks about adding traits but doesn't justify adding types. I'm not wholly against adding types to the prelude but I do feel they need more discussion. What are the downsides? If there are none, why aren't all std types in the prelude so long as they don't clash with each other? How much of an inconvenience is importing types? Could this inconvenience be reduced in other ways? Reading through the explanations given for each item, I think this sums up the various motivations:
I think it would be great if these had more discussion. I wonder if putting more types in the prelude deserves a separate RFC? Especially as the motivation says adding types does not need an edition boundary. |
The |
It doesn't work for that particular example with the three-argument |
Started a std/core PR for the edition traits in rust-lang/rust#82781. This failed pretty quickly because the minifier crate which rustdoc appears to rely on defines a custom |
@djc We’ve tried this before when stabilizing these traits in rust-lang/rust#49305, conclusively established that breakage is too widespread in this case, and reverted in rust-lang/rust#49518. This is the entire reason we’re discussing edition-specific preludes. I don’t understand the point of rust-lang/rust#82781, and especially of GuillaumeGomez/minifier-rs#65. Forcing the entire ecosystem through this transition would be a lot more painful than it’s worth. |
@scottmcm it was already discussed that there doesn't seem to be strong connection between knowing some part of Rust and being in prelude. If you want to find out the truth, ask the person these questions
Frankly, I suspect the person doesn't know that there's |
I related the same experience on the IRLO thread.. To save people the click, my uncertainty came from some combination of not seeing the pattern before and it not being imported while living next to things like I haven't reread the book in awhile, but at least at the time, these weren't scenarios covered by the introductory materials. When it comes up on URLO today, I'm likely to suggest this article by Niko instead, and/or just suggest |
@QuineDot thank you for thoughtful comment!
This could be used as justification for adding it to prelude. I'm still not sure, but at least it's something interesting. Of course this can be also solved by introducing new module(s) or just writing better doc. Actually the article you point to seems to describe what is the most important use of |
Consensus in the libs team meeting was that the breakage might have been reduced in the 3 years since the previous attempt, since these traits have now been stable in std for quite a long time, and that it might be worth assessing the amount of damage. In addition, the PR also adds the
Are you saying we should not add these traits to the prelude at all, or that we shouldn't bother assessing the breakage and just focus on making sure lints/cargo fix provide a good experience? |
The first one says this:
The second one seems like: I don't think anyone's saying we should force the entire ecosystem through anything. |
Some alternatives to adding new types or functions to the prelude:
|
Repeating my comments from discord: this may have been fixed by rust-lang/rust#77862, but I don't know without testing. If someone wants to make a PR removing |
@jyn514 checking now if it works. |
How about removing |
This should probably be closed unless there's desire to use this PR for 2024? |
As I understand it, the non-trait changes do not need to wait for an edition change, so we could just move forward with the remaining changes (also some further discussion and RFC updates are warranted). I'll see if I can get to it soon -- if someone else wants to take over, that'd be fine too. |
After talking with Josh on zulip would you maybe want to update the title & doc to indicate we want to reuse this issue for the 2023 edition? If you are still interested in maintaining this PR. |
I don't think it makes sense to reuse this for 2024 edition, given that most of the trait contents (which are the only parts that really need an edition as I understand it) moved into RFC 3114. I'll just close this for now, since I am not currently motivated to work on this. |
Here's a first take on the plan to update the prelude for 2021 edition.
Rendered
March 3 feedback summary