-
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 in/box refinement #1426
Conversation
[unresolved]: #unresolved-questions | ||
|
||
Does `Place::pointer` need to return an `&mut T` (or some other special pointer) | ||
to ensure RVO? Should it return `std::ptr::Unique`? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I almost feel like Unique<T, A>
should be Place<T, A>
's "filled" counterpart, if both were structs and A
described how the allocation should be handled.
To expand on the special HIR node idea: PLACE <- EXPR // gets desugared into:
ExprEmplace(Placer, PLACE, EXPR) box EXPR // gets desugared into:
ExprEmplace(Boxer, ExprCall(Default::default, []), EXPR) This way, we could guarantee that 0 unnecessary copies are being made, DST support can be added without having to come up with impossible source desugarings and, probably the best part, we can employ a simpler form of rust-lang/rust#27292 only for If we have an expected type, i.e. Otherwise, it's either a legitimate error, or our Thankfully, the unsizing coercions relevant here only involve structs (and We can take the most conservative stance and replace all type params in Then, we require that E.g. for Unlike rust-lang/rust#27292, this also works if you replace |
Why would the Allocator be constructed in the desugaring and the Boxer have an Allocator parameter? One can simply impl<T, A> Boxer<T> for XYZ<T, A> where A: Allocator+Default Having the Boxer trait know anything about allocators is completely unnecessary and a huge restriction. |
@eddyb Doesn't move_val_init already do what you want? Except that move_val_init doesn't unconditionally get translated to a memcpy for some reason. |
@mahkoh The problem is that you can't desugar to |
@mahkoh, how is this a restriction? impl<T, D, B> Placer<D, B> for T
where T: Allocator,
B: Boxer<D, T>
{
type Place = B::Place;
fn make_place(self) -> Self::Place
where Self: Sized
{
B::make_place(self)
}
} Which, in turn, lets us do the following: impl<T, A> Boxer<T, A> for Box<T, A> where A: Allocator { /* ... */}
let boxed: Box<_> = CustomAllocator::new(options) <- thing; |
The Boxer implementation can acquire an allocator (if it even needs one) by means other than |
@mahkoh, sorry, hit enter too soon. See my updated post. |
@Stebalien All of this can be done without the restrictions imposed by having Boxer know about allocators. E.g. let a: Box<_, A1> = box val; // where A1: Default
let a = Box::with_pool(CustomAllocator::new(options)) <- thing; |
The first line is equivalent to let a = Box::with_pool(A1::default()) <- val; |
@mahkoh, which means that one has to implement a new |
It doesn't support
The object might want to use a globally shared allocator stored in a static variable or might want to construct an allocator with custom options. |
And where is the problem with that? |
You also don't need a "new" Placer. See the following pseudocode struct Box<T: ?Sized, A>
where A: Allocator,
{
alloc: A,
val: *mut T,
}
struct BoxBuf<T, A>
where A: Allocator,
{
alloc: A,
val: *mut T,
}
impl<T, A> Boxer<T> for Box<T, A>
where A: Allocator+Default,
{
type Place = BoxBuf<T, A>
fn make_place() -> BoxBuf<T, A> {
let mut alloc = A::default();
/* ... */
BoxBuf {
alloc: alloc,
val: val,
}
}
}
impl<T, A> Placer<T, Box<T, A>> for BoxBuf<T, A>
where A: Allocator,
{
type Place = Self;
fn make_place(self) -> Self { self }
}
impl<T, A> Place<T> for BoxBuf<T, A>
where A: Allocator,
{
type Owner = Box<T, A>;
fn pointer(&mut self) -> *mut T { self.val }
unsafe fn finalize(self) -> Box<T, A> {
Box {
self.alloc,
self.val,
}
}
} It seems that what you actually want is a default implementation of impl<T, P> Placer<T, <P as Place<T>>::Owner> for P
where P: Place<T>,
{
type Place = Self;
fn make_place(self) -> Self { self }
} |
To be quite honest, I don't think there is a need for the Placer trait at all. The only use it has is that it can be implemented for Allocators so that you can use the This can also be done with the Place trait alone: Box::with_pool(HEAP) <- val So the only advantage seems to be the shorter syntax. The most common cases are
Neither of these cases is served by the Placer trait. There is also the problem with that Allocators have no idea how to construct containers and that the Placer implementation for Allocators is limited by this. This inversion then leaks into the placement traits by having them suddenly depend on Allocators (this RFC). Apart from this forced dependency, allocators and placement traits are orthogonal. |
@mahkoh also consider |
@eddyb The first one doesn't work because Placer consumes self. I'll think a bit about the second one. |
@mahkoh it would work if |
@eddyb Is there a reason that |
@eddyb, note, as of this RFC, it has to be @mahkoh, FYI, it's Re your previous comments, this really just comes down to the common. With the system proposed in the RFC, one would write: let boxed: Box<_> = HEAP <- value;
let object = Object::from_object_pool() <- value; With your system, one would write: let boxed: Box<_> = Box::with_allocator(HEAP) <- value;
let object: Object = box value; I'll try to come up with a way to make both cases simpler. |
@eddyb I see. Well, I'm not bothered much by the Placer trait itself. It's the idea to implement it for Allocators that seems wrong. |
Also, |
@Stebalien Well that could be made unsafe and the compiler implementation of emplace can do the right thing (TM). @mahkoh Another "nice" example: |
Just go full
I'm aware.
In the first case you don't have to write the type on the lhs because let boxed = Box::with_allocator(HEAP) <- value; |
|
||
## Allocators | ||
|
||
Boxer's now make Places from Allocators. This means that any type implementing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Boxer’s/Boxers/?
/// | ||
/// If evaluating EXPR fails, then the destructor for the | ||
/// implementation of Place is run to clean up any intermediate state | ||
/// (e.g. deallocate box storage, pop a stack, etc). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pop a stack frame
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
All in all, everything related to |
Replying again here as my comment was swallowed in the push. IIRC, the original motivation of |
1. Don't have Boxers take Allocators. 2. Explain why we need the Placer trait.
All (specifically, @nagisa), I've updated the proposal to move the allocator related logic out of the |
unsafe fn finalize(self) -> Self::Owner; | ||
} | ||
|
||
/// All types implemeinting this trait can be constructed using using the `box` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: "implemeinting" --> "implementing"
Can someone summarize the state of this RFC with respect to the comment thread? Does the text include any desired updates? Are important "non-desired" updates summarized in the alternatives section? I'd like to make decisions on older RFCs like this one =) |
I recall there being good ideas here, but it will be a lot easier to evaluate once Allocators are implemented, so I suggest waiting for that. |
There are also a few updates I want to make to take advantage of specialization. Should I close this for now and re-open it when allocators land (or are you planning on stabilizing placement new before the allocation API)? |
Yeah I haven't moved on landing allocators because I was waiting until the pieces were in place to support them on the library types (see RFC 1327) But now the most fundamental language change for that has landed, so I hope to make forward progress there soon. I don't think you need to close this RFC in the meantime. |
Yay! |
Team member @aturon has proposed to postpone this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
OK, I'm going to close this as postponed. Work on placement has largely stalled; we should probably revisit the whole question at some point. |
Supersedes #1401
rendered