Extending somebody's type

How to extend functionality of 3rd party type?
I'm using cursive for my project and there is a Dialog struct. In C++ I'd inherit from it and simply add the desired functionality. How to do it in rust?

Thanks

There are a few approaches:

  • if you want to implement a third-party trait B for Dialog, you can create a newtype

    struct MyDialog(Dialog);
    

    and then impl B for MyDialog

  • if you want to package additional data with Dialog, you'd create a new struct like this:

    struct DialogPlus {
        dialog: Dialog,
        extras: MyData,
    }
    
  • if you just want to write your own functions that take a Dialog as receiver, so that you can call them with method syntax, you can write an extension trait:

    trait DialogExt {
        fn my_extra_method(&self) -> Foo;
    }
    
    impl DialogExt for Dialog {
        fn my_extra_method(&self) -> Foo {
            /* implementation goes here */
        }
    }
    
7 Likes

Thanks, will check that out and let you know how it went.

Hi, unfortunately none of those solutions work as I need to extend existing Dialog's trait. So the situation is:
Dialog has a trait View and I need to modify one method of this trait to suit MyDialog.
Is this achievable?

Could you not create a new MyDialog type and implement View on MyDialog? I.e. what's wrong with the two first solutions?

3 Likes

Would that mean that I have to implement all of the required methods from that trait? Because I only need to modify one and leave the rest as they are.

Yes, you need to implement those too, but you can forward the call to the inner dialog.

For any methods you don't want to override, you can implement them by forwarding to the inner class. Currently, you have to do this manually, which is simple but involves a lot of boilerplate for traits with many required methods:

struct MyDialog {
    inner: Dialog,
}

impl View for MyDialog {
    // This method is overridden.
    fn do_stuff(&self) {
        // new code goes here
    }

    // These methods all delegate to `self.inner`.
    fn foo(&self) { self.inner.foo() }
    fn bar(&self, count: usize) { self.inner.bar(count) }
    fn baz(&self, s: &str) { self.inner.baz(s) }
}

If you are doing this frequently for the same trait, writing a macro can help eliminate the boilerplate. There are proposals for dedicated syntax to simplify such code.

2 Likes