-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Functional record update should respect privacy (or consume a non-Copy source) #21407
Comments
Note that, as @glaebhoerl discovered, you can also explicitly consume pub fn free_and_use<T>(t: Vec<T>) -> Vec<T> {
let result = Vec { ..t };
drop(t); result /* or drop(result); t */
} |
💣 |
Is |
It is. There's the potentially-useful case where some of the members are private, and FRU allows you to update the public ones. Of course it should consume the source even then. |
P-backcompat-lang, 1.0 beta |
In my opinion the problem here is the privacy violation. The idea is that |
That was my opinion as well (but my favored solution isn't minor). |
When I initially saw this problem, I did not see it as a privacy violation, for the (obvious?) reason that since no private members of I think this line of thinking is analogous to @arielb1's outline of the useful case where FRU allows one to update the public members of a type and silently move the private ones as well, via I originally was going to try to explain my point of view via analogy with something from hygienic macros: If I were to define (and export) a macro within mod foo {
pub struct Bar { ... }
#[macro_export_or_whatever]
macro_rules! bar_update_xy {
($x:expr, $y:expr, $b:expr) =>
{ Bar { x: $x, y: $y,
other_1: $b.other_1,
[... manually list other fields here ...]
other_k: $b.other_k } }
}
}
let b1: Bar = ...;
let b2 : Bar = bar_update_xy!(new_x(), new_y(), b1)); then it should, in principle, not be a privacy violation to use Then I realized the crucial problem with that kind of analogy: This latter point, that providing support for FRU should not be something that is silently attached to a type like So, as I see it, we can either:
|
I don't want to make a big fuss about it, but I do want to note, again, that our "deadlines" are entirely self-imposed, and that under these circumstances "we don't have time" is slightly odd, because we can make time, any time we want. The blanket refusal to even contemplate doing that - even in light of new information - and to weigh the tradeoffs on their own merits is something I still don't really understand. That out of the way, an additional possibility, let's call it 6., for @pnkfelix's list:
|
@glaebhoerl Sure, hypothetical show-stopper issues could cause us to revisit our self-imposed schedule. I personally don't think that this issue, on its own at least, provides sufficient motivation for schedule revision. I admit that your draft RFC seems like it addresses a host of issues, so maybe all of them taken in unison would be a different story. (But then again, that's not even my call to make.) |
There were a couple more options that I should have put on the list, for completeness, but overlooked.
|
Also, I just wanted to mention: when I wrote my comment #21407 (comment) 6 hours ago, I came to the keyboard thinking that the FRU support for adding new private fields to But after some reflection in the hours since, supporting that use case does not seem as important to me. Here is why: It is relatively easy for a developer who wants to provide that sort of extensible abstraction can still do it, by factoring the type into a all-public front-end with a single public field that holds the all-private back-end, like so: fn main() {
use foo::Foo;
let f1 = Foo::new(13, 14);
let f2 = Foo { x: 23, y: 24, ..f1 };
println!("f2: {:?}", f2);
}
mod foo {
pub struct Foo {
pub x: u8,
pub y: u8,
pub private_data: FooPrivate,
}
pub struct FooPrivate {
_other_1: u8,
_other_2: u8,
// developer is free to add new fields here
}
...
} So, given that there exists a reasonable pattern to bring back usable FRU even under the option "(3.) change FRU into a non-hygienic expansion into the record construction form with all fields listed, in the sense that |
I think that "has any private field" is a decent way to handle abstractness (you can always add a private unit field). On the other hand, Rust supports trait bounds of types – these should handle roles just fine – you shouldn't be able to coerce past a trait bound. By the way, this is somewhat subtle, because coercing |
I mean, Rust already has a mechanism for ensuring representation-abstraction – private fields – which are semantic (they are handled after type-checking, we probably want to handle them during it, but they definitely aren't handled syntactically or during resolution). It is just that FRU currently accesses them improperly. Also, it doesn't have much to do with e.g. roles – |
Another alternative came to me while I was drafting an RFC about this. (But its an alternative that I do not particularly like.)
|
@pnkfelix That would leave the vulnerability intact in the case where the type has both public fields and private |
@glaebhoerl yep. Library authors would have to factor their structures very carefully. (I described the drawback you mention in the RFC I posted shortly after you wrote your comment, though I did not include the detail of having the private fields be Just to be clear, I'm not saying I prefer (8a) or (8b); I'm just trying to be complete in my exploration of the solution space. |
Repurposed as the tracking issue for rust-lang/rfcs#736 |
I'll just go snag my commit |
This is RFC 736. Fix rust-lang#21407.
Tracking issue for: rust-lang/rfcs#736
Old Description:
Functional record update does not mark the source as consumed, even if does not implement Copy. This means that e.g. the source's destructor will eventually be run, so the following code prints
["Heap Spray"]
:The text was updated successfully, but these errors were encountered: