Live data from Hacker News

Modern C++ gamedev: thoughts and misconceptions

vittorioromeo.info

171–180 of 221 posts

Re: Modern C++ gamedev: thoughts and misconceptions

#171
post #6

After years of experience writing code for games, I find that the dumbest code is the best code. It doesn't matter if it's C# or C++, whenever I've used something like reactive extensions or template metaprogramming, it has been a terrible mistake every single time. Make your code simple, dumb and verbose all the time. Avoid using any complex abstractions or any overcomplicated syntactic sugar and you'll have a codeb…

> Avoid using any complex abstractions or any overcomplicated syntactic sugar and you'll have a codebase that anyone can jump into and quickly be able to add features without introducing bugs (at least less likely).

The thing is what is complex abstraction changes with time. At one time, floating point, especially transcendental functions would have been a complex abstraction. Functions at one time were a complex abstraction. Classes and polymorphism were a complex abstraction. Pointers are a complex abstraction for a lot of people. Linear algebra is a complex abstraction. Transforms are a complex abstraction.

Many times “complex abstraction” just means “an abstraction I am not familiar with”.

Back in the 80’s most games were written in assembler. I am sure many people thought that C was a complex abstraction. I mean, instead of just doing a jmp to a location, now you had a stack and a calling convention and which registers to save and restore...

Since “complex abstraction” is often code for “unfamiliarity”, education, like what the original article is doing is very helpful in moving the state of the art forward. As people become familiar with new abstractions, that becomes the new baseline for “simple” code.

Re: Modern C++ gamedev: thoughts and misconceptions

#172

I don’t think this really covers the whole topic, but yeah the Twitter thread is toxic in the exact way most threads are tbh... I’ve been using C++ for about 15 years now, and also tbh, and dislike just about everything beyond 11-14. The cognitive load reading code has just skyrocketed. The simple basis of the issue was when the meaning of existing syntax elements being “overloaded”. &, &&, [] in my mind. It is not c…

Kind of agree, and the root cause may be backwards compatibility so another construct is invented which is slightly different.

The other day I explored std::promise and std::future, only to realise that all it is under the hood is a semaphore (which starts with count of zero) and a pointer. The promise.set() updates the pointed memory and releases the semaphore, while future.get() waits for the semaphore and reads the memory. My workaround was just as many lines of code with abstractions that are no more complex. So whats the point of promise/futures? Async adds spawning a thread to the mix, yet another unneeded abstraction. Coroutine adds more. Just be done with this and add proper Actor model and call it a day.

Re: Modern C++ gamedev: thoughts and misconceptions

#173
post #32

Earlier quoted context omitted.

> Not always, though. See every bug and exploit with C arrays ... That can also be perceived as a a flaw of the language design in that it does not allow one to write dumb, safe and fast code. Which are such languages in existence today? edit: fixed typos

I would say Java, which I suspect is bound to be a bit of an unpopular opinion here (I expect more startup people than enterprise denizens in HN); but the more I think about it, the more sure I'm that it fits the bill: - Dumb: you bet. The inclusion of lambdas has shaken things a little, but usually Java code is straightforward with little space for "cleverness". The counterpoint to this, of course, would be the meme…

- Dumb: you bet.

Java as a language is dumb, but as an overall platform is not. In a way it is a two-layer platform: you have the outer layer, a boring language that is used by a lot of people to write most of the code, then you have a hidden layer, that most people ignore, made of bytecode manipulation, runtime code generation and language agents that let you do cool things like adding compile-time nullness checks, generate mapping classes to avoid writing a lot of boilerplate code or good old ORMs that automatically generate your sql queries for you.

Such functionalities are not exactly easy and straightforward to use, but in my opinion it is a good thing: they are there and can be used, but for most programmers will be hidden behind a few "magic" annotations.

This is in contrast to other languages where the advanced functionalities are "all over the place" and every programmer must be aware of them (I'm thinking of C++ and Common Lisp for example).

If you have a teams of great programmers you may achieve better results with the latter approach, but for the average company the Java approach is better because you can have average programmers write boring code while taking advantage of a few clever tricks here and there by using libraries/frameworks written by better programmers.

Re: Modern C++ gamedev: thoughts and misconceptions

#174
post #6

After years of experience writing code for games, I find that the dumbest code is the best code. It doesn't matter if it's C# or C++, whenever I've used something like reactive extensions or template metaprogramming, it has been a terrible mistake every single time. Make your code simple, dumb and verbose all the time. Avoid using any complex abstractions or any overcomplicated syntactic sugar and you'll have a codeb…

> Avoid using any complex abstractions or any overcomplicated syntactic sugar and you'll have a codebase that anyone can jump into and quickly be able to add features without introducing bugs (at least less likely). The thing is what is complex abstraction changes with time. At one time, floating point, especially transcendental functions would have been a complex abstraction. Functions at one time were a complex abs…

> Many times “complex abstraction” just means “an abstraction I am not familiar with”.

A lot of times it can also mean "an abstraction that my development environment is unaware of or otherwise has deficient tooling for"

Re: Modern C++ gamedev: thoughts and misconceptions

#175

Earlier quoted context omitted.

I'm a C++ developer who occasionally writes Rust. The experience of writing new code in one is very, very similar to the experience of writing new code in the other, right down to the compile times. The lifetime analysis in Rust is nice and pretty far ahead of what static analyzers can do in C++, but Rust Generics are a pretty weak approximation to Templates. Rust has better Browser integration, C++ has Qt. One imagi…

As someone who built a career in C++ I like that Rust's generics are a poor approximation of templates(and that includes having worked with some of the modern C++ features). I have months of my life I've lost to the increased compile times from Boost on the applications I've worked on. C++ also makes it way too easy to reach for shared_ptr instead of unique_ptr leading to all sorts of unfortunate things. Rust makes t…

I would pick C++ for anything to do with high-performance linear algebra. There are a few other domains (desktop GUI, CAD) where I don't trust the Rust library ecosystem.

But, yeah, there are a ton of domains (notably embedded) where I would want Rust.

Re: Modern C++ gamedev: thoughts and misconceptions

#176
post #53

Earlier quoted context omitted.

No coding approach will ever solve an issue caused by a lack of discipline.

Not so much 'discipline' as mastery . You have to know your trade, and there will never be a way around it.

The mastery comes in at the specification level, though -- or at least, it should.

Ideally, a program's specification and implementation would be one and the same. The more the program departs from a plain-language specification, the more room for error exists, and the more discipline is required to avoid those errors.

IMO, what we need are better specification languages and better tools to compile them, not better programming languages. I believe we've gone as far as we can go with the latter. Some might even say that watershed was crossed in the COBOL era.

Re: Modern C++ gamedev: thoughts and misconceptions

#177

Earlier quoted context omitted.

Move semantics and rvalue references are too complex and error prone to be useful in general code. It is best to use them only in performance sensitive places and containers.

I strongly disagree. Move Semantics allow you to communicate ownership information at API boundaries with the type system. C APIs come, of necessity, with tons of documentation about who is deleting what, when. Or, you know, maybe they don't and you have to learn the hard way. std::unique_ptr (implemented with move semantics) largely solves this problem. And you can imagine notions of ownership more complex than "I'm…

If you read carefully, I said use move semantics to implement containers. That includes std::unique_ptr (a container for pointers with a deleter).

The point is that you shouldn't be using rvalue ref parameters, std::forward, etc. in most of your code. Even std::move should be fairly rare.

Re: Modern C++ gamedev: thoughts and misconceptions

#178

Earlier quoted context omitted.

- winterismute questioned qualifications to have a position on writing C++ for game dev. That is gatekeeping and No True Scotsman. - At least someone on Twitter called some tweets "retarded", etc., so OP thought to continue the conversation by ignoring nonsense and restating concerns in a healthier tone. This post is his attempt to be productive, apparently. - Any perceived slight against you, you have inferred. No o…

> winterismute questioned qualifications to have a position on writing C++ for game dev. That is gatekeeping and No True Scotsman Well, not really. Some of the people on twitter (and the author himself) basically pointed out that "one of the main reason we do not use that coding style is that, despite the advantages, when you need to work on a codebase that requires both performant simulation of the planet and rapid…

The piece makes the point that the features presented have negligible to no downsides in the context of gamedev (and other contexts as well), and your argument doesn't refute that other than by assertion. It instead tries to disqualify the relevant points based on the credentials of the author.

While making big assumptions about the author's experience in the process. It's plausible he has experience in complex, performance-sensitive, highly collaborative C++ as well. The whole argument hinges on partial information and disbelief, really.

Re: Modern C++ gamedev: thoughts and misconceptions

#179

Earlier quoted context omitted.

I strongly disagree. Move Semantics allow you to communicate ownership information at API boundaries with the type system. C APIs come, of necessity, with tons of documentation about who is deleting what, when. Or, you know, maybe they don't and you have to learn the hard way. std::unique_ptr (implemented with move semantics) largely solves this problem. And you can imagine notions of ownership more complex than "I'm…

If you read carefully, I said use move semantics to implement containers. That includes std::unique_ptr (a container for pointers with a deleter). The point is that you shouldn't be using rvalue ref parameters, std::forward, etc. in most of your code. Even std::move should be fairly rare.

Any time you want to pass a named unique_ptr across an API boundary, you'll need to std::move it

Re: Modern C++ gamedev: thoughts and misconceptions

#180

Really the “problem” here is that C++’s functional constructs will never allocate memory, giving them somewhat strange signatures that don’t really conduce themselves well to typical functional concepts. At compile time there is no such goal and as such some of these constructs can only be found there.

According to https://en.cppreference.com/w/cpp/algorithm/stable_sort : > This function attempts to allocate a temporary buffer equal in size to the sequence to be sorted. If the allocation fails, the less efficient algorithm is chosen. Or is this not what you consider a "functional construct"?

I know some basic C++ and STL. Is there anything like streams in C++. I mean things would be as easy as vec.stream().map(lambda).fold(T::operator+), so it wouldn't require any more allocations than those done by copy constructors.
Post reply on HN