Why Box is special?

My friends I had have a discussion about some topics about rust standard library. We've discussed a lot of stuff but there's one topic we can't comprehend: specialty of std::box::Box type.

We all know about one Box' feature that can't be implemented in stable rust nowadays:

  • Box can be dereferenced "by value" to move out its content onto stack, but as for me there.s not much difference between *boxed and boxed.into(), and the latter can be implemented in rust today.

So is there any reason except this one? I mean, not counting "a long time ago, in a galaxy far, far away...`.

Ok, I guess this is the answer:

  • The dereference operator for Box<T> produces a place which can be moved from. This means that the * operator and the destructor of Box<T> are built-in to the language.
  • Methods can take Box<Self> as a receiver.
  • A trait may be implemented for Box<T> in the same crate as T , which the orphan rules prevent for other generic types.
1 Like

The latter two points are not Box specific, but they are unstable so can't be implemented outside the standard library.

Methods taking Box<Self> as a receiver is part of the arbitrary_self_types feature, this has been extended to support some other types such as Pin<&mut Self> and Arc<Self>. There has been proposals to stabilize this so that types outside the standard library can be used as method receivers.

Being able to implement a trait for Box<SomeLocalType> is part of the fundamental feature, this is again also applied to Pin and some other types like Fn. As far as I'm aware there haven't been any concrete plans to expose this as a stable feature for other libraries to use.


There is another very important thing to know about Box and how it is special: a Box pointer cannot be aliased.

That's why

let ft = Box::new(42);
let at_ft: *const i32 = &*ft;
let ft = ft; // invalidates at_ft
println!("{}", unsafe { at_ft.read() });

is UB whereas

let ft = Box::into_raw(Box::new(42));
let at_ft: *const i32 = ft;
let ft = ft; // does not invalidate at_ft
println!("{}", unsafe { at_ft.read() });
unsafe { drop(Box::from_raw(ft)); }

is not.