Allow FRU for types that are Copy OR types that are not Drop
Nobody has claimed this yet.
- Dominant language
- Markdown
- Stars
- 6.6k
- Forks
- 1.7k
- Avg merge
- 16h 14m
- Merged PRs (30d)
- 1
Description
RFC 736 altered Functional Record Update to treat FRU as equivalent to a full struct literal and disallow its use when the expansion would result in referencing a private field. This was done to fix a problem where this can break invariants that the struct needs to preserve (e.g. that a ptr field is unique).
This solution is overly restrictive. It prevents patterns that would otherwise be perfectly okay, such as
mod foo {
#[derive(Debug,Copy,Clone)]
pub struct Bar { pub a: u8, b: &'static str }
pub fn make_bar(a: u8, b: &'static str) -> Bar {
Bar { a: a, b: b }
}
}
fn main() {
let s_1 = foo::make_bar(1, "one");
//let s_2 = foo::Bar { a: 2, ..s_1 }; // this is eqiuvalent to
let mut s_2 = s_1; // make a copy
s_2.a = 2;
println!("s_1: {:?}, s_2: {:?}", s_1, s_2);
}
In this case the struct is Copy, so I can freely make a copy and change public fields, which is equivalent to what FRU is doing.
This is also true of structs that are not Copy but are also not Drop. Because of the lack of a destructor, moving fields from one instance of the struct to another is perfectly safe (as it's equivalent to moving the whole struct and then modifying the public fields).
As it turns out, the actual restriction here that we care about is whether it's legal for us to either copy the struct or move out of it. This means the struct has to either implement Copy or it has to not implement Drop. For any struct that is Copy, FRU is trivially safe because I can just copy the struct and update the public fields. For any struct that is not Drop, FRU is also safe because I can move the struct as a whole and then update the public fields.
I actually think it would be perfectly safe to go even farther and adopt Alternative 1 from RFC 736, which says that FRU should be treated as consuming the old struct value. This should be perfectly safe, with Foo { a: a, b: b, ..old_foo } being equivalent to { let mut foo = old_foo; foo.a = a; foo.b = b; foo }. But there is a bit of a question about the precise semantics; for example, if all fields of a struct are Copy and pub, and I use it with FRU, should it actually consume the struct or merely copy all of the fields? Based on that, I'm willing to defer that question until later (although I suspect the answer should be along the lines of copy fields if possible, and fall back to consuming the whole struct otherwise).
tl;dr - Adjust FRU to merely require that the source type be Copy or not be Drop, instead of looking at field visibility.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading RFC 736 and the examples in this issue. Compare the current field-visibility restriction with the proposed Copy-or-not-Drop rule, then resolve the open semantics around consuming versus copying the source value. Done means the RFC or issue records an agreed precise behavior for FRU.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100