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
Boxconstructor is magic.Box::new(value)is literally implemented asbox value. (This already feels backwards; I’d expectboxsyntax 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 Derefis confusing, it looks as if it was infinitely recursive whereas it’s not. - Relatedly,
*some_boxmoves out of the box and deallocates. This is inconsistent with the behavior of otherDerefand smart pointer types in the ecosystem. - It’s mildly inconvenient to implement
Box<T>yourself (if someone were so inclined), because it needs theexchange_mallocandexchange_freelang items. - And generally, it just feels wrong that such a simple type isn’t implemented in pure Rust, like C++'s
std::unique_ptris 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?