Indeed, they are distinct types. Says the reference:
Two trait object types alias each other if the base traits alias each other and if the sets of auto traits are the same and the lifetime bounds are the same. For example, dyn Trait + Send + UnwindSafe is the same as dyn Trait + UnwindSafe + Send .
There are no subtyping relationships between dyn A, dyn A + Send, dyn A + Send + Sync, etc. But you can "cast away" the auto traits:
let x: Box<dyn Any + Send + 'static> = Box::new(5) as _;
let y: Box<dyn Any + 'static> = x as _;
I believe they are distinct types, yes, but can be converted into each other (you can pass a &dyn Display + Send into a function expecting &dyn Display)
I can't remove the as i32 in the example above. That's not surprising. But I wonder why I can pass Box<dyn FnMut() + Send + Sync> to a function that expects Box<dyn FnMut()>, if both are separate types and there is no subtyping.
Don't get me wrong, I'm happy I can pass the closure here; it would be annoying if I couldn't. I'm just trying to find the corresponding rule or explanation in the reference. Maybe I've just been looking in the wrong place, or is this something that's not mentioned in the reference?
"[…], a type Foo<T> can implement CoerceUnsized<Foo<U>> when T implements Unsize<U> or CoerceUnsized<Foo<U>>." (see Unsized coercions in the reference).
Certainly should look at the unsized coercions more closely to understand them better.
I feel like there's something (fundamentally) new to learn about Rust everyday! Does this ever end?
Hello One
Hello Two
Before drop
DropMonitor was dropped
After drop
Note that we cannot cast or coerce Box<dyn FnOnce() + Send + Sync> into Box<dyn Dropable>. I assume that's because of the vtable being different, right?
Interestingly, it's possible to wrap it in another box to make it Dropable and thus passable to nop. (Side note: That trick can help me to be generic over the argument and return type of a closure in my ephemeral closure experiment.)