Skip to content
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

Forget marker trait #3782

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

Ddystopia
Copy link

@Ddystopia Ddystopia commented Mar 1, 2025

Add a Forget marker trait indicating whether it is safe to skip the destructor before the value of a type exits the scope and basic utilities to work with !Forget types. Introduce a seamless migration route for the standard library and ecosystem.

Rendered

Pre-RFC thread

@Noratrieb Noratrieb added T-lang Relevant to the language team, which will review and decide on the RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC. T-types Relevant to the types team, which will review and decide on the RFC. labels Mar 1, 2025
@clarfonthey
Copy link

clarfonthey commented Mar 1, 2025

This definitely seems to be a reasonably motivated RFC, although it's going to definitely be something I'll have to read through a lot more closely to fully comment on it. A few first impressions:

  1. I don't think that Forget as a name is very good for a marker. Forgetting something as a verb is fine, but as… an adjective? Not really. I think that at least Forgettable would be a better name, although something like ForgetSafe would probably be more in line for this trait, in line with UnwindSafe.
  2. While I appreciate the effort to be as accessible as possible by explaining everything, including concepts like RAII guards which not everyone might be familiar with, your desire to explain everything in advance of using them means that the RFC itself is difficult to follow. For example, the motivation section doesn't really get into the actual motivation until it provides multiple code blocks and examples. This makes the entire thing difficult to follow, since I can't easily look at the top of the section and understand what it's about. Chronological order is good for explaining the prior art, but not for the motivation, IMHO.
  3. On that note, I don't think that the current guide-level explanation is very good for a guide-level explanation. It feels very structured like an FAQ, which I don't think is good for the guide level: you're explaining to someone what the feature is outright, and not just answering their questions about it.

Again, I do want to go through this a bit more closely before fully commenting on it, but I think that you definitely need to go back and make the primary motivation for this crystal clear: because of forget, invariants in types cannot be violated by borrowing wrappers. This was not a problem before async code, because you could effectively ensure that function calls happen to completion (minus poisoning semantics) and nothing is ever left in an invalid state. However, with async code, you now have the issue that you can "forget" to finish part of a full function call via forgetting its Future, which leaves things in an invalid state.

Generally, the only way to deal with this is to make these calls unsafe and tell people to pinky-promise they run the future to completion, but it would be nice to be able to have a safe way to do this instead.

@kennytm
Copy link
Member

kennytm commented Mar 2, 2025

@clarfonthey We do use verbs as trait name when the only purpose of the trait is to support that verb, think of Send or Copy or Borrow or std::iter::Extend.

@kornelski
Copy link
Contributor

This is definitely a much desired feature that would enable new safe design patterns in Rust.

Having a gradual migration path with default_generic_bounds sounds reassuring.

I appreciate all the links to the prior art.

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation

The core goal of `Forget` trait, as proposed in that RFC, is to bring back the "Proxy Guard" idiom for non-static types, with `async` being the primary motivation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand correctly that all !Forget types need to have a lifetime bound to have any effect? Does it ever make sense to have a !Forget type that has no lifetime? (like an integer)

Copy link
Contributor

@Jules-Bertholet Jules-Bertholet Mar 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That’s correct. Non-Forget types must be dropped before their lifetime ends

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the perspective of use cases and definitions, it really makes little sense to have !Forget and 'static together. But I am not opposed too, it may have some other benefits which I am not aware of / or implementational / migrational benefits.

# Unresolved questions
[unresolved-questions]: #unresolved-questions

- [ ] Maybe the name `Forget` is misleading, as its core is around the `unsafe` guarantee of borrowed resources and the destructor. `IndirectPin`?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not mix it with Pin. Pin is an advanced concept needed only for certain niches, so for many users it may not clarify the meaning, but rather connect it to something they're unfamiliar with. There are also proposals for integrating Pin more into Rust's syntax, so the Pin itself may become even less visible in the future.

I assume that Forget may appear more often in the API surface. It may eventually be easier to teach Pin in terms of !Forget than the other way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-lang Relevant to the language team, which will review and decide on the RFC. T-libs-api Relevant to the library API team, which will review and decide on the RFC. T-types Relevant to the types team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants