How can I create a generic type that includes a trait

Viewed 161

I find I am using this pattern a lot.

Arc<Mutex<dyn SomeTrait + Send>>;

and so I thought I would do this:

pub type NicePtr<T> = Arc<Mutex<dyn T + Send>>;

but this does not compile

   Compiling rsim v0.1.0 (C:\work\pdp\rsim)
error[E0404]: expected trait, found type parameter `T`
 --> src\common.rs:9:37
  |
9 | pub type NicePtr<T> = Arc<Mutex<dyn T + Send>>;
  |                                     ^ not a trait

I assume this is possible, but I just dont know the correct syntax.

2 Answers

An interesting note is that (it is the thing that you want)

use std::sync::{Arc, Mutex};
pub type NicePtr<T: Send> = Arc<Mutex<T>>;

does compile, but with a warning:

warning: bounds on generic parameters are not enforced in type aliases
 --> src/lib.rs:2:21
  |
2 | pub type NicePtr<T: Send> = Arc<Mutex<T>>;
  |                     ^^^^
  |
  = note: `#[warn(type_alias_bounds)]` on by default
help: the bound will not be checked when the type alias is used, and should be removed
  |
2 - pub type NicePtr<T: Send> = Arc<Mutex<T>>;
2 + pub type NicePtr<T> = Arc<Mutex<T>>;
  | 

As a comment points out, you can accomplish something similar to what you want with macros. You could have one macro that expands to a type and one that wraps Arc::new(Mutex::new()) (or any other pointer type that you decide is nice).

use std::sync::{Arc, Mutex};
use std::fmt::Display;

macro_rules! nice_ptr {
    // for types
    ($t:ty) => {
        Arc<Mutex<$t>>
    };
    // for traits
    ($t:expr) => {
        Arc<Mutex<$t>>
    }
}

macro_rules! nice_ptr_new{
    ($inner:expr) => {
        Arc::new(Mutex::new($inner))
    }
}

fn main() {
    let example: nice_ptr!(dyn Display) = nice_ptr_new!("example");
    println!("{}", example.lock().unwrap());
}

Using it with the wrong types even gives a helpful error message.

fn main() {
    // arrays don't implement Display!
    let example: nice_ptr!(dyn Display) = nice_ptr_new!([1,2,3]);
    println!("{}", example.lock().unwrap());
}
15 |         Arc::new(Mutex::new($inner))
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[{integer}; 3]` cannot be formatted with the default formatter
...
20 |     let example: nice_ptr!(dyn Display) = nice_ptr_new!([1,2,3]);
   |                                           ---------------------- in this macro invocation
   |
   = help: the trait `std::fmt::Display` is not implemented for `[{integer}; 3]`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: required for the cast to the object type `dyn std::fmt::Display`
   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
Related