Make certain methods of traits "non implementable"

You can get away without specialization, by using an unnameable type trick:

impl<T : Component> PropagateUpdate for T {
    fn propagate_update(&mut self, engine: &mut Engine, delta_time: f64)
    {
        self.__propagate_update_impl__(engine, delta_time, Private)
    }
}

pub trait Component: Send + PropagateUpdate {
    fn new() -> Self where Self: Sized;

    fn init(&mut self, engine: &mut Engine) {}
    fn update(&mut self, engine: &mut Engine, delta_time: f64) {}

    #[cfg(feature = "docs")]
    /// **This method cannot be overriden.**
    fn propagate_update(&mut self, engine: &mut Engine, delta_time: f64) {
        unreachable!("For docs only!");
    }

    #[doc(hidden)]
    fn __propagate_update_impl__ (
        self: &'_ mut Self,
        engine: &'_ mut Engine,
        delta_time: f64,
        _: Private, // <- this is what makes the whole function unimplementable for downstream users
    )
    {
        self.update(engine, delta_time);
    }
}

pub(in crate) use helpers::{Private, __ as PropagateUpdate};
mod helpers {
    pub struct Private;

    pub trait __ { // use this weird name to give it "less visibility" in the docs
        fn propagate_update(&mut self, engine: &mut Engine, delta_time: f64);
    }
}

Advantages of this approach:

  • by having Component be the subtrait rather than a super trait, people can call .propagate_update(...) simply by useing Component.

  • Some doc-related tweaks to help readability (real world example).

  • If you still want to provide overrides within your crate, the __propagate_update_impl__ escape hatch is available:

    impl Component for NodeComponent {
        ...
    
        fn __propagate_update_impl__ (
            self: &'_ mut Self,
            engine: &'_ mut Engine,
            delta_time: f64,
            _: Private,
        )
        {
            self.update(engine, delta_time);
            for child in &mut self.children {
                child.propagate_update(engine, delta_time);
            }
        }
    }
    
5 Likes