-
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
Placement protocol should not consume Placer #1286
Comments
The issue description isn't clear about whether it is asking for the argument to be Obviously some use cases would not be satisfied by requiring (This should mesh in with the Allocator design, where I am currently planning to use |
Being one who proposed it initially, I’m personally very strongly in favour (of |
That's because I haven't made up my mind on that yet. One such alternative would be leaving the signature to be |
Doesn't malloc use |
I don't really know what you mean. If this is about "allocators that can't be behind a |
You need to be very careful about evaluation order and panic safety, as well as forcing the placer to be used:
How do we handle panics in for just
This cannot be allowed, would it leave an unitinialized slot? |
That's what All of this is completely independent of whether the first step consumes the |
@bluss I see what you mean, but I don’t think it is a problem, because the protocol explicitly addresses preconditions for panic safety:
-- Last paragraph of EDIT: actually it might be worse than I initially thought, because destructors are safe to not run now ( e.g. let something = Something::new();
let place = something.make_place();
// place relies on destructors running for panic safety (e.g. decreasing length in vector case)
mem::forget(place);
panic!();
// destructor for Something reads uninitialized data? |
@nagisa Thanks, looks like I didn't realize this was well enough covered, it's hopefully a matter of adjusting the mockup implementations and it should be possible to solve with the protocol. Not sure the protocol is at risk because of |
Just a note that the way to make |
FWIW, I created one for TypedArena and had no issues with consuming the |
Yes, because the Placer is a |
I can't fully articulate this, but |
Ugh, you're right, if it takes Luckily, this is a local change, it doesn't affect the type (so it doesn't affect callers and data strutures) and it is only necessary if you want to use placement syntax. Still sad. And I had all but convinced myself that |
If you have an &Arena, you cannot call any method on it that requires On Sun, Oct 4, 2015, 7:31 AM rkruppe [email protected] wrote:
|
Probably the only thing you can’t do with |
The trait would still be implemented for |
@rkruppe I was playing around with this last night. I'm a little worried that we would not want to make this change without higher kinded types (HKT). But, my opinion has revised somewhat over the course of writing this comment and trying to make demonstrative examples. Maybe we should make the change you suggest, under the expectation that it might cause some pain in the short term, but in the longer term it is the "right thing" and will yield better code once we do have HKT (assuming that comes in the future). (Explanation follows) In particular: we want the pub struct VecEndPlace<'a, T:'a> {
v: &'a mut Vec<T>,
}
impl<'a, T> Placer<T> for &'a mut Vec<T> {
type Place = VecEndPlace<'a, T>;
fn make_place(self) -> Self::Place {
self.reserve(1);
VecEndPlace { v: self }
}
} If we try to change the impl<T> Placer<T> for Vec<T> {
type Place<'a> = VecEndPlace<'a, T>; // <-- needs HKT!
fn make_place<'a>(&'a mut self) -> Self::Place<'a> {
self.reserve(1);
VecEndPlace { v: self }
}
} Now, there is a way to get this to While trying to fix this, I tried having it pass impl<'a, T:'a> Placer<T> for &'a mut Vec<T> {
type Place = VecEndPlace<'a, T>;
fn make_place(&mut self) -> Self::Place {
self.reserve(1);
VecEndPlace { v: *self }
}
} Unfortunately that does not compile, due to a lifetime inference failure, shown here: http://is.gd/35E1lk Frustrated by the latter, which seems like a case of "this should obviously work", I resorted to a transmute of the impl<'a, T:'a> Placer<T> for &'a mut Vec<T> {
type Place = VecEndPlace<'a, T>;
fn make_place(&mut self) -> Self::Place {
self.reserve(1);
VecEndPlace { v: unsafe { ::std::mem::transmute::<&mut Vec<T>, &'a mut Vec<T>>(*self) } }
}
} This does "work" unsoundly: http://is.gd/KvlwI8 ... but it scares the hell out of me because it is unsound.
(One option that I did not try: remove the lifetime parameter from If you or others have another way to address this problem, I would appreciate you demonstrating it by modifying the following running example (which uses the current Anyway, as I said at the beginning, my opinion has changed somewhat over the course of writing this comment. (Originally I thought that this example was a deal-breaker for the change you suggest, but then I did the experiments above. I am willing to use workarounds, and continue doing |
It seems we are in violent agreement. Your first option is basically everything I want. I'm just thinking beyond that, how real code will look when using placement syntax liberally, and I'm unhappy that it will probably be littered with As I said, I am not insisting on Admittedly, it makes for a rather strange protocol if the signature says |
If we want |
That's a good point, and AFAIK the first solid argument for by-value |
@arielb1 I don’t see how not consuming |
Actually |
Is |
Some relevant IRC discussion. |
Could someone list the arguments for making |
Its taking |
@nagisa you sure? If |
Ah, of course. I’m dumb, and shouldn’t comment on things without checking them again if I hadn’t seen them for a month. Sorry! |
@Stebalien I think it hasn't changed much since @rkruppe wrote the description of the issue. Namely this sentence:
You've already noted that you would prefer
... so the remaining item is allocators that aren't Sad to admit as the author of the current Allocator RFC, I have not yet taken the time to personally experiment with mixing together placement-in and allocators in the manner described elsewhere. I hope to get a chance to do so, but I also don't mind when our awesome community beats me to the punch when it comes to things like this. :) |
Actually, allocators are why I first asked. As noted in #1401, let b = BoxPlace(HEAP) <- value; However, we can also do something like let b: Box<_> = HEAP.alloc() <- value Which gets rid of the problem of taking |
Methods have auto-ref, so obviously they would address this (that's exactly why |
try!(vec.insert(n)) <- value; which reserves a slot and moves things to the right. The placer does nothing and neither does the place (which simply points to the free slot) unless it is dropped in which case it moves things back and reduces the length by one. Since the placer cannot allocate memory if you want to do error handling, the placer would have to manually track if it has already been called once and abort the process in this case. Unless |
It also prevents the Placer and Place from being the same object which is what one wants if the real |
Or another example: try!(Rc::with_pool(allocator)) <- obj; In this case it is impossible to call the Placer twice because the first call consumes the memory pool. |
These are nice example. I could quibble a bit with each, but collectively and together with the examples earlier in this discussion, they make pretty clear that by-value self can also be valuable. Additionally, So, I hereby officially propose shifting the focus of this issue from "make |
…sakis Remove all unstable placement features Closes #22181, #27779. Effectively makes the assortment of placement RFCs (rust-lang/rfcs#470, rust-lang/rfcs#809, rust-lang/rfcs#1228) 'unaccepted'. It leaves `box_syntax` and keeps the `<-` token as recognised by libsyntax. ------------------------ I don't know the correct process for unaccepting an unstable feature that was accepted as an RFC so...here's a PR. Let me preface this by saying I'm not particularly happy about doing this (I know it'll be unpopular), but I think it's the most honest expression of how things stand today. I've been motivated by a [post on reddit](https://www.reddit.com/r/rust/comments/7wrqk2/when_will_box_and_placementin_syntax_be_stable/) which asks when these features will be stable - the features have received little RFC-style design work since the end of 2015 (~2 years ago) and leaving them in limbo confuses people who want to know where they're up to. Without additional design work that needs to happen (see the collection of unresolved questions later in this post) they can't really get stabilised, and I think that design work would be most suited to an RFC rather than (currently mostly unused) experimental features in Rust nightly. I have my own motivations - it's very simple to 'defeat' placement in debug mode today and I don't want a placement in Rust that a) has no guarantees to work and b) has no plan for in-place serde deserialisation. There's a quote in [1]: "Ordinarily these uncertainties might lead to the RFC being postponed. [The RFC seems like a promising direction hence we will accept since it] will thus give us immediate experience with the design and help in determining the best final solution.". I propose that there have been enough additional uncertainties raised since then that the original direction is less promising and we should be think about the problem anew. (a historical note: the first mention of placement (under that name - uninit pointers were earlier) in an RFC AFAIK is [0] in late 2014 (pre-1.0). RFCs since then have built on this base - [1] is a comment in Feb 2015 accepting a more conservative design of the Place* traits - this is back when serde still required aster and seemed to break every other nightly! A lot has changed since then, perhaps placement should too) ------------------------ Concrete unresolved questions include: - making placement work in debug mode [7] - making placement work for serde/with fallible creation [5], [irlo2], [8] - trait design: - opting into not consuming the placer in `Placer::make_place` - [2] - trait proliferation - [4] (+ others in that thread) - fallible allocation - [3], [4] (+ others in that thread) - support for DSTs/unsized structs (if at all) - [1], [6] More speculative unresolved questions include: - better trait design with in the context of future language features [irlo1] (Q11), [irlo3] - interaction between custom allocators and placement [irlo3] [0] rust-lang/rfcs#470 [1] rust-lang/rfcs#809 (comment) [2] rust-lang/rfcs#1286 [3] rust-lang/rfcs#1315 [4] #27779 (comment) [5] #27779 (comment) [6] #27779 (comment) [7] #27779 (comment) [8] rust-lang/rfcs#1228 (comment) [irlo1] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789 [irlo2] https://internals.rust-lang.org/t/placement-nwbi-faq-new-box-in-left-arrow/2789/19 [irlo3] https://internals.rust-lang.org/t/lang-team-minutes-feature-status-report-placement-in-and-box/4646
Closing as this is moot now. |
This came up in the discussion of #1228, but it's mostly independent from the syntax change proposed there. Currently creating a
Place
for "placement box" will consume the value that produces the place (the one that's written out in the placement expression, i.e.PLACE
inbox (PLACE) EXPR
). This hasn't been an issue so far because the only implementation (in std and, as far as I can tell, on GitHub overall) inExchangeHeapSingleton
which isCopy
. That type (and its public name,boxed::HEAP
) is hanging by a thread though,box thing
is widely preferred toin (HEAP) thing
orin HEAP { thing }
orHEAP <- thing
or any variant of that.Some hypothetical types that would implement
Placer
in the future (such as&Arena
and the results ofmap.entry(k)
,vec.back()
) would likely beCopy
or inherently "one-off", but other possible uses of placement box would be ruled out by takingself
. Examples raised in #1228 arevec <- thing;
(instead ofvec.push(thing)
),set <- thing;
and (disclaimer: my example and pet interest) allocators that can't be behind a&
reference.@pnkfelix said:
The text was updated successfully, but these errors were encountered: