Readit News logoReadit News
dventimihasura · 2 years ago
Some people don't understand OOP, sure. That's the nature of things. However, many of us do understand. Consequently, nothing here comes as a surprise. And yet, we still think OOP has drawbacks where it's often applied, even if it has benefits in other applications. If nothing else, one benefit is that it helps us organize code segments and reason about function dispatch. One drawback is that it's not well-suited where it's often applied. This is the well-known "impedence mismatch." When that happens, it's worth asking if there are other ways to organize code segments and reason about function dispatch, which are better-suited so they don't experience these drawbacks. There are. Database constraints are one. Database triggers are another. They're not the only ones and they're not perfect, but then neither is OOP, and at least they have the virtue of being mated to the underlying data model perfectly.

Therefore, before we rush to say that other people don't understand OOP, perhaps we should consider the possibility that WE don't understand OOP if we insist on applying it where it doesn't apply.

golly_ned · 2 years ago
Did you read the article, or are you just responding to the title?
smitty1e · 2 years ago
The response has an AI pap flavor.
dventimihasura · 2 years ago
No, I read the article. Did you read my comment or did you just read the first line?
tialaramex · 2 years ago
Hmmm. I already don't like it when we're collecting together "procedures and state".

One of the most poisonous things about the "class" whether that's in Java or C++ is that it looks as though this procedure called "chirp" and this state called "loudness" are snuggled up together in my Bird class, after all in my source code they are literally on adjacent lines!

Of course they're not, the actual mechanics are the same as in say Rust, where "chirp" lives in an impl block, while "loudness" is part of the actual data structure, or a language with full blown Uniform Method Call Syntax where the relevance of Bird to a "chirp" procedure is just spelled out wherever "chirp" is defined, not in the data structure of Bird itself.

I think the heart of OOP is the opacity, the fact that we (for some definition of we) aren't allowed to poke around in the state directly, and this article talks about that idea at length, critiquing people who build a whole bunch of getter and setter mechanics for what is, in practice, just Plain Old Data and not really an object at all. So I think I'd start there, not by adding procedures.

So, I think a Doodad which may have internal state but we can't touch it, is an Object, even if there seemingly aren't any procedures for Doodads at all. But a Thingy, which has six named integers and a string inside it, that's not an object in the OOP sense, that's just some data, even if I have a whole tonne of procedures for Thingys.

This also makes sense when I don't have total information. If you give me a Thingy, I can do things with that, regardless of whether you provide procedures, but if you give me a Doodad, I can't do anything with that unless you provide procedures. Maybe you have procedures, but I can't necessarily use them.

randomdata · 2 years ago
> I think the heart of OOP is the opacity, the fact that we (for some definition of we) aren't allowed to poke around in the state directly

At the heart of OOP is being able to throw a message out into the world and maybe find another actor willing to respond to it. It is not so much that you are not allowed to poke around in the state of other actors, but that you fundamentally cannot know what other state exists without breaking the paradigm.

> So I think I'd start there, not by adding procedures.

Agreed. A thin veneer over internal state does not fix a break in the paradigm.

> if you give me a Doodad, I can't do anything with that unless you provide procedures.

You aren't even given Doodad, per se. Under OOP, you just send the message out there. If Doodad chooses to respond, then so be it. If Doohickey responds instead, such is life. Who responds is not your concern.

lioeters · 2 years ago
> If you give me a Thingy, I can do things with that, regardless of whether you provide procedures, but if you give me a Doodad, I can't do anything with that unless you provide procedures.

This is one of the issues I've experienced with overly eager "everything is a class" style of programming. The plain old data gets wrapped up and partially hidden, complected together with procedures.

The other aspect is that plain old functions get wrapped up too, and can only be accessed by instantiating the class, and complected together with state.

This style of code can make the underlying data and algorithms harder to work with, less flexible, too specific to the exact architecture designed by the author - especially as hierarchy of classes, which extend the "complectedness" in more dimensions where they're tied up with each other.

I just want typed and structured "thingies" as plain old data, that lets me reach in, access and modify everything as my own. Then separately, I want stateless plain old functions that accept those and other thingies of the same shape, wherever they come from, however they're created. That way I can use them by themselves, without being tied to any associated state, for my own purposes.

Sometimes I think the problem is too much "architecture", where all the parts are fused and can only be used together; whereas I prefer a "toolset" or "workshop", a coherent collection of parts that are independently useful and usable.

PaulHoule · 2 years ago
What all these discussions leave out is the importance of distributed object systems (COM, Binder, ...) and related technologies that played a prominent role in GUIs post 1990. Notably COM was designed so you could create "objects" in a non-OO language like C.

I see it as an important watershed because it seems to me the reliability and particularly performance reliability went downhill around the time this technology went mainstream. I remember plain old X Windows was rock solid but once KDE and Gnome came around that were based on this technology the Linux desktop became about as reliable as the Windows desktop.

Someone · 2 years ago
Could also be because when “KDE and Gnome came around” also was when X Windows started running more than XEyes, XClock and a few terminal windows, and grew extensions left and right to support new use cases.
pitched · 2 years ago
The C-style of OO, that is a struct of callbacks, takes a very tree-shaped execution graph of a single entry point and grafts on other random trees from who knows where. Extremely helpful when it’s helpful but a nightmare to debug when it’s not.

“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” ~Dijkstra probably?

smarx · 2 years ago
I think it's Kernighan, actually: https://www.laws-of-software.com/laws/kernighan/.
compressedgas · 2 years ago
Yes, GNOME was doing CORBA objects in C.
mathgenius · 2 years ago
For me objects capture some notion of invariants in data that would otherwise just be a bunch of variables. This is usually indicated by functions that act on the data maintaining the invariants. Those functions are the methods.

I get that many people either don't see, or don't place much importance on the invariants of their data and so they are happy writing functions and even get annoyed by people and their over use of objects. Maybe these people are just way smarter than me; I definitely need objects/classes to help me organize my code.

tialaramex · 2 years ago
I'm not convinced invariants are crucial. Common, certainly, but not crucial, I think the opacity is more important.

Take Rust's core::net::Ipv4Addr, that's obviously just a 32-bit value inside - it has no invariants to be maintained, but it's opaque, even though I know it's a 32-bit value, I am actually not able to just directly treat it as the value or prod that value, I have to use certain procedures, which include predicates (to ask if this is, for example, the broadcast address, or a loopback address) and some useful bit operations,

nicoty · 2 years ago
I’m not convinced you need objects to enforce invariants on your data. Why wouldn't you just use a good type system and type-checker to enforce those invariants? They could check if you're using data in places where they're meant to be, without having to bundle data with procedures.
nightowl_games · 2 years ago
At its core, I view OOP as organizing code so the data and the methods that act on that data are linked. Usually there are some compile time restrictions on who can touch the data. You are able to be sure some state is valid because only this class can touch the state. If you think of OOP like that, it seems trivially good. Surely a lot better than a bunch of raw data hanging out that anyone can mutate at any time.

Inside of some class, you can then implement whatever you want inside of that class, ie:struct of arrays, or w/e.

I don't view "inheritance" as a necessity of OOP. Composition fits great. I don't view "array of structs" as a necessity of OOP, nor over usage of heap allocations and pointer chasing. People associate OOP with this, but it's not fundamental, it's a poor, out dated mutation.

It seems like when people say "OOP is bad" they really mean "over abstractions are bad", and yes, they are bad, but "data oriented design" and "procedural code" isn't some silver bullet that's gonna save you from writing trash code.

Ultimately, I consider ideal code to be "verifiable on sight". Ie; I can read it easily and mentally verify that it is correct. Bad code is code that is very hard to verify correctness by reading. There's an art to this and it doesnt always fit into these semantic buckets of "OOP" or "Data Oriented Design".

munksbeer · 2 years ago
Quite honestly, software development is subject to fashions and egos the same way as say, the practice of architecture or interior design is.
roenxi · 2 years ago
Programming is mostly about understanding the problem domain. It is interesting that OOP had its heydey when everyone was building native GUI programs. The most likely situation was that programmers were developing abstractions that matched well to GUIs and those abstractions most closely mapped to OOP.

Things like functional programming, OOP, declarative programming, etc, might matter to language designers. They need these concepts to work out if their language is convenient/internally consistent/featureful and maybe these banner concepts help. Once the language has been built, I don't think programmers actually care. The abstraction isn't at the sweet spot where a developer gets the most power. The components of OOP (encapsulation, message passing, interfaces) are important and should be used liberally - but grouping them together under one heading is detrimental, because there will also be opportunities for other techniques from other schools of thought.

And as an aside inheritance seems to have been a mistake. I haven't seen a lot of places where inheritance was the best idea. Interfaces yes, inheritance no.

magicalhippo · 2 years ago
> I haven't seen a lot of places where inheritance was the best idea. Interfaces yes, inheritance no.

I like to use interfaces to expose the public side of things, but I find inheritance can be really powerful in terms of code-reuse for implementing those interfaces.

Of course if you got a language that makes encapsulation very smooth then inheritance might not be needed, but otherwise I find it can really cut down on code re-use and boilerplate to have a base class for certain interfaces.

Of course, since the interface is the public bit, if the base class is not a good fit for a certain implementation there's no requirement to use the common base class. So you use it when it makes sense.

randomdata · 2 years ago
> It is interesting that OOP had its heydey when everyone was building native GUI programs.

Erlang is probably the only OOP language in existence. I'm not sure it was ever the tool of choice for GUIs.

dventimihasura · 2 years ago
> The most likely situation was that programmers were developing abstractions that matched well to GUIs and those abstractions most closely mapped to OOP.

Bingo

randomdata · 2 years ago
Questionable. Qt signal/slot extensions were undeniably created to add OOP concepts to C++ for the sake of GUIs. You might, if you stretch hard enough, be able to make a case that Objective-C emerged for the sake of GUIs. But what else beyond that?

Smalltalk most definitely influenced how we thought about GUIs, but never really solidified itself as the place to develop GUIs. Class-based, non-OOP, languages seemed to be where most GUI development happened. And in large part were suited to the task. There was little need to introduce OOP.

There was COM and the like, which perhaps can reasonably be considered object-oriented, but only at a higher level of abstraction. The programming was not object-oriented. OO, but not OOP.

mcbrit · 2 years ago
I'm sure I'm butchering this, but...

Alan Kay: an object should be just as powerful as the entire computer, ie an object is a recursive structure.

The rest is implementation details. The implementation details chosen over the past many years, particularly those favored by OOP, generally involve making objects way less powerful than the entire computer.

bcrosby95 · 2 years ago
Correct me if I'm wrong, but can't you encapsulate data with c? It's been 25 years since I've used it but I thought it was possible.