Associated type trait bounds with trait objects

Hi!

I've been trying to find an answer as to why this does not work, but I'm not sure I understand.

pub trait Notifiable {
    type EventType;

    fn notify(&self, event: Self::EventType);
}

pub trait Observable {
    type EventType;
    type NotifiableType: Notifiable<EventType = Self::EventType>;

    fn observe(&mut self, viewer: Self::NotifiableType);
}

/// Events a window can broadcast to listeners.
pub enum Event {
    Generic,
}

pub struct Window {}

impl Observable for Window {
    type EventType = Event;
    type NotifiableType = Box<dyn Notifiable<EventType = Self::EventType>>;

    fn observe(&mut self, viewer: Self::NotifiableType) {
        todo!()
    }
}

If I don't specify the bounds for Observable::NotifiableType, it does work:

pub trait Observable {
    type EventType;
    type NotifiableType;

    fn observe(&mut self, viewer: Self::NotifiableType);
}

I feel like having the notifiable type be bound to the notifiable trait to be a sane choice, but obviously it does not work. I only get the error:

"the trait bound `Box<(dyn Notifiable<EventType = Event> + 'static)>: Notifiable` is not satisfied
the trait `Notifiable` is not implemented for `Box<(dyn Notifiable<EventType = Event> + 'static)>`"

Maybe that's the reason why it's necessary to have a trait impl for fundamental type constructors.

impl<EventType> Notifiable for Box<dyn Notifiable<EventType = EventType>> {
    type EventType = EventType;
    fn notify(&self, event: Self::EventType) {
        <dyn Notifiable<EventType = EventType>>::notify(self, event);
        // or
        // (&**self).notify(event);
    }
}

Rust Playground

Also see

3 Likes

Thank you so much for the answer! It didn't strike me I actually can implement a trait for a box type like this!

Feels a bit awkward that I cannot have the above code in a separate library and write the implementation for box in another crate, where I can write the behaviour. Might as well have a new struct wrap/implement the notifiable trait in that case. (Otherwise you get the error: "only traits defined in the current crate can be implemented for types defined outside of the crate. define and implement a trait or new type instead").