Live data from Hacker News

The Case Against OOP Is Wildly Overstated

medium.com

251–260 of 312 posts

Re: The Case Against OOP Is Wildly Overstated

#251
post #247

Earlier quoted context omitted.

Lots of things in software development have an is-a relationship. The only time inheritance is an antipattern is when it's used for code-reuse and it isn't modeling an is-a relationship. Once you get to application code there aren't a lot of is-a relationships but inside operating systems, libraries, and frameworks it does come up legitimately.

Is-a relationships are best handled by interfaces. If you don't have those and only have inheritance then that is the exception I mentioned above. In those cases I would argue that the base class should be composed entirely of abstract methods and the depth of the inheritance hierarchy should be no greater than 1.

If you have something that is something else in almost every way except for one or twos details inheritance is far superior than interfaces.

The other benefit of inheritance, that often goes unmentioned, is the ability to fix bugs in other products. I've had to inherit from some library/framework class to fix a bug in that technology -- it might be a rare situation but it's absolutely invaluable to have that option.

Re: The Case Against OOP Is Wildly Overstated

#252
post #4

This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful, and that statefulness is fine to freely sprinkle throughout your program.

"Tightly binding data and code" allows you to maintain complex invariants via code, and to abstract away from the specifics of any single implementation. Statefulness per se is quite manageable; what's not manageable is shared, mutable state that isn't isolated to a single, modular, highly cohesive "unit" of code that can be understood in its totality. The real issues with OOP have to do precisely with things that br…

Isn't this basically just namespacing? Not at all unique to OOP.

Re: The Case Against OOP Is Wildly Overstated

#253

Earlier quoted context omitted.

"Tightly binding data and code" allows you to maintain complex invariants via code, and to abstract away from the specifics of any single implementation. Statefulness per se is quite manageable; what's not manageable is shared, mutable state that isn't isolated to a single, modular, highly cohesive "unit" of code that can be understood in its totality. The real issues with OOP have to do precisely with things that br…

Not just invariants, covariants as well. State and zip code always change together. Having had to fix code that passed 5 variables around for an address (which needed to go to 6 for “address 2”) I replaced it with an address object.

An address datastructure is a good thing. I'm not at all convinced that an address object - one with behaviour - is.

Re: The Case Against OOP Is Wildly Overstated

#254

Earlier quoted context omitted.

You might want to consider examining another programming language for clues here. Perhaps look to a language that has a more modern approach to state such as Clojure.

My understanding is that Clojure is basically lisp implemented inside the Java ecosystem. I'm not sure how that makes it "modern" given that the only higher level language older than lisp is the original version of Fortran.

That like saying Go/Rust/Kotlin are just Algol, what’s so modern about them? Lisp isn’t a language anymore, it’s a category of languages and it’s members are rather different from each other besides some superficial syntax style. Common Lisp, Scheme and Clojure are three very different languages, certainly more different than Ruby is from Python IMHO.

Clojure, in 2020, is very very different from the Lisp of 50 years ago and is modern in many respects, even compared to other popular languages.

Re: The Case Against OOP Is Wildly Overstated

#255
post #241

Earlier quoted context omitted.

This is generally accurate, but I want to highlight the awesomeness of opaque structs. In C you can declare a struct in a header file, but not its fields ie struct point;. Then in the corresponding c file you can write out the whole definition ie struct point {x: float; y:float;};. Any code that includes the header can pass pointers to struct point (or pointers to pointers, etc) but can't directly pass points around…

This might sound stupid but I have ONLY ever known OOP in the Ruby / C++ / Java sense before but this idea blew my mind as such an interesting and different way of thinking about it and I can't tell if it is just my own bias but my initial thought is that it seems like such an additional level of mental overhead that you would always have to carry around on top of everything else you already have to think about. I as…

It's the opposite - you can spend less time worrying about the details because you know they're opaque. It's like how in Java it can actually be easier to work on a generic datastructure (e.g. a tree) than a more concrete implementation (e.g. a tree of integers) - the generics force you to cleanly separate the structure-specific parts and the value-specific parts and not get them mixed up.

You can achieve the same kind of hiding in Java by using an existential type. E.g. you could have a library that looked like:

    interface Cursor {
      T start();
      T nextStep(T currentState, int move);
      void finish(T);
    }
    class DataStructure {
      Cursor traverse();
    }
And then you don't know what the internal state of the cursor is because the T type is hidden from you, but the compiler checks that you always call nextStep() with the same state you got back from start(), and you can't possibly mix up the state from two different cursors.

Re: The Case Against OOP Is Wildly Overstated

#256

Earlier quoted context omitted.

Essentially, yes, but in a way that sounds more careful than what you saw in that Fortran program. If it absolutely has to be stateful, like with a db connection for example, then there's no getting around that, but what you can do is (1) not bury it in a bunch of stateful objects that didn't have to be stateful, which can cause cascading errors when either one of them misbehaves and also makes it difficult to isolat…

More concretely, for every bit of state in the program I'm interested in two big questions, each with two subquestions: 1.) Who can access this state, and which of those accesses allow writes vs. which are read-only? 2.) What is the lifetime of that state, and what portion of that lifetime is mutable vs. read-only? Java-style OOP can control #1, but makes no distinction between reads & writes. C++ const correctness a…

> I'm still waiting for a language feature that lets you say "This field of this struct is only mutable while this module is running, and once it completes it will never be changed", though. A lot of data structures are initialized in passes and then passed along as constant data: you construct the basic object structure with nothing but a few IDs, then you compute extra fields as necessary, then you're done and the object is never written to again. If you could keep the fields mutable during initialization (which may be a longer process than just constructor calls) and then seal them off once that's complete, you eliminate a whole class of bugs where a read-only client decides to mutate a field that should only be mutated from designated initializer.

Why do you want to think of it as "the same" struct? It seems to me that the way to achieve this is having the partially initialised thing be a different type than the fully initialised thing, along with a linear type system that makes sure the partially-initialised one is consumed in the process of making the fully-initialised one.

Re: The Case Against OOP Is Wildly Overstated

#257
post #66
post #4

This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful, and that statefulness is fine to freely sprinkle throughout your program.

Objects are essentially structs with namespaces and methods with implicit this params. If you can't have state then you throw structs out too. If you're going this far, you're essentially throwing away typing as well. Are you actually just opposed to private fields?

You should have data structures, but not mutable state or reference identity (two sides of the same coin). Having a bundle of structured data with functions is great. Having those functions secretly change other data somewhere else in your application (you wanted a banana but got the gorilla holding the banana and the whole jungle) is not great.

Re: The Case Against OOP Is Wildly Overstated

#258

IMO, OOP just puts too many footguns at your disposal, the most dangerous one being mutability (how normal is it that our methods mutate instance variables?). The larger a system grows the more mutability will make it even harder to understand and control. It may be tolerable in small-scale embedded software, but outside of that we should make use of the better alternatives that modern hardware affords us.

I knew a professor who worked on Density Functional Theory which can be used to derive many of the properties of materials from first principles. (e.g. "Does Iron Conduct Electricity?") This involved running FORTRAN programs on what was then considered a large supercomputer (256 nodes.) Asked what he thought about any programming technique that cost a factor of 2 in performance and he told me it was a non-starter whe…

If that's his attitude then Hickey is right not to bother. Suppose Hickey puts in months of efforts and gets it so that you can apply the same technique with only a 1.2x performance cost. The professor is still going to dismiss it for the same reason.

Re: The Case Against OOP Is Wildly Overstated

#259
post #68

IMO, OOP just puts too many footguns at your disposal, the most dangerous one being mutability (how normal is it that our methods mutate instance variables?). The larger a system grows the more mutability will make it even harder to understand and control. It may be tolerable in small-scale embedded software, but outside of that we should make use of the better alternatives that modern hardware affords us.

Calling mutability an OOP issue doesn't make sense to me. You could certainly have immutable objects. You can event have immutable object inheritance. Maybe you just want a language where fields are immutable by default. If you're just passing around raw structs or arrays, it's way harder to manage blocks of data.

> Calling mutability an OOP issue doesn't make sense to me. You could certainly have immutable objects. You can event have immutable object inheritance.

When they're immutable they're not objects, they're just data. There's no need for encapsulation because if you can't mutate something then you can't break its invariants. There's no need for identity or references, there's no message-passing...

Re: The Case Against OOP Is Wildly Overstated

#260
post #4

This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful, and that statefulness is fine to freely sprinkle throughout your program.

> This doesn't speak to what I consider some of the most dangerous parts of OOP, which include the assumptions that tightly binding data and code is helpful,[...]

I don't agree at all. It's much more dangerous to separate data representation from the code that manipulates the data. I can't tell you how many bugs I've found and had to fix in large codebases (most of which are procedural-code-in-"OOP"-languages) that result from some horrific evolving arrays-and-records structure not recording intent and validity constraints properly (since that would require, you know, code). Instead, each interaction with the Holy Data Structure requires the code to go to confession, recite ten Hail Marys and five Our Fathers before receiving the Almighty's state-changing grace, mercy and peace; failure to do so will result in immediate confinement in purgatory, and possibly damnation.

I'm not being hyperbolic albeit a bit facetious about this. "Data" itself is the problem: it is subjective, and so requires a lot of tinkering for a programmer to grok. That tinkering transforms it into information, but only in the programmer's head, which is less than ideal since it's outside of the program. If that information fades away, it must again be rebuilt (or worse, be short circuited so a hotfix can go out to prod).

> and that statefulness is fine to freely sprinkle throughout your program.

I agree much more with this, with the condition that shared statefulness sprinkled throughout is the problem. An object should be treated with the same respect we would show a VM or even a person: decent ones would not tolerate having an external entity reach in and manipulate things like memory, nor would they be so care-free as to depend on and trust literally everything they are told. I think the big problem here is that few or no OO languages are powerful enough to allow for this kind of arrangement to be the norm. But it is a valid criticism and should be taken more seriously by OO language designers.

EDIT: I wanted to add one more thought, which is that when I'm working on a new feature or new codebase, I tend to model the problem first in a procedural style. Then I rewrite it as objects. I've had very little luck trying to do objects first (though I think this is just me), because decomposing the problem space is just hard to do de novo. But once I understand the problem, it's easier to see the constraints and issues.

Also, certain code that doesn't need to worry about things like noisy channels (e.g. Dijkstra's shortest path algorithm) is probably a good candidate for non-OO code. OO is good for the large amount of software that interacts with people across multiple machines and environments, rather than isolated from everything in just a single machine.

Post reply on HN