6 ms·
I still don't understand why it's bad! Feels like spaghetti sentences tied together as a single article. Why is OOP so bad, anybody? With scenarios, code sampl
by ctxc 5y ago
I still don't understand why it's bad! Feels like spaghetti sentences tied together as a single article.
Why is OOP so bad, anybody? With scenarios, code samples or alternate implementations?
- unnouinceput 5y agoOOP is not bad. Also the entire discussion is pointless. Problems require solutions. You do the solution in OOP or not, nobody's gonna care, just that the solution solves the problem. Rest is just whispers in the wind.
- hutzlibu 5y agoIn my opinion it is just the current anti-hype. A few years ago OOP was supposed the be the magic bullet for everything, which it was apparently not. And now people critizice OOP for not delivering magic bullets. At the same time everybody seems to mean different things with OOP. So no, it is not bad. Certain practices from OOP, like deep inheritance turned out to be worse in reality than expected in theory. But nothing dramatic. And by my definition of OOP - it is still a major part of every major language.
- lamontcg 5y agoI think the major problem is that base classes are really two different interfaces (public and protected) combined with a default implementation, all exposed as a public symbol that anyone can reference. So if you have a Vehicle base class with Car and Truck that inherit from it people will naturally externally do things like pass around List<Vehicle> and will extend functionality with Lorry : Vehicle and start using it. This creates a problem because you cannot change the base class of a Car or else it will no longer fit in a List<Vehicle> but if you modify Vehicle you may break people who inherit from Vehicle. If you wrote it out explicitly without using inheritence though you'd have something a bit more sane and split up into the three different concerns: class Car : IPublicVehicle { IProtectedVehicle _vehicle = new Vehicle(); public void Drive() { _vehicle.Drive() } } Now you have a public interface where you'd create List<IPublicVehicle>'s and toss them around, but you would be free to write a VehicleV2 class that could be injected into _vehicle (you could even do it dynamically and go nuts with dependency injection). Then other people using Vehicle() wouldn't have their behavior changed and everyone would still live happily inside of List<IPublicVehicles>'s next to each other. At the same time by having to write down the interface IProtectedVehicle (not shown) you'd be more likely to do actual design about the interfaces between your subclasses and your base class. This is the real problem which is that people do lazy shit design over the base class interface and just use it to shove shared code into the base and don't consider it a private interface and then go and break behavior as they mess around with more crap in there. And the "DRY" principle pushes software devs to ALWAYS push shit into their base classes, without even thinking beyond "because DRY", which is guaranteed to be bad design. With good design you may have to tolerate some level of necessary repetition in your base classes. Then you wind up realizing that you need derived classes that do not share behavior (e.g. consider adding a Boat subclass of Vehicle when previously you had taken the SinksInWater() implementation of Car(), Truck() and Lorry() and pushed that into the Vehicle() baseclass. Oops. Now your boats all SinksInWater() unless you override that. And if you override it you may be heading down the road of violating Liskov. So that's the source of the objection that OO programmers will just tell you to write interfaces everywhere for loose coupling and only depend on interfaces not types (not abstract/virtual base classes). But so far I don't know what Go or rust programmers do that is any different. And Go has a really fairly slick system for delegating interfaces to contained structs by composition which is just the same model I outlined above but where the two interfaces are the same. I'm still searching for where other programming languages produce a fundamentally better model. And as far as I've been able to ascertain Go's model is to just replace inheritance with interfaces and delegation -- which you can do in any OO model just by not using inheritance and writing interfaces and delegating. But then the complaint against OO is that proponents will just tell you to write interfaces, and for some reason that is bad. IDK if I'm missing something here...
- acchow 5y agoAfter quite some time with OOP, I rather just use it without inheritance (at least in business logic; inheritance is still useful in libraries). In which case, it would be nice if the language supported ADTs
- tialaramex 5y ago> so far I don't know what Go or rust programmers do that is any different Rust doesn't have object inheritance. So Car and Truck can't inherit from a class named Vehicle. However its Traits have inheritance, so for Car and Truck you could write implementations of a trait named Vehicle or a trait MotorTransport which inherits from Vehicle (and so you'd need to implement Vehicle too in this case as MotorTransport relies on that). Rust only allows the author of Boat or the author of the trait Vehicle to implement Vehicle for Boat, so if you were to add a sinks_in_water() predicate to Vehicle either: * As author of Vehicle you're responsible for implementing sinks_in_water() for Boats OR * You've made a backwards incompatible change, anybody who uses the existing Boat can't upgrade to your revised Vehicle OR * inside your own system where nothing external can force the version requirement, now it doesn't compile because Boat claims to implement Vehicle but it lacks sinks_in_water()
- lamontcg 5y agoIf traits map to interfaces and you have concrete implementations of those which can be composed into Car then rust is still just subtractive and eliminating inheritance. There's nothing you can do in rust then that you couldn't fundamentally do in OO languages by avoiding inheritance. Which gets to the point of if we should be talking about avoiding inheritance specifically? Because "OO" is somewhat ill-defined.
- tialaramex 5y agoInheritance isn't gone from Rust it just only exists for Traits (akin to interfaces) as I explained. For example std::cmp::Eq inherits from std::cmp::PartialEq - if there's an Equivalence relation between things of this type then necessarily there is also a Partial Equivalence relation between some of those things (specifically: all of them) so you implement std::cmp::PartialEq and then just say actually it's also Eq (ie this equivalence applies to the whole type). If you make some types which you implement std::cmp::Eq for, and all I need is std::cmp::PartialEq, I can use your types, because of the inheritance. But the fact your types have std::cmp::Eq (and thus also std::cmp::PartialEq) does not prevent them from being quite different in every other respect to other types, nothing about the types themselves is inherited. So this means thinking about inheritance in a different way but it doesn't mean the concept is gone from the language. A typical toy Rust type might implement half a dozen or more Traits, some of them inherited from others and some not, "eagerly" implementing common Traits is encouraged. As to just not using subtype inheritance in languages which have that, you're likely to immediately run into an existential crisis when the language - not unreasonably - depends upon this feature in its own design. In Java for example you can't go anywhere without tripping over Object, the supertype of all user-defined types. Java expects you to use inheritance so avoiding it comes with needless penalties.
- throwawaylinux 5y agoI'm not sure that it is so bad. But I still don't understand why it's good! Why is it so good? It is said to be better than (non-OOP) alternatives. Where's the evidence for that?
- chadcmulligan 5y agoI always think the best argument for OOP is avoiding name space collisions - with procedural programs you have a bunch of functions that could be named the same - how do you separate them? OOP gives you the ability to wrap things together - their variables along with the methods that make sense for the objects - little collections of things that go together. Then once you have an object, sometimes you'll want to make a method work a bit different in different circumstances - inheritance solves this. Sometimes you'll want a bunch of objects that aren't really in an inheritance hierarchy to have some features the same - so interfaces (protocols) are born.
- _dain_ 5y agoIsn't that just polymorphism? There are lots of ways to get that.
- chadcmulligan 5y agodon't think so - https://stackify.com/oop-concept-polymorphism/ https://stackify.com/oop-concept-polymorphism/
- rawoke083600 5y agoI would argue (my opinion) - OOP smashes together state + behavior. The original reason for this was good: I.e the user of the class(object) should not need to know ALL the internal details etc. Something like ECS (data-orientated). Very explicit separates DATA(state) and BEHAVIOR (System, Functions, Methods etc). For me at least it makes it easier and more reliable to "reason" and have a "mental model" about the big-complex system. If I know that for example in a game project ANYTHING with "gravity" is about the ONE Gravity-System(which runs 1x60 seconds in possible sep.thread) and that it Operates(change state) for ALL entities with the "Mass + Pos Components."
- LadyCailin 5y agoI stopped reading after they said they don’t know much about what unit tests are really. It’s clearly not a well informed opinion, even if it happens to be right, which, from what I did read, it very well may not be.
- jcranberry 5y agoThere is a famous paper called 'out of the tar pit' which may be somewhat related.
- creakingstairs 5y agoI think it’s hard to explain it because the very definition of OOP varies per person. Often people who hates it worked with a codebase that took some OOP principles to the extreme. E.g. I worked in a code base with extreme levels of abstraction where literally everything is a class. That said, any principle including FP, taken to an extreme can produce a very tiring codebase (I’m guilty of doing this :p). So its not really OOP’s fault
- jerome-jh 5y agoInheritance in itself conflicts with encapsulation. First because it gives access to protected members of the super class. So it breaks encapsulation to the letter. Secondly because it hurts code locality so much. To such an extend it is difficult for the average programmer to determine what is going on by simple looking at the program. We have a recrutement test on this. Although candidates usually have a good intuition at what the test program does, it is amusing how easy it is to make them doubt by asking simple questions. Dynamic dispatch principle in itself is well understood but it opens so many questions about member access, non virtual methods access, overloaded method access to which people usually have no firm answer.