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

RFC: core::mem::replace_with for temporarily moving out of ownership. #1736

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions text/0000-mem-replace-with.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
- Feature Name: mem-replace-with
- Start Date: 2016-09-01
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

Add a new function to `core::mem` (and thus `std::mem`), `replace_with`, which
invokes a closure that takes temporary ownership over some value behind a
mutable reference.

This is similar to the functions provided by [the take_mut crate](https://crates.io/crates/take_mut).

# Motivation
[motivation]: #motivation

A common pattern, especially for low-level programmers, is to acquire ownership
of a value behind a reference without immediately giving it a replacement value.
Copy link
Member

Choose a reason for hiding this comment

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

Can you include a simple example of this pattern and the problem it causes?


`core::mem::replace_with` allows such thing by generalizing
`core::mem::replace`, to allow the replacement value being generated by a
closure and even depend on the old value.

Unfortunately, there are no safe implementation in the standard library,
Copy link
Member

Choose a reason for hiding this comment

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

s/are/is/ to match "implementation". Or alternatively, "the standard library doesn't provide any safe implementation"

leading some Rust users to either reimplement a safe interface for such a
feature (often flawed due to unwinding, see below) or use things like
`ptr::read`.

This should standardize the ecosystem with respect to that.

# Detailed design
[design]: #detailed-design

A complete implementation can be found [here](https://github.com/rust-lang/rust/pull/36186). This implementation is pretty simple, with only one trick which is crucial to safety: handling unwinding.
Copy link
Member

Choose a reason for hiding this comment

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

Should we just include the code here? The implementation is short, and including makes the RFC self-contained.


Without handling unwinding, the closure could unwind and invoke destructors on
the invalid value. Thus we use "exit guards" which are placed in the stack
frame (as a variable) and holds a destructor exiting the program.

This behavior is rather specific and it is not certain that it will be kept in
the future, so we leave the unwinding behavior unspecified for now.

# Drawbacks
[drawbacks]: #drawbacks

It expands the core library slightly, and the panic semantics might not be
clear for everyone.

# Alternatives
[alternatives]: #alternatives

1. Specify the unwinding behavior to abort.

2. Use `catch_unwind` and print an error on unwinding (in libstd).

3. Require `T: Default` and replace the value as such on panic, so we are sure the dropping value is in fact valid.

4. Leave it out of the standard library.

# Unresolved questions
[unresolved]: #unresolved-questions

Are there currently any crates relying on invariants that this will break?