10 ms·
Yeah ya... everyone likes to go on and on about how inheritance is the root of all evil and if you just don't use it, everything will be fine. Sorry, it won't
by osigurdson 1y ago
Yeah ya... everyone likes to go on and on about how inheritance is the root of all evil and if you just don't use it, everything will be fine. Sorry, it won't be fine. Your software will still be a mess unless it is small and written three times by the same person who knows what they are doing.
The bottom line is, no one ever really used inheritance that much anyway (other than smart people trying to outsmart themselves). People created AbstractFactoryFactoryBuilders not because they wanted to, but because "books" said to do stuff like and people were just signaling to the tribe.
So now, we are now all signaling to the new tribe that "inheritance is bad" even though we proudly created multiple AFFs in the past. Not very original in my opinion since Go and Rust don't have inheritance. The bottom line is, most people don't have any original opinions at all and are just going with whatever seems to be popular.
- josephg 1y ago> The bottom line is, no one ever really used inheritance that much anyway If you think that, you have no idea how much horrible code is out there. Especially in enterprise land, where deadlines are set by people who get paid by the hour. I once worked on a java project which had a method - call a method - call a method - call a method and so on. Usually, the calls were via some abstract interface with a single implementor, making it hard to figure out what was even being executed. But if you kept at it, there were 19 layers before the chain of methods did anything other than call the next one. There was a separate parallel path of methods that also went 19 layers deep for cleaning up. But if you follow it all the way down, it turns out the final method was empty. 19 methods + adjacent interface methods all for a no-op. > The bottom line is, most people don't have any original opinions at all and are just going with whatever seems to be popular. Most people go with the crowd. But there's a reason the crowd is moving against inheritance. The reason is that inheritance is almost always a bad idea in practice. And more and more smart people talking about it are slowly moving sentiment. Bit by bit, we're finally starting to win the fight against people who think pointless abstraction will make their software better. Thank goodness - I've been shouting this stuff from the rooftops for 15+ years at this point.
- HdS84 1y agoI don't think Inheritance is always bad - sometimes it's a useful tool. But it was definitely overused and composition, interfaces work much better for most problems. Inheritance really shines when you want to encapsulate behaviour behind a common interface and also provide a standard implementation. I.e: I once wrote a RN app which talked to ~10 vacuum robots. All of these robots behaved mostly the same, but each was different in a unique way. E.g. 9 robots returned to station when the command "STOP" was send, one would just stop in place. Or some robots would rotate 90 degrees when a "LEFT" command was send, others only 30 degrees. We wrote a base class which exposed all needed commands and each robot had an inherited class which overwrote the parts which needed adjustment (e.g. sending left three times so it's also 90 degrees or send "MOVE TO STATION" instead of "STOP").
- josephg 1y ago> I don't think Inheritance is always bad - sometimes it's a useful tool. I can only think of one or two instances where I've really been convinced that inheritance is the right tool. The only one that springs to mind is a View hierarchy in UI libraries. But even then, I notice React (& friends) have all moved away from this approach. Modern web development usually makes components be functions. (And yes, javascript supports many kinds of inheritance. Early versions of react even used them for components. But it proved to be a worse approach.) I've been writing a lot of rust lately. Rust doesn't support inheritance, but it wouldn't be needed in your example. In rust, you'd implement that by having a trait with functions (+default behaviour). Then have each robot type implement the trait. Eg: trait Robot { fn stop(&mut self) { /* default behaviour */ } } struct BenderRobot; impl Robot for BenderRobot { // If this is missing, we default to Robot::stop above. fn stop(&mut self) { /* custom behaviour */ } }
- esailija 1y agoThe problem is of course that there is no useful default behavior you can define when the trait is so isolated and generic.
- rixed 1y agoI believe you just summed up 90% of popular wisdom about software engineering. With enough patience you will see many fads pass twice like a tide raising and falling. OOP, runtime typing, schema-less databases and TDD are the first to come to mind. I feel "self-describing" data formats and everything agile are fading already. Very few ideas stick, but some do: I do not expect GOTO to ever come back, but who knows where vibe coding will lead us :)
- falcor84 1y ago> Your software will still be a mess unless it is small and written three times by the same person who knows what they are doing. 100% this! And I've recently been wondering whether this is the right workflow for AI-assisted development: use vibe-coding to build the one that you plan to throw away [0], use that to validate your assumptions and implement proper end-to-end tests, then recreate it again once or more with AI asked to try different approaches, and then eventually throw these away too and more manually create "the third one". [0] "In most projects, the first system built is barely usable....Hence plan to throw one away; you will, anyhow." Fred Brooks, The Mythical Man-Month
- ajuc 1y ago> The bottom line is, no one ever really used inheritance that much anyway That's just false. Before Java abstract factory era there was already a culture of creating deep inheritance hierarchies in C++ code. Interfaces and design patterns (including factories) were adopted as a solution to that mess and as bad as they were - they were still an improvement.
- goeiedaggoeie 1y ago>> People created AbstractFactoryFactoryBuilders not because they wanted to, I don't think this is accurate. people created factories like this because they were limited by interface bounds in the languages they were coding in and had to swap out behaviour at run or compile time for testing or configuration purposes.
- rayiner 1y agoThe problem is every library and framework uses a ton of class hierarchies with big inheritance trees.
- deleted 1y ago[deleted]
- throw4847285 1y agoThe reason people don't have original opinions is because it isn't worth it. The stakes are extremely low. How one chooses to write code is ultimately a matter of personal preference. The lower the stakes, the more dogmatic people become about their choices, because they know on some level it's a matter of taste and nothing more. Counterintuitively, it becomes even more tied to one's ego than the choices that actually have major consequences.
- deleted 1y ago[deleted]
- shadowgovt 1y agoObjects are a pretty good abstraction for when you have data that represents, well, objects. In 3D graphics it's a very useful abstraction. Significantly less good when you're trying to model process, pipeline, or flow IMHO (I know there are some people who swear by them for anything they would bash together with UML first, and I just... Don't see it. I've used more than enough object-oriented flowchart-description languages to fundamentally disagree; charts are two-dimensional, text-represented code is one-dimensional, making the code "objects" doesn't fix that problem). (Probably also worth noting that high performance 3D graphics torture the object abstraction past recognizability, because maintaining those runtime abstractions costs resources that could be better spent slamming pixels into a screen).
- karolinepauls 1y ago> Your software will still be a mess Your software will still be a mess but a mess you can work with. Not a horror beyond comprehension. We should aim for workable mess. This is from experience working with both procedural/functional mess and OO mess.
- quietbritishjim 1y ago> The bottom line is, no one ever really used inheritance that much anyway (other than smart people trying to outsmart themselves). Inheritance is most definitely used in many popular C++ libraries, e.g., protobuf::Message [1] (which is base class to all user message classes and also has its own base class of MessageLite) or QWidget [2] (which sits in a large class hierarchy) or tinyxml2::XMLNode (base class to other node types). These are honestly the first three libraries that I thought of that have a non-trivial collection of classes in them. They're all stateful base classes by the way, not pure interfaces. And remember, I'm not trying to justify whether these are good or bad designs, just the make the observation that inheritance certainly is well used in practice. (The fourth library I thought of with a reasonably complex collection of classes is Boost ASIO [4] which actually doesn't use inheritance. Instead it uses common interfaces to allow some compile-time polymorphism. Ironically, this is the only library in the list that I've been so unsatisfied with that I've written my own wrapper more than once for a little part of it: allowing auto-(re)connecting outbound and accepting incoming connections with the same interface. Guess what: I used inheritance!) [1] https://protobuf.dev/reference/cpp/api-docs/google.protobuf.message/#Message https://protobuf.dev/reference/cpp/api-docs/google.protobuf.... [2] https://doc.qt.io/qt-6/qwidget.html https://doc.qt.io/qt-6/qwidget.html [3] https://leethomason.github.io/tinyxml2/classtinyxml2_1_1_x_m_l_node.html https://leethomason.github.io/tinyxml2/classtinyxml2_1_1_x_m... [4] https://www.boost.org/doc/libs/1_88_0/doc/html/boost_asio/reference.html https://www.boost.org/doc/libs/1_88_0/doc/html/boost_asio/re...
- cloogshicer 1y agoI've long been searching for a concise example of "good" inheritance, can you recommend one?
- tikhonj 1y agoI've written a bunch of code in languages without inheritance per se—OCaml, Haskell, Rust—and things have been more than fine. Hell, I barely use any sort of subtyping! I definitely miss structural subtyping in Haskell and Rust on occasion, but even in those situations the code has never reduced to a thrice-written mess. I've also written some code that's gotten a lot of mileage out of inheritance, including multiple inheritance. Some of my Python abstractions would not have worked anywhere near as well as they did without it. But even then, I could build APIs at least as usable in languages without inheritance, as long as those languages had sufficient facilities for abstraction of their own. (Which OCaml, Haskell and Rust absolutely do!)