Working around non existent delegation support

Consider I have an external struct Connection that implements a lot of methods and traits.

In my crate I want to make a special variant of connection SpecialConnection that adds some minor functionality. (Say 2 extra methods send_special_request, recv_special_reply) but for all other intents and purposes SpecialConnection is just a simple Connection

What is the ideal way to implement this pattern?

If SpecialConnection has no additional state then there is no need to create a new struct. Just implement a trait called Special and add the extension methods to it.

pub trait Special {
    fn send_special_request(&self);
    fn recv_special_reply(&self);
}

impl Special for Connection {
    fn send_special_request(&self) {}
    fn recv_special_reply(&self) {}
}

But this is no longer sufficient if we need additional state tracked for this two methods to work

pub struct SpecialConnection {
    pub conn: Connection,
    pub special_props: Vec<String>,
}

impl Special for SpecialConnection {
    fn send_special_request(&self) {}
    fn recv_special_reply(&self) {}
}

But the problem is apart from these two methods and an additional state SpecialConnection is exactly the same as Connection and thus needs to implement all the methods and traits that Connection does.

Obviously one approach is to expose the internal connection and let the user access it if they need the base functionaility.

let spconn = SpecialConnection::new();
spconn.conn.send_request();

This is what I am doing now. But this is not ideal. I would like a proper implementation of an is-a relationship. I don't even need selective delegation, I just want to delegate everything to Connection.

Implementing as_ref to allow &SpecialConnection to be coerced into a &Connection is a possible solution. But I have heard that it's not advisable. Besides, the original Connection does not implement as_ref so this is not even possible unless I convince the original crate author to implement it.

There is another option. I can move special_props as a global lazy static variable using lazy_static or once_cell since it only has to be populated once for the lifetime of an application. If I do that I don't need extra state for SpecialConnection and go back to the Connection with an extension trait approach. But I am not sure if creating a global variable is a good idea as a library author.

What's the ideal way to do implement this pattern? How do you extend external structs that have lots of methods and traits?

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.