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 as box value. (This already feels backwards; I’d expect box syntax to just be sugar for Box::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 other Deref and smart pointer types in the ecosystem.
- It’s mildly inconvenient to implement
Box<T> yourself (if someone were so inclined), because it needs the exchange_malloc and exchange_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?