I wasn’t able to find a related proposal, RFC, or issue on GitHub, so I’d like to ask here: would it be possible to transform Box<T>
into a true library-implemented type?
Currently, Box<T>
is a special-cased, quite ugly language item. As I understand, this has historical reasons, because originally, heap-allocated uniques were a built-in type, but they no longer are. This leads to issues you probably know very well. A non-exhaustive list of symptoms:
- The
Box
constructor is magic.Box::new(value)
is literally implemented asbox value
. (This already feels backwards; I’d expectbox
syntax to just be sugar forBox::new()
.) - The destructor is also magic:
Box::drop()
is a no-op with a comment saying that the real work is performed by the compiler. - The type needs (?), but certainly has, special handling in the compiler, increasing the complexity of internals for I think no good reason.
- Relatedly,
impl Deref
is confusing, it looks as if it was infinitely recursive whereas it’s not. - Relatedly,
*some_box
moves out of the box and deallocates. This is inconsistent with the behavior of otherDeref
and smart pointer types in the ecosystem. - It’s mildly inconvenient to implement
Box<T>
yourself (if someone were so inclined), because it needs theexchange_malloc
andexchange_free
lang items. - And generally, it just feels wrong that such a simple type isn’t implemented in pure Rust, like C++'s
std::unique_ptr
is implemented in C++.
Given all these drawbacks, wouldn’t it be better to make Box
a regular library type? Is it possible? Today’s Rust seems to have all the necessary features for doing something like:
struct Box<T: ?Sized>(*mut T);
impl<T> Box<T> {
fn new(value: T) -> Self {
// IRL we wouldn't libc in std, of course
let ptr = libc::malloc(mem::size_of::<T>()) as *mut T;
let garbage = mem::replace(unsafe { &mut *ptr }, value);
mem::forget(garbage);
Box(ptr)
}
}
impl<T> Drop for Box<T> {
fn drop(&mut self) {
let value = unsafe { mem::replace(&mut *self.0, mem::uninitialized() };
drop(value);
libc::free(self.0 as *mut c_void);
}
}
impl<T> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.0 }
}
}
etc.
I understand that there may be scenarios when special knowledge about a box is required, but couldn’t only those requirements be moved into a trait that itself is a lang item, leaving the rest of poor Box
impl alone?