Skip to content

Instantly share code, notes, and snippets.

@mitchmindtree
Last active May 1, 2024 06:19
Show Gist options
  • Save mitchmindtree/29d3753fcec4112439ba to your computer and use it in GitHub Desktop.
Save mitchmindtree/29d3753fcec4112439ba to your computer and use it in GitHub Desktop.
The ability for derived traits to override their parent trait methods.
// Firstly - I LOVE Rust! This is just something that has
// been cropping up more and more in my Rust coding experience
// recently, so I though it could be good to discuss it with
// fellow Rustaceans!
//
// TOPIC:
// I'd love the ability to be able to override parent trait
// methods with default methods in the child trait.
//
// The following is a pattern that I come across very often:
trait Foo {
fn create_a_thing(&self) -> Thing { ... }
fn another_really_handy_method(&self);
}
trait Bar: Foo {
fn create_a_thing(&self) -> Thing { ... but uniquely } // this is what I'd love to be able to do! (See below for a better syntax suggestion)
}
struct A {..}; impl Foo for A {}
struct B {..}; impl Foo for B {}
struct C {..}; impl Foo for C {}
struct D {..}; impl Bar for D {}
struct E {..}; impl Bar for E {}
struct F {..}; impl Bar for F {}
fn create_all_the_things<T: Foo>(creators: &Vec<Box<T>>) {
for creator in creators.iter() {
println!("{}", creator.create_a_thing()); // Here, `create_a_thing` would get called uniquely for those that implement Bar if overriding were possible.
}
}
fn main() {
let a = box A{..};
let b = box B{..};
let c = box C{..};
let d = box D{..};
let e = box E{..};
let f = box F{..};
let creators = vec!(a, b, c, d, e, f);
create_all_the_things(&creators);
}
// My real case scenarios have many, many more than just 6 types,
// but hopefully you can see what I mean (and how this might be
// useful) with this small example.
// SYNTAX:
// Perhaps an explicit syntax could be used to make overriding
// parent trait methods both possible, and easy to keep track of:
trait Foo {
fn create_a_thing(&self) -> Thing { ... }
}
trait Bar: Foo {
over<Foo> fn create_a_thing(&self) -> Thing { ... but uniquely } // `over<Trait>` tells us exactly what trait owns the method that we're overriding.
}
// Maybe we could be even MORE specific (and help the
// compiler out) by requiring explicit syntax upon Foo's
// version of the method as well?:
trait Foo {
virtual fn create_a_thing(&self) -> Thing { ... } // `virtual` indicates the ability for the method to be overridden.
}
trait Bar: Foo {
over<Foo> fn create_a_thing(&self) -> Thing { ... but uniquely } // The overridden version
}
// MODULE PROBLEM:
// "But what if you're using a `MyType` that has implmented
// `Bar`, but only `Foo` is imported into the module?"
//
// POSSIBLE SOLUTION:
// Then the compiler should produce an error stating
// that "MyType's implementation of Foo's "create_a_thing"
// method has been overridden - import the overriding trait
// to fix this."
// These are my humble thoughts. What are your thoughts?
// I realise that Rust draws quite a lot more inspiration
// from the FP paradigm, but I feel this could help a lot for
// those who are coming from slightly more of an OOP background.
// It's a pattern that crops up quite often in OOP, but with the
// right explicitness, I feel that Rust could do it better than
// it has ever been done before!
@mitchmindtree
Copy link
Author

Hmmm I don't remember if I ever posted an issue about this. Fwiw, I no longer have any issue with this - I think I was just trying to carry over some of my C++ habits into Rust, and my create_all_the_things example doesn't make any sense 😅

The overriding of constructors is kind of a special case in C++, as the constructor is a special function that you can't give a unique name, whereas in Rust there are no special constructor functions. It turns out it never hurts to write new method/function names that are better suited to what you're actually doing differently. E.g. in Rust you'll see types that have multiple constructor functions use names like new, from_foo, from_bar_and_baz, etc.

As for method overriding, I think in the example above I was trying to get at something like specialization: rust-lang/rust#31844. In general it's not too hard to work around the lack of this using newtypes or traits.

@lib-eramen
Copy link

lib-eramen commented May 1, 2024

i see!
i asked because i just had a case where i was also wondering if my oop tendencies are playing nice with rust's fp features. what happened was i'm trying to build my own single-window manager from scratch (for one reason or another) and i ended up creating a window trait which then specific window structs are created from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment