6 ms·
In my experience, 90% of the time people use inheritance but they really only cared about composition, and their language simply does not have any convenient fa
by qalmakka 6y ago
In my experience, 90% of the time people use inheritance but they really only cared about composition, and their language simply does not have any convenient facility to compose types and re-export their methods.
With a good type system that includes traits, you almost never need virtual dispatching, as any Rust developer may tell.
- cout 6y agoThat's also been my experience. I've also seen programmers use composition and delegation solely to avoid inheritance (in a language that makes it natural), and the result is often less maintainable than a design that just uses inheritance.
- SMFloris 6y agoRecently experimented a bit with Rust and I found the reverse to be true. You cannot compose types in Rust. You compose behaviors not types. Very important distinction as I found out the hard way. Take the following example I have found on the net: https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=52feae5c84edb7942d05c8bf112b8237 https://play.rust-lang.org/?version=stable&mode=debug&editio... In that example, both the bicycle and the car have the property `speed`. Imagine you have multiple types now that need to have the `speed` property. You would need to copy-paste the same code for each new type in order for you to be type safe. Apparently it is called *Monomorphization*: https://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#monomorphization https://cglab.ca/~abeinges/blah/rust-reuse-and-recycle/#mono... From the article: * But if I want a single queue to be able to handle different tasks, then it's not clear how that could be done with monomorphization alone. That's why it's called "mono"morphization. It's all about taking abstract implementations and creating instances that do one thing. * Which was exactly what I was experimenting with: A single queue worker that can handle different cases. Honestly, it made Rust almost not worth it for me. Sadly, I was too deep to turn back so I wound up doing the whole thing in Rust. I have tons of copy-paste code. It is ugly and it is bothering me.
- twic 6y agoI've heard "monomorphisation" to refer to something a compiler does, but not something a programmer does. I think this is just "repetition"! The need for something to solve the problems inheritance solves has been known in Rust for a long time. Mostly it's been motivated by the need to implement the HTML DOM, which is fundamentally an inheritance hierarchy, in Servo. There's a longstanding RFC about it: https://github.com/rust-lang/rfcs/issues/349 https://github.com/rust-lang/rfcs/issues/349 Inheritance is one possible solution. There are others.
- SMFloris 6y agoI do hope they adopt one solution or the other. Rust for me seems incomplete because of this. Another issue I have with it is perfectly described in this article: https://theta.eu.org/2021/03/08/async-rust-2.html https://theta.eu.org/2021/03/08/async-rust-2.html
- d1plo1d 6y agoFor reference I have over a decade of JavaScript experience in industry and my async Rust rewrite of a large JS project was *more* concise then the heavily refactored and polished NodeJS version (a language I consider more concise then most). If you are having to copy and paste excessively in Rust that is an issue but it is not necessarily intrinsic to the language. For what it's worth traits largely prevented copy and paste and where traits fail there are macros. The classic inheritance example you link to is a tiny percentage of my code and an orders of magnitude smaller time sink when compared to the code maintenance problems I faced in other languages.
- dwattttt 6y agoYou actually can have a single queue that handles the different cases. You want dynamic dispatch for that, the syntax looks like this (quick addition to the playground sample): https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=65c322cf17745d855c348e65eb3d0284 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- zozbot234 6y agoTraits are virtual dispatching, albeit the dispatch table is not bundled with the object. The meaningful distinction is between implementation inheritance vs. inheritance of interfaces, abstract classes or traits.
- Twisol 6y agoTrait objects (via `dyn`) are virtual dispatching, but traits themselves are basically agnostic to static vs. virtual dispatch. If you use a trait method through a statically known type, the method is invoked statically -- no runtime lookup.
- d1plo1d 6y agoVery true. I'm checks cloc 14,000 lines into a personal project and I have yet to feel any need to use `dyn` (virtual dispatching for non-Rust folks).
- pierrebai 6y ago"I've designed this project in Go following Go naturally imposed design patterns and found that I did not need inheritance.", said the Go programmer. "Well, mmm, duh?", thought programmers of other languages. "I've designed this project in Rust, following Rust-imposed design principles, and found monomorphism sufficient", said the Rust programmer. "Well, mmm, duh?", thought programmers of other languages. "I've designed this project in Python, using Python-style design and I've found that I did not need strictly typed functions", said the Python programmer. "Well, mmm, duh?", thought programmers of other languages. "I've designed this project in language X, which impose Y and as such I've found that you actually don't need Z", said the X programmer. "Well, we got the picture already", said the HN reader.
- politician 6y agoAbsolutely, but the interesting bits are in the metrics. How many lines of code does it take in each language? How many distinct concepts are required for the solution? To what degree is the mastery of each concept required?