Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I like rust a lot, but coming from C++ and python there are times inheritance saves so much time enabling quickly creating small variations in classes. In rust you have to duplicate all the base logic, or abstract it to another common type to use composition. Which is fine but it’s painful at times knowing that time sink lies ahead. I understand everyone hates OO now but I still miss it at times when it would save me a lot of effort.


If you can use C++20, I'd encourage you to look into using concepts. Since I've started using them, it feels like a much more natural choice than class hierarchies when one needs to enforce type constraints on interfaces.

Instead of making a parent class that has a few key methods you need (e.g. send, recv) with the signatures (e.g. takes a pointer, returns a number), one can encode the use of those functions in a concept (e.g. a "socket" concept). This decouples the implementation from the use in the method, with the one big advantage being that it is easily testable -> no more need to carefully craft type hierarchies to carefully be able to substitute some mock object when you can just directly call it!

OO hierarchies certainly still have their place (even though so many conference talks seem to be about getting rid of them), but I'm glad I can relegate them to a dark corner of my toolbox until I absolutely need them.

In fact, come to think of it C++ concepts are basically Rust traits!


Yea for sure, it’s a lot like swift being protocol oriented too. It’s a major paradigm shift I have to enforce in my head manually still at this point tho


Note that you can do Swift's protocol oriented programming / portocol extensions in Rust, too:

  trait Test {
      fn value(&self) -> i32;
  }

  impl dyn Test {
      fn multiplied(&self) -> i32 {
          self.value() * 2
      }
  }


What does `impl dyn` mean, exactly? That this only works for trait objects?


That it works for any type implementing the trait, via vtables. Otherwise, it’s a method specific to the particular type implementing the trait (a concrete implementation but distinct to the specific impl).


To be fair, a trait gets you 98% there. It can have default implementations for most functions, you just overwrite the ones you want to change. You'll still need to declare the underlying struct though, so a bit of extra code


In my programming career, I had several situations where a base class made a lot of sense, with a dozen derived classes only implementing specific functionality. They were mostly algorithm-related.

OO makes a lot of sense in hierarchic structures.


It's a good practice to make the base class abstract.

With that in mind, this pattern cleanly maps onto a trait with default implementations for methods plus several structs that implement the trait.


I often find the opposite to be true. Where I have to spend a lot of time clearly defining a hierarchical structure, which after implementation needs to restructured. Or fighting against an already defined hierarchy, usually unchangeable and made by someone else.


Unconstrained templates can also sometimes be a massive time saver.


Rust could have inheritance - perhaps limit it to single parent


Can you imagine a non-inheritance solution to this problem? If you used this way of solving things your whole life then I understand that changing paradigms is a challenge.


Since there was no answer, and no concrete example where inheritance was needed, I'll just provide one possible solution: you can store a function pointer that implements the desired varying functionality as a part of the struct whose implementation you want to slightly change. That function can accept self as the first argument like any method.

Performance-wise this is the same as a vtable generated by c++ and doesn't require creating more entities.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: