Live data from Hacker News

Case against OOP is understated, not overstated (2020)

boxbase.org

211–220 of 557 posts

Re: Case against OOP is understated, not overstated (2020)

#211

Earlier quoted context omitted.

> This is why simulations like say someone making a game or simcity with like relatively independent entities that map to something in real life use OOP. I don't think this is the case, or at least it hasn't been for quite awhile. Any gamedev I've known in the last decade or so would reach for an ECS[0] if they wanted to clone SimCity, in other words they would design it somewhat like a normalized database. Each char…

I appreciate that info! Its an abstraction that I had used in the past to demonstrate to other engineers that I have thought seemed somewhat useful about OOP, but as I was typing I thought to myself I'd bet that modern performant games wouldn't use active mutable entities but rather abstract into systems that change state at certain ticks so state can be much more easily managed, reasoned about and optimized. This so…

> This sort of begs the question: where does classical OOP, the one taught to all undergrad CS majors in programs that use Java or C++, really fit in nowadays?

As everyone is telling you, it’s a poor paradigm that makes the developer’s job harder compared to both non-OOP approaches and better approaches (mixins / multiple inheritance).

That said, one should be cognizant of the reason it was created in the first place - single inheritance allows C++ to implement fast polymorphism via virtual function tables.

Re: Case against OOP is understated, not overstated (2020)

#212

Earlier quoted context omitted.

Elegant Objects by Yegor Bugayenko actually argues against mutation in OOP for the same reasons that FP advocates due (bad for concurrency, hard to test, hidden state is hard to keep in your head, et cetera), but then all you get are namespaces with functions that act on a (usually) single data type (i.e. the class itself and its properties). OOP itself could be good for problems where you need state machines. The Er…

Nothing that the typical junior engineer does with OOP can't be done with functions and well organized files. If they can't be trusted to do that well they shouldn't be writing OOP code.

When everything's a function, junior programmers treat the entire set of available functions as reasonable things to call at any time. With OO, they at least have to think about how to organize things by which interfaces are available.

People love to hate on Java, but a Spring app with everything set up into a graph of interacting interfaces is about the most well-organized code you'll ever see, and it encourages modifications that maintain thoughtful organization.

Re: Case against OOP is understated, not overstated (2020)

#213

We have data and complex systems. No one, with the exception of Alan Kay, has convinced me that Object Oriented Programming is or was a good idea. “ … Because the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. “ —Joe Armstrong, creator of Erlang programmin…

But, thats exactly the reality of the problem, and exactly what you want. I work with robots, so much of it is physical. There are no floating bananas in the world. They're all held up by something.

Re: Case against OOP is understated, not overstated (2020)

#214

Earlier quoted context omitted.

In functional languages you can still ensure that only certain functions can change certain parts of the state. The big idea is that state is isolated. You can actually write functional code that looks a lot like OO code (essentially just calling `foo(thing)` instead of `thing.foo()`) but because state is isolated, you know that nothing is changing behind the scenes. It may not seem much, but it's actually really fre…

Let me separate out immutability for a moment. If I don't have immutability, then if I can call foo(thing), then I can write bar(), and then call bar(thing). Bar can now alter thing. So my encapsulation can be broken by someone just writing a function. (This is the same problem that C had with structs - anyone could write a function to alter the data in your struct, and thereby put it in an inconsistent state.) Now,…

Your last sentence there is pretty unnecessary. Moving along...

Echoing my sibling comment: immutability is a defining feature of FP, so there is no way to put it aside if we're talking about FP.

As for the rest of your argument, I'm a bit of meathead and maybe haven't followed it fully. My thought is that in OO, an instance of an object can be passed some data that it processes along with its own internal state. If that data is a reference to another object, then that object could be changed while the receiving object is doing its thing. The receiver then would go and store its results within itself.

In functional, functions receive everything as parameters and all that data is guaranteed not to change for duration that the function runs. Once it returns, it will update the global state and then, again as my sibling comment points out, it's far easier to check validity of the whole shebang as it's in one place.

As for "you have a lot less code to look through", I feel this is a common thing said by folks who have not really grokked how FP works. I say this because I used to make this argument ;P While FP can be slightly more verbose than OO, I've found FP way easier to figure out where things came from.

All in all, I don't have a vendetta against OO. I was really just trying to get across that I was a big OO enthusiast and went in FP perhaps even with a closed mind and it didn't take much to win me over. Having said that, I'm in the Elixir/Erlang world, which is a bit of its own beast.

(Edit: your/you’re/yore)

Re: Case against OOP is understated, not overstated (2020)

#215
For my part, I've tried to be as overstated as possible, as you can tell from the title "Object Oriented Programming Is An Expensive Disaster Which Must End." Written in 2014, and discussed several times here on Hacker News, it remains the most popular technical essay that I've written:

http://www.smashcompany.com/technology/object-oriented-progr...

Re: Case against OOP is understated, not overstated (2020)

#216
post #184

Earlier quoted context omitted.

>But FP isn't used so much for real world solutions It's taken over the front end. The react paradigm is FP. SQL read queries are FP.

And, in fact, much of the front end ecosystem is constantly getting ideas from Elm which is pure FP… and a pleasure to use (I think).

I work with Elm and yes I can confirm this

Re: Case against OOP is understated, not overstated (2020)

#217

Back in the 90s OOP was touted as revolutionary. The next big thing, would completely change programming. If something wasn't object oriented, it was looked down upon. SQL even got on the bandwagon. It was said that very complex inheritance structures, operator overloading, and all this other stuff would (somehow) make it far easier to write and understand complex projects. Many seemed to have taken and repeated this…

> Were there ever any real objective [hah] studies done about how much it improved software development? And did they show a significant improvement?

I think years of hard experience across the industry found out that, for example, multiple inheritance and operator overloading caused more problems than they solved. Both features were taught and advocated back in the day, and now "there be dragons" signs have sprung up and most of the literature today warns the journeyman programmer to avoid them.

Re: Case against OOP is understated, not overstated (2020)

#218
post #157

Earlier quoted context omitted.

> This is why simulations like say someone making a game or simcity with like relatively independent entities that map to something in real life use OOP. I don't think this is the case, or at least it hasn't been for quite awhile. Any gamedev I've known in the last decade or so would reach for an ECS[0] if they wanted to clone SimCity, in other words they would design it somewhat like a normalized database. Each char…

what about when the abstractions age and a new feature for a system needs the data from the components from another system? the long term answer is probably a refactor, but what's the common quick fix? copying/duplicating data between component types? systems that examine other components as well as their native ones? merging systems? asking the hard question... how does it stand up to the unpleasant cases?

> asking the hard question... how does it stand up to the unpleasant cases?

It's the best tool I know of for a certain class of problem, that's all I'm claiming. Not evangelizing it as a magical cure-all for all domains, just explaining it in enough detail that it can be understood by someone outside the domain of gaming.

> what about when the abstractions age and a new feature for a system needs the data from the components from another system?

> the long term answer is probably a refactor, but what's the common quick fix? copying/duplicating data between component types? systems that examine other components as well as their native ones? merging systems?

I apologize if I gave the impression that things are so tightly coupled that a system owns a component or vice versa. (Though if I had to pick one, it'd be that components have associated systems)

In reality your components are just plain structs, and any systems that want access can query for entities based on any combination of components. (and good ECS impls allow for exclusion as well)

For instance I mentioned a Position component. This would be used by a movement system that checks for (Position, Velocity). It would also be used by a rendering system, which could query for (Position, Mesh) or (Position, Sprite) as appropriate. It could be used for collision by querying for (Position, Bounds).

If later you want to unload entities that are too far away from a player, you could perform two queries: (Player, Position) and (Position), filter out entities in the second query that are within n units of an entity in the first query, and then despawn what remains.

No existing data or systems need to change to allow multiple systems access to the same data. The only thing that might change is if the engine provides automatic parallelization, and you have two systems that mutate the same data, you may need to define an explicit ordering for them and they would not run simultaneously. If you don't need explicit ordering you may not even need a code change in this case.

***

In the spirit of what you're asking though, let's say you've been making a tile-based game where the player can move between discrete spaces like in chess, but you decide you'd rather have free movement like Mario. Your Position component uses integers instead of floating point values and you don't want to change your world's scaling. Here you have a few options:

0. You could just bite the bullet and change the types on the Position component to floats instead of ints, and let your type system guide you to any errors. Then you run your test suite again and make sure that everything is still behaving as expected. I'd also plan on creating several new tests based on analyzing existing uses of Position. And of course play your game again to make sure it feels right.

1. You can store the fractional position in a separate component, PositionFraction, and create/update systems as needed. Movement would need to be updated to look for (Position, PositionFraction, Velocity) and rendering would need to be updated to look for (Position, PositionFraction, Sprite). Meanwhile pathfinding could still just look for (Position, Goal).

2. You can create a second component that holds the full float value called PositionFine. Like above you update the systems that care about fine-grained positioning to use PositionFine instead of Position. Then you create a system to update Position based on PositionFine's value or vice versa, and log anytime there's a discrepancy. Once you're confident that you can drop Position, you replace every use with PositionFine. Rename afterward as desired.

If I'm changing the meaning of an existing component like this, #0 would be my strong choice, but if the game is already in production and the migration needs to go over super smoothly I'd consider #2 as well. In particular you can treat the existing logic as the source of truth, but run the new logic side-by-side and log out any variation between the two for analysis before flipping the switch and preferring the new logic.

However if the new data is purely additional and makes sense being split off from the existing data, then #1 is the solution to use. Think migrating from displaying usernames over players' heads to letting them choose a custom name. You still need the username for authentication, save games, friends lists, and the like. But a new component for the display name lets you reference that when it makes sense.

Re: Case against OOP is understated, not overstated (2020)

#220
Here is a different take: OOP is not evil. State is not evil. They exist for a good reason:

Procedural is "linear" while OOP is "layered". One could write code either way but OOP better resembles the physical world and since brains have grown up in the physical world, layered code is easier to grok. It can hide/show pieces such that you can inspect functionality in a controlled way. Of course procedural can do the same with functions but it's coarser.

State is also a property of the physical world. Things persist, stuff accumulates, that's just how it is. Since applications ultimately model things in the physical world, they also have to persist things and accumulate things. State is inevitable.

OOP is a sharp tool and of course it's possible to use it well or cut one's self really badly

Post reply on HN