-
-
Save mitchmindtree/29d3753fcec4112439ba to your computer and use it in GitHub Desktop.
// 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! |
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.
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.
i don't know if this feature is implemented yet (i just wrote the code out and i have my suspicions it's not actually overriding) and this comment is 9 years into the future, but is it implemented now?
i would love if you can link the issue/forum you posted this gist on! thank you so much.