5 ms·
> Abstractions like RAII, constructors and destructors, polymorphism, and exceptions were invented with the intention of solving problems that game programmers
by gregstula 11y ago
> Abstractions like RAII, constructors and destructors, polymorphism, and exceptions were invented with the intention of solving problems that game programmers don’t have
This is the only part of the Jai philosophy I struggle to understand. How is an explicit delete keyword better than deterministic destruction? From my perspective, the former method reintroduces the problem the latter method solves.
Also, polymorphism is bad for games now? I absolutely cringe when I see abstract base classes, virtual functions and classical inheritance, outside of a generic interface in 2016. However, games might be the one case I would strongly consider using those features as part of my design. For example, a Final Fantasy-style job system seems to elegantly lend itself to the "Intro to OOP with C++98" style of runtime polymorphism*
As for exceptions, well I think the reputation of exceptions is one of the great tragedies of C++. Rust, Go, and other new languages seem to have decided that regressing to pervasive error checking boilerplate is more elegant than to have exception handlers.
I think Swift got it right with scoped exceptions and a defer statement - although, they selectively use "error handling" as double speak to avoid saying the e-word.
*Although, I personally think interface/protocol based solutions have proven to be the cleanest way to tackle polymorphism -- this is possibly true even in the case of an rpg with class inherentence as a game mechanic.
- w0utert 11y ago>> This is the only part of the Jai philosophy I struggle to understand. How is an explicit delete keyword better than deterministic destruction? From my perspective, the former method reintroduces the problem the latter method solves. My interpretation of statements like "problems game programmer's don't have" is that they don't mean game programmers don't run into situations where things like RAII or polymorphism would be useful, just that the stereotypical game programmer doesn't care about using them because they have their own ways to get the same results. Which often involves programming practices that aren't considered safe for most other application domains. The thing with 'game programmers' when referring to people like Jonathan Blow and e.g. Casey Muratori (who does Handmade Hero), is that they have been writing the same kinds of systems for so long, and have developed so much 'muscle memory' to avoid the pitfalls of their coding style, that they appear to have gotten a blind spot for all the deficiencies in the code they write. It works, it's efficient, and someone with the same mindset could make progress on it despite of the minefields they've created, but it's usually not 'good code'. The Handmade Hero code for example is atrocious if you ask me. It never ceases to amaze me how people who are so smart, much smarter than myself, fail to acknowledge all the ways in which they could write better code without throwing out any of the goals they've set for themselves (performance, compilation speed, predictability, ...). All things considered, it does not surprise me that so many games ship in a half-broken state.
- ilek 11y agoOut of interest, why do you think the Handmade Hero code is atrocious? I haven't kept up with it so I don't have much of an opinion.
- gregstula 11y agoIt's gross because it's written in "C with namespaces and overloading" Preferring #define for constants over constexpr is 100% the result of C++ bigotry. It's a laughable decision. constexpr gives you the power of typesafe, compile time evaluation of purely functional expressions with type deduction. #define gives you a compile time 1972-style copy-paste
- ilek 11y agoI agree with things like these, I think Casey and other programmers like him are too far in the camp of C++ is just C with classes. From what I have seen of the code and videos, I think his general structure of programs is off. I'm no advocate of "every function has to be at max N lines" or "every file has to be smaller than N lines". But I think there are issues there, and I don't think it can be defended just because it's a game, where a lot of general practices go out the window.
- w0utert 11y agoListing all the things bad about it would take me the rest of the afternoon, and likely evoke many replies along the lines of "you don't understand why he does it that way, it's supposed to be handmade, so you can't have all the nice things", like last time I commented about the HH code. The executive summary would be that the code is basically full of unsafe code, pointer chasing, half-hearted argument/input validity checking, no memory management, no abstractions of the higher-level parts of the code, it uses none of the idioms we've learned through years of writing crap code to avoid common mistakes (RAII would be a good example, etc), doesn't use 99% of the language features C++ offers over C. Casey himself dismisses these things as adding unnecessary bloat and/or mental overhead, that they have no benefits for his purpose, and that the way he writes code you don't need them, but I just flat-out disagree with that. Let me make clear that I'm not saying this because I don't like HH or because there's nothing to be learned from it, just that the results you get from this programming style should not be taken as an example. The quality of the code is immediately apparent if you watch Casey work on it in the streams, almost every line he changes breaks something somewhere else in the code, often even multiple things.
- alaties 11y agoWould you mind explaining or linking to a good document on "C++98 style runtime polymorphism"?
- deleted 11y ago[deleted]
- autoreleasepool 11y agoYou can do a google search for this information
- CyberDildonics 11y agoThere are cases where virtual functions lend a lot of flexibility, but for games they are usually a sign of a programmer that doesn't understand how pointer chasing destroys performance. If you look at Ogre (and I think box2d) both architectures could be massively sped up by not using arrays of pointers.
- deleted 11y ago[deleted]
- pandaman 11y agoGames (I am talking about AAA here, have no idea about all possible games) are not written in the style that leaves place for constructors/desturctors. The data is better in tables (i.e. arrays) than spread all over the memory and accessible through a pointer network. The reasons being: a) walking an array is orders of magnitude faster than walking a pointer chain and b) heap allocation wastes more memory This, in turn, makes no sense for polymorphism since you already have uniform data in the arrays there is no need to do an expensive indirect jump to figure its type.
- gregstula 11y agoWhy couldn't you use a structure to encapsulate the table and then have the destructor to deallocate the the array? This is how vector works.
- pandaman 11y agoYou could, but why? To compensate for the lack of construction/destruction of the array's elements? Practically these arrays never go away so there is little point in deallocation anyways.
- autoreleasepool 11y agoIf you're using C++ you're still using default destructors even if you don't write them. In C, you at least get deterministic destruction for variables and structures on the stack. This isn't something you really opt out. It's there by default. The parent was wrong about vector though, it won't safely free elements that do not have their own destructors to clean up their own resources. Another good reason to use RAII everywhere. It costs nothing, to encapsulate memory management. > You could, but why? Because there's zero overhead and you guarantee to be passively covered in the few edge cases where you do end up needing deallocation. Now you don't have to worry about special handling of edge cases and you have a more general purpose data structure. A better question is, why not? It's simply a better designed and more flexible container than a raw array. Other than a bias against C++isms, there's no good reason to avoid these useful features.
- BSVino 11y agoHey there. I wrote the Jai Primer. Ideas there are my best interpretation of Blows ideas, which I generally agree with, but bear in mind they're not his. To quote Joe Armstrong: You wanted a banana but you got the gorilla holding the banana and the whole jungle. You wanted a way to delete memory automatically, which sounds great but in practice most language's approaches to solving this problem come with a host of other problems that at scale make the given solution not worth it. RAII solves a big problem but it introduces a bunch of tiny problems like big mysterious constructors that implicitly do a lot of work and deconstructors that don't map to any particular line of code other than an ending brace. It's tough to examine in a debugger, it's tougher to reason about when it gets to nontrivial scale, etc etc. But human brains naturally weight a lot of small pains to be less bad than one big pain, so the solution looks legit. Polymorphism is a way of modeling the world that runs along the lines of the categorizations that people tend to make, so it feels natural to create deep class hierarchies. But in practice it doesn't match the problem that you need to solve when you make games - you have data in state A and you need to get it into state B. Example: to do a physics integration on each simulated body, the CPU wants to do a for loop over a list of position vectors. But those vectors have been scattered all over memory by the class hierarchy. So that's one problem, you also get problems like needing RTTI and casting and yadeya. Class structures have largely fallen out of vogue in game development in favor of component systems, which is a pretty good step forward.