Live data from Hacker News

OOP Is Dead, Long Live OOP

gamedev.net

291–300 of 357 posts

Re: OOP Is Dead, Long Live OOP

#291
post #118
post #94

Earlier quoted context omitted.

> as long as it is single-threaded Yet, there is a well-known pattern, which is to have objects each running on its own thread . (Incidentally, this gives a new - I'd say, true - meaning to the notion of 'message passing' as the idea of how objects are to communicate.)

How many projects do you know that do that? Yes, the original intent of OOP is message passing between objects. But no on thought about massive parallel computing back then. And how many objects do you want to run in its own thread? 10k? 100k?

This is called the actor model, and we actually implemented it in a prototype game engine once. We made one thread per CPU core and collected messages in "cycles" - where you'd process a batch of messages in parallel, which could produce the next batch. Messages would be sorted/grouped by target object address and then partitioned among the thread pool for execution. Most of the architecture was wait-free (no locks/atomics) so it really was quite fast. This resulted in a C++ framework where you could write 'typical' OOP code and it would automatically be deconstructed into call-graphs and safely scheduled for execution across any number of threads in a completely deterministic way, without locks. We abandoned the prototype because the "typical" OO behaviour of having deep call graphs is not actually something we want to keep, making the purpose of the framework kind of shaky. Also, while performance was good, the characteristics weren't quite suitable for games -- it worked best if you had large objects, receiving multiple messages each, doing computationally complex work. In our games though, we typically have huge numbers of very simple objects, so batching messages by class instead of by object typically gives the best performance.

Re: OOP Is Dead, Long Live OOP

#292
post #287

Earlier quoted context omitted.

Oh, that's very cool! I had a similar idea years ago, but I didn't have the technical chops to pursue it at the time, and I ended up losing interest. I think this would actually be even more useful in the kind of architecture I'm describing, since the accumulated state has a richer structure, and many of the smaller bits of state that would be separate objects are put into a larger context. > From what I've seen, str…

Interestingly, I think I built that project with an architecture somewhat reminiscent of the 'boundaries' concept (still just surmising at this point). It's a super simple framework with two types of things 'Domains' and 'Converters'. Domains are somewhat similar to a package... but with the boundaries actually enforced, so that you have to explicitly push or pull data through Converters to other Domains; Converters…

> Is your research related to programming languages?

Yep: I just finished a Master's degree with a focus on programming language semantics and analysis. I'm interested in all kinds of static analyses and type systems -- preferably things we as humans can deduce from the source without having to run a separate analysis tool.

> Also I'm going to have to think about "computing a new value" vs. "modifying state" —not sure I quite get it...

It's kind of a subtle distinction. A value doesn't need to have any particular locus of existence; semantically, we only care about its information content, not where it exists in memory. As a corollary, for anyone to use that value, we have to explicitly pass it onward.

On the other hand, mutation is all about a locus of existence, since ostensibly someone else will be looking at the slot you're mutating, and they don't need to be told that you changed something in order to use the updated value. (Which is the root of the problem, quite frankly!)

Re: OOP Is Dead, Long Live OOP

#293

Earlier quoted context omitted.

Duck typing is the worst of all worlds, in my experience. And in defense of inheritance, the Liskov Substitution Principle is extremely useful and makes a lot of sense. If a function accepts a `Weapon` as parameter, surely you should be able to pass it a `Sword`.

Except Firearms require the reload() method be called periodically between calls to use(). So now we have to think about whether Swords need an empty reload() method or whether there need to be separate Firearms and Blade interfaces based on Weapon.

"Swords need an empty reload() method"

That always seems to the problem with deep hierarchies after a while. Suddenly you have something where one of the inherited methods shouldn't be there. You can't take it away so you have to do something clunky like throwing an exception or making it empty.

Re: OOP Is Dead, Long Live OOP

#294

Earlier quoted context omitted.

Give it up. Mocks are mostly useless. If you want testable code, the first step is to separate computations from effects. Most of your program should be immutable. Ideally you'd have a mostly functional core, used by an imperative shell. Now to test a function, you just give it inputs, and check the outputs. Simple as that. Oh you're worried that your function might use some other function, and you still want to test…

That's a solid plan for acceptance testing and a great way to make sure you can never test diagnostic, recovery, rollback, and other something-abnormal-happened-here logic. For small programs with few interfaces to worry about, that might be fine, but as you number of users go up, the odds go up that you'll be ensuring rollback bits get flipped when filesystems fail. None of that is simple to test without some sort o…

Why would you use mocks to test those things?

Re: OOP Is Dead, Long Live OOP

#295

Earlier quoted context omitted.

The fact the the original code is a straw-man is discussed. The fact the flexibility is being removed is discussed too, along with why it was there and hits on better ways to re-achieve it later. It's mentioned that these were going to be covered in a follow-up. You need to work on your speed reading skills before throwing shade...

> The fact the the original code is a straw-man is discussed. Yes, but instead of timing it against the improvements the grand-author made to the straw man, you still timed it against his straw man. So I'll quote you: "You need to work on your speed reading skills before throwing shade..." > The fact the flexibility is being removed is discussed too You state: "Why do these frameworks exist then? Well to be fair, the…

Calm your titties my dude, you're angrier than me, here... You're still missing my point, claiming I'm making points I'm not, and insulting me for it. Grab a handful of good faith, please.

I timed it against the bad starting point because that's what Aras did too when showing that "ECS beats OOP by 10x". My version wasn't designed to be optimised - it was designed to be a simple rule abiding OOP rewrite. The point of the blog was about the annoying ECS evangelism trope of comparing ECS to bad OOP code and showing massive wins - the simple rewrite shows that the optimised ECS version is like a 1.03x win, not a 10x win.

The fixes that Aras makes to the starting straw-man code help perf, yes, but they fly in the face of idiomatic C++ and are still bad OOP. Still, I can update the graph is perf resufrom each of Aras's commits if it makes you happy.

Run time composition is(will be) added in the next version in a way doesn't add any performance overheads at all (a benefit of using composition properly that the straw man code lacks). There's no need for bloated frameworks to achieve this. BTW I'm also an engine dev, previously at a 400 person company, and now indie for a small team. I'm familiar with many kinds of entity frameworks... Making a game without one is perfectly valid. Many of the big commercial games that I've worked on didn't have one at all (just normal/good code)...

The particular ECS implementation from Aras (again its bad due to it being learning material, not a real project) has lots of holes too. The memory usage is atrocious due to it allocating one component per entity regardless of need, but he presents a memory-usage win against his straw man OOP version! His example framework also has silly restrictions on composition, such as a limit of one component per entity. This kind of stuff doesn't fly outside of toy game projects.

Re: OOP Is Dead, Long Live OOP

#296
post #294

Earlier quoted context omitted.

That's a solid plan for acceptance testing and a great way to make sure you can never test diagnostic, recovery, rollback, and other something-abnormal-happened-here logic. For small programs with few interfaces to worry about, that might be fine, but as you number of users go up, the odds go up that you'll be ensuring rollback bits get flipped when filesystems fail. None of that is simple to test without some sort o…

Why would you use mocks to test those things?

Because manually triggering an optimistic locking failure is a pain. Triggering one of those and a filesystem write failure at the same time is a whole pile of work compared to the mocking.

Re: OOP Is Dead, Long Live OOP

#297

Earlier quoted context omitted.

I was a programming teacher some years ago and I would sometimes grade two submissions, which had both gotten full marks from the automated tests but where one was 150 loc and the other 500 loc. The most surprising part was that if I read the longer submission first, it would never really seem like there was that much excess code to take away. But obviously there was. > My personal anecdotal experience is that OOP le…

I have a hard time getting on board with the "waste" or loc argument. The things that matter most to me are readability, organization, maintainability, etc. If the structure that provides those things results in there being more lines of code, or more "waste" then that's a price I'm happy to pay. The context you describe being a teacher is exactly the kind of case I was suggesting OOP may not be beneficial. If you're…

> I have a hard time getting on board with the "waste" or loc argument. . The things that matter most to me are readability, organization, maintainability, etc

I think people also have different ideas on readability. Some prefer a single file with 2k lines and some prefer 40 small files in 12 folders with 50 lines each. Like the parent says you can often write the same code in 4x length, be it to prepare for future features or just to have it look "clean".

"Good code" is different for different people.

Re: OOP Is Dead, Long Live OOP

#298
post #257

Becoming a professional Haskell and Erlang developer really shifted my view on OOP (let OOP denote class based OOP as found in Java or C++). In my view, OOP is prove a poor model for computation, and the result has been that OO code is almost always significantly more complex and error prone than an equivalent computation written in a concurrent, functional, or structured paradigm. Recent trends in language design (s…

Interesting view. How should i, as a sysadmin who just writes bash and powershell scripts, start to learn _serious_ programming? Is it still worth to force myself into OOP?

Start writing some of the scripts in Python, for example, quite popular in both sysadmin world and _serious_ programming world.

Re: OOP Is Dead, Long Live OOP

#299
post #177

All my attempts to jump off OOP train break at exact same moment when I try to write a unit test. Closure: or, simply use this monstrous component pattern when 70% of your code is boilerplate or hack into namespaces and override functions in them in runtime. And don’t forget to do it in right order! JavaScript: yeah, simply re-define ‘require’ before importing dependencies in tests. Yeah, do it in right order. Recent…

Dependency injection is probably my favourite paradigm out there, especially in a statically typed language: for the reasons you mentioned, and for discoverability with an IDE (or ctags). It is also a natural fit for “OOP”, or rather: classes. In a sense, it turns non-OO code into OO simply by storing the interfaces implementing the dependencies required by your code. If that’s your only state, are you still OO? I’d…

I second this. I think that a class offers a simpler contract than a closure or a curried function, with the difference that you use "this" to refer to the enclosed objects. However, the same keyword can be used to hide state and that can lead to obscure or unexpected behaviors.

Re: OOP Is Dead, Long Live OOP

#300

Earlier quoted context omitted.

I have a hard time getting on board with the "waste" or loc argument. The things that matter most to me are readability, organization, maintainability, etc. If the structure that provides those things results in there being more lines of code, or more "waste" then that's a price I'm happy to pay. The context you describe being a teacher is exactly the kind of case I was suggesting OOP may not be beneficial. If you're…

> I have a hard time getting on board with the "waste" or loc argument. . The things that matter most to me are readability, organization, maintainability, etc I think people also have different ideas on readability. Some prefer a single file with 2k lines and some prefer 40 small files in 12 folders with 50 lines each. Like the parent says you can often write the same code in 4x length, be it to prepare for future f…

Maybe. I suspect most people who say they prefer the java style are simply wrong. I don't think they've spun up on enough new projects to notice the extra weight that increased size and scale brings. Or they're assuming that the extra complexity is all necessary, and they're mistaken the same way I was while grading those assignments. (Aside: Isn't it super weird how reading code is so rarely encouraged at school?)

I suspect you could objectively measure this - take two implementations of the same problem; one small and one large but where the implementations do the same thing. For example, write a simple website using a stateful OO style. Then write the equivalent code using the mostly stateless react component style. The latter would be functionally equivalent, while using less code. The latter would also use much less local hidden state.

Then measure how long it takes new people to start making meaningful changes to the two respective codebases. I don't think its a matter of opinion or preference. I expect that the functional component model would come out as a clear productivity winner.

The easiest code to change is code you never needed to write in the first place.

Post reply on HN