Problem
In Rust, taking ownership of an object is a way of enforcing proper API usage. It may be possible to implement a particular method using only &mut self
or perhaps even &self
, but if the library author wants to ensure the object won't be used again after the API call, they'll have the method take an self
instead.
Currently, the only way for an object-safe trait to take ownership of Self
is via Box<Self>
:
trait A {
fn borrow(&self, ...); // Object safe
fn borrow_mut(&mut self, ...); // Object safe
// fn owned(self, ...); // Not object safe*. Requires Self: Sized
fn owned(self: Box<Self>, ...);
}
Unfortunately, this has poor ergonomics for users of the trait who don't care about object safety. If they have a Sized
type that implements A
, calling owned required them to do Box::new(x).owned()
.
This leaves library authors with a couple of choices:
- Make their trait take
self
and forgo object safety. - Take an
&mut self
and add runtime checks to ensure the object isn't used afterwards. - Use
Box<Self>
and accept the worse experience for users who don't need object safety. - Suggested by @Nemo157: Have two differently named versions of
owned
and force users to pick the right one based on the context. Non-object safe version could have a simple implementation that just called the Box version.
*There is a proposal to allow unsized function arguments but it is likely a long ways out.
Possible solution
A small amount of syntactic sugar could make the situation much nicer. Have the dot-operator automatically call Box::new
for receiver Box methods, the same way it does autoref currently.
This would imply "implicit" allocations when viewing the call site. However, the function signature would still be clear about the possible allocation (which is more than can be said about many existing functions that allocate immediately after being called!)
Also if desired, the possible allocation could be made even more clear by adding a #[autobox]
(or similar) annotation to the trait definition.