How to make this object-safe?


I'd like to have a trait like this:

trait Access<T> {
  type Guard: Deref<Target = T>;
  fn get(&self) -> Self::Guard;

Now, I can certainly use this directly with static dispatch like this:

fn print_int<A: Access<usize>>(a: &A) {
    println!("{}", *a.get());

But it's not object safe, so I can't do print_int(a: &dyn Access<usize>). I could have the trait return Box<dyn Deref<Target = T>>, but that forces one to do boxing every time, which is wasteful in the first scenario.

Is there some elegant way to allow both use cases? I have this very unelegant way (not tried to compile it, it's just an idea):

trait Access<T> {
    type Guard: Deref<Target = T> where Self: Sized;
    fn get(&self) -> Self::Guard where Self: Sized;
    fn get_boxed(&self) -> Box<dyn Deref<Target = T>>;

Also, it's for a library that tries to be compatible with oldish rustc releases, so I'd like to avoid very fresh features.

Because there's no way to know the actual type of Guard from dyn Access<usize>. For example, you can make &dyn Access<usize, Guard=Box<usize>> without modifying the trait Access.

I know why it's not object safe, I was asking for a pattern to do something like this, but one that works.

Unfortunately, fixing the Guard does not solve my problem. It would again force me, when implementing the trait for a particular type, to set the guard to Box<dyn Deref<Target = T>> and would disallow static dispatch. I really do need an intermediate guard type, it kind of locks something for its own lifetime, so Box<usize> isn't an option either :frowning:

What about this,

When you want static dispatch, you just don't use DynAccess. But if you want dynamic dispatch then you box the guard to erase the type. It doesn't even change the trait!


Thanks, yes, this solves the problem. I would still not call it exactly elegant, but it definitely gets the job done :-).

Or even better,


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.