-
Notifications
You must be signed in to change notification settings - Fork 9
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
Type erased (dynamically dispatched) allocators #33
Comments
What makes an explicit vtable useful? I’ve always assumed we would keeps the "main" trait ( |
👍 I always assumed this as well, maybe it might be worth to open an issue to track seeing if this has consensus and writing that down somewhere. |
Box must always be a single pointer for backwards compatibility, so putting additional pointers in box is a no go. |
The epxlicit approach is a bit more flexible in what it can represent. E.g. you can have the same type which represents the equivalent of a I think with regular trait objects you have to be explicit in terms of whether and how the trait object is boxed (static ref, Box, Arc). The regular trait object approach also always uses the 2 pointers as an object. But sometimes that might actually not be what you intend. E.g. you might define a static allocator which manages a set of buckets - where each buckets contain equal sized memory chunks. You could now simply store the bucket ID in the data field. The method in the vtable then finds the associated underlying buffer by doing along You can use trait objects for some of those alternate implementations, but it gets quite messy - people need to rely directly on |
@lachlansneff what do you mean by this? Why would adding a field at the end of the struct break compatibility? |
@JelteF I assume it's because |
That link only talks about how you can convert between Box ptrs and Global allocator pointers. It doesn't make any guarantees that the size of a Box will always be the size of a native int. For other things like |
My main issue with this design, other than using up more space unnecessarily, is that it erases lifetimes as well as types. There is no way to safely put a stack allocated allocator into box here. |
Yes, for that you would need to have a different concrete type. E.g. That makes 2 concrete types, but that should cover all scenarios. |
Would this WG also be interested in working on and standardizing type-erased/dynamic-dispatched/polymorphic allocators?
I imagine something along:
The benefit of this type of allocators is that it can be stored inside the types which allocate (custom
Box
es,Vec
s, etc) without also making them generic. E.g.Box<T>
could be defined along:This also allows to pass types which originate from different allocators to the same APIs. Basically the same reasoning why C++ introduced polymorphic allocators (PMR).
Some personal experience report why I am interested in using those kinds of allocators:
I recently played around with custom allocation strategies for libraries in no-std environments, where relying on global allocation and always succeeding allocations wasn't feasible.
I started there with using traits for buffers and allocators to support various allocation strategies (e.g. buffer pools) - see the appendix. But the more I implemented my program, the more I got annoyed by it. The main reason was that I was at some places threading up to 6 generic generic types through functions in order to abstract over buffers and some other platform related types.
Since then I'm looking more and more into type-erased buffers and allocators, which seem to be very promising. In addition to having
Allocator
s as plain structs, the buffer types could be the same, and e.g. store astruct Allocator
inside them to be able to release themself back to the allocator or a pool. The Bytes crate recently went into a similar direction. This would clean up a lot of APIs in my case and make it easier for end-users to utilize them (it's e.g. easier to know whatBytes
is then what aBufferLike
constraint is).Another domain which will in my opinion benefit from it would be
Future
s andasync/await
support on embedded platform. There we will wantFuture
s to be allocated from different allocators in order to provide fault isolation and to prevent fragmentation. However parameterizing Future boxes for allocators and trying to makeFuture
s from different allocators to run on the same executor is not pretty. This project tried this approach, and already ended up with a huge amount of code for just supporting 3Future
types. AFutureBox
whic doesn't have to be generic over an allocator might be easier.Drawbacks
The polymorphic allocator has 2 drawbacks:
Allocator
in the types which allocate. That will likely be 2 additional pointers (which certainly can be relevant!).Therefore it might not be a full replacement for generic static dispatched allocators.
But for my personal use-cases the usefulness would currently be higher.
Appendix: This was the original message buffer mechanism that I used
The text was updated successfully, but these errors were encountered: