Why Rust Is the Future of Game Development
thefuntastic.com
thefuntastic.com
In games, that's a safe assumption for many parts of the system, since you're definitely only going to be running one instance of the game world at a time. So making that state private just means you have to pass around references to it on the stack, and keep track of what you're doing.
But not if you actually have to keep things around in-memory. Then all the sudden your functions can’t be pure, you have to add additional parameters to each method to account for additional state, and you can’t design flat structs anymore since you have many different object types and they have to go somewhere and you can’t just declare N variables line by line. So you have to grapple with the limited definition of trait objects, or non-extensible enums, or throw everything out and use Any. It gets complicated.
As an alternative to C++, JAI is more promising in my opinion.
Jonathan Blow has a reputation for taking a rather long time to release something eagerly awaited, and the result being impressive and critically acclaimed.
I hope Jai will be the same way. We'll see what happens.
Languages are ecosystems. They have tools, and libraries, and shims to integrate with other tools. They need evangelism. They grow with community involvement. As far as I know, no one has ever released a new language that was perfect in its initial release - there has always been feedback and syntax quirks that get addressed in future versions.
If a "0.1" compiler with warts was out there for people to play with and improve on, I'd have faith. But if you can't get a demo that you're willing to share within 5+ years, then I have very little faith you'll ever release anything, and absolutely zero faith that you'll be able to compromise your mental idea of perfection enough to build a thriving community around a product.
There are private betas available by the way.
"Machine learning let me train my dog twice as fast."
"How AI will revolutionize marriage counseling"
"Study: Using Go results in 10% better senior programmer retention"
To me it seems like this would require a significant adjustment in how certain problems are approached, but the outcome would likely be more effective development as you could eliminate a lot of cost that's spent dealing with bugs in the future.
I'm certain that Rust will help some parts of game development a lot, but I'm also certain that game developers sometimes use tricks safety of which cannot be proven by Rust's type system.
It is not as "safe" as Rust without "unsafe" blocks, but it is still reasonably safe.
But circular structures are usually a bad choice.
It can be done "safely" in Rust, as in without actual bugs; it can't be done in "safe Rust", that is, Rust without `unsafe{}` blocks. But it's reasonable to assume that any Rust game would make liberal use of `unsafe{}` blocks, because as we have all agreed, game developers don't actually care that much about memory safety anyway.
As such it seems wrong to suggest that the primary barrier to Rust in games development is its memory safety. Perhaps the culture of today's Rust community that shuns `unsafe{}` is unsuitable for games development, but Rust offers plenty of advantages beyond memory safety, and in contrast with C++ the particular advantages I would see as most relevant are:
- no legacy types/structures, important when you have a large team on a shoestring budget working late nights with sporadic communication; there will be fewer discrepancies in code styles
- potentially faster compile times than C++ when Rust is more mature
- distant future item, but there's the possibility for better FFI with game scripting languages when Rust is more mature
None of the above really depends on memory safety except kinda the FFI, but it's all relevant for a game dev.
While the adoption of "safe Rust" has left the tarmac, the best practices and widespread use of "unsafe Rust", a perfectly reasonable language in itself, have barely begun to develop. It's likely that any Rust games will generally be written with lots of `unsafe{}` and while nobody would learn Rust to use `unsafe{}` specifically, game developers might learn mostly safe Rust in CS courses that cover systems programming and then take those skills to the game industry and already know most of what they need to ramp up on an unsafe Rust codebase.
That last sentence is also why I think the Rust games era is at least a decade away; game shops don't usually want to retrain their employees on new languages; they'll just use what's in the field. That's also why Rust will probably beat out Zig (or Nim/Jai), since even though the latter is a little more suited for games, the former is much more likely to be taught in schools.
First cargo needs to also handle binary dependencies, and C++20 has modules now.
I'm open for discussion as I haven't been able to convince myself of the use of any linked list.
Enterprise developers often look very poorly upon the solutions that game developers come up with, but game development is an entirely different realm, very far away from any enterprise software development stuff I've worked on, or even heard of. I've looked. I didn't believe this myself for a long time.
Games have very strict performance requirements that enterprise software simply does not have. Virtually no one in enterprise software cares about performance, really, and certainly not as a primary concern. Enterprise developers will often just throw more RAM or CPU at the problem until it goes away. I mean why not, that's an option that is on the table. Of course they're going to take that route sometimes. Game developers can't do this, because they're not in control of the hardware that their game is run on.
Games are often scored on how good they look, and how well they perform. Game sales are a function (at least partially) of the score/rating that the title attains, and game developers are paid out of the money that game sales provide. Concerns that do not result in an improved critical game rating are secondary. So, there is a very strong hunger there for performance which simply does not exist in other software development fields. Until enterprise software developers are paid based on the performance of the applications they write, no one who has NOT developed a game and fought performance problems along the way can ever understand.
There are games which consume nearly the entire bandwidth between CPU and RAM on a modern PC -- continuously -- and this is after many optimization passes to prune the data that is needed from RAM at any particular moment in time and make it as small as possible.
Game development is just an entirely different thing than any other kind of software development. Languages created with general purpose use in mind may achieve (and have achieved) some success in game development, but those languages will get in the way of the developer at least as often as they aid the developer. Same rule applies for general software engineering rules.
In the indie space, you see a lot more titles where performance is a secondary consideration. The concept (and the style of the visuals) is often more important than having cutting edge graphics.
There are also segments of the business that are more like enterprise software. If you look at something like League or WoW, you have titles that are continuously evolved over many many years, and getting the infrastructure right matters a lot.
With the added mention that the game still has to run smoothly, otherwise it's extremely annoying, no matter how great the concept.
In game development, if you introduce a bug that causes a game to not function, you must fix it right away because you may receive lost business and possibly a death threat.
further, the whole point of rust is that is fast and safe.
safe doesn't imply slow.
a lot of game development is entity component systems, and there are several of those for rust - it will be a matter of time until these are good and fast enough to be used in larger and larger games.
You are missing the part about wasting hours or days to investigate the crash, easily offsetting the time saved with fast and loose coding.
It would be nice to see examples to judge whether a stricter language like Rust can save more time on the debugging and fixing side (by reducing mistakes) than it costs with verbose syntax and "unnecessary" safety mechanisms on the design and coding side.
For example, consider a function for 16 byte equality:
fn equals(v1: [u8; 16], v2: [u8; 16]) -> bool {
v1 == v2
}
rustc emits a branch to test if v1 and v2 point to the same thing, which is unnecessary (it can never be true!) and can ruin loop vectorization, etc. The useless branch is not serving any safety purpose but requires unsafe to avoid.https://rust.godbolt.org/z/6973jG
The efficient version is quite a bit more verbose :(
In this godbolt [0] I tried using the safe version of equals with two values (from stdin so it can't just optimize the computation away, though I don't think it would) and it seems that when the compiler inlines the equals function, the inefficiencies are removed (which can be seen in the example::main section of the output; lines 212-216 look nearly identical, if not identical, to equals_unsafe in your example).
Please let me know if I'm missing something or if there are any other safe APIs to be wary of.
IME Rust is more dependent than C++ on these fragile optimizations. I think it is because idiomatic Rust is more abstract, and also because C++ has more advanced specialization features which allows implementing optimizations directly. For example in C++ you can say "if the type is uint8_t then do this instead..." but this is harder in Rust.
You asked for other examples: consider a simple operation over an array, like bitwise not. A C-style for-loop does the obvious thing but idiomatic Rust emits a gazillion one-byte 'not' instructions. This doesn't involve 'unsafe' but it does illustrate that you really do have to babysit Rust to get efficient codegen. https://rust.godbolt.org/z/PjW5vo
(In fairness C++ has its own stupid pitfalls too: https://travisdowns.github.io/blog/2019/11/19/toupper.html)
That's true, and while I agree that it is a concern, is there ever a way to gain both ergonomics and optimization? In other words, aren't we always leaving it up to the compiler one way or another? You mention C++'s specialization, and I suppose that is a solution, but then you are (potentially, I can't say for certain) sacrificing compile times. Although I will admit that this is probably a fair trade for certainty of optimization, and it would be nice if Rust at least offered some amount of specializing.
> you really do have to babysit Rust to get efficient codegen. https://rust.godbolt.org/z/PjW5vo
Oh wow, that is interesting. Yeah, that probably speaks to Rust still being a relatively new language, although I would have expected LLVM to do something about that... In any case, that's certainly no zero-cost abstraction.
Thanks for the neat info!
Reminds me of the time we had to write a high performance SQL engine at university. In Java, and it boiled down to exactly the same realization: We spent a lot of time babysitting the GC instead of actually making the actual SQL engine better.
The plan was to use C++ instead, but that option was dropped by the lecturer shortly before the project started :/
1: https://doc.rust-lang.org/src/core/slice/mod.rs.html#6610
A lot of the time, a game's bug surfaces in a way that will never cause a crash: it's just undesired behavior. At some level, the behavior can be defined in terms of "must" and "cannot" constraints, RFC-style.
And in theory you could do some kind of automatic verification of each behavior. But...the majority of the plumbing of the game isn't in the rule logic itself - almost all of the rules are simple. It's in making sure that the mutations produced by one rule will flow neatly into the next, without introducing some form of synchronization bug. This is a real minefield because you're often iterating over lots of similar elements, and it can look like you can bundle their update code to look "clean" or present an opaque interface, but then in practice, you need to split out the iteration differently to resolve a dependency issue.
Developers responded to this by introducing an event-bus abstraction, with bubbling and priorities and all the bells and whistles. But that doesn't really solve having dependencies, it just presents another way to surface a scripting layer.
Repeat this class of problem enough times and you will start inlining the bulk of the update into a single main loop, because that makes manual review of the dependencies more of a spatially engaging process, one where you don't have to provide new boilerplate so that the build process can tell you that you screwed up: instead you just look carefully, see that the ordering is wrong, and shovel around the block of code. Done.
And while you can do this in Rust, it renders a great deal of the language irrelevant, because the features it helps most with are those parts where you want tighter access control across function boundaries. When you start leveraging that access model, behavioral changes can start to take hours instead of seconds, which makes it appropriate for inner-layer backends that need deep optimization, but ergonomically terrible for the greenfield case, which is what games need to bend towards early in production when major features might be changing.
One of my first experiences interacting with a golang programmer, was in the context of my game server project. As an optimization, I had a race condition in the code that disconnected clients. After all, if the connection is about to die, I don't care if it dies in frame n, n+1, n+2...etc. This golang programmer was totally out to tell me I'm stupid, ugly, and bad, because I should always be using -race and always have 0 race conditions.
Like, it would have been one thing if he could've had a cogent discussion around how the build should be free of warnings, because that makes such signals super clear, but no, it was just pure dogmatism.
Additionally, object ownership can be unclear in a game development setting, which typically makes use of global variables for state.
In ECS, why should object ownership be an issue? The Systems can just own everything.
Perhaps you are aware of all these subtleties and knew it was ok in this case.
If the other party really had an interest in understanding, and not just condemning, he would've looked for more facts. He wouldn't have been talking over me and cutting me off.
Bullshit.
How many games have had releases delayed and major wrenches thrown into marketing plans because of progress ruining heisenbugs? How many failed certification passes from banal data races and other undefined behavior?
We trap UI in actionscript or javascript, and gameplay programmers in other scripting languages - perhaps python or lua - for faster iteration times, hot reloading, and safety. Because it's difficult enough to keep the build stable when it's merely all the engine programmers who should know better screwing things up with C++.
This results in large messes of poorly performing, poorly optimized, garbage-collector laden code that Rust would handle much faster. We're leaving lots of performance on the table, often for little other purpouse than "safety".
Console first day patches may have taken off some of the pressure for getting the first release right, but handhelds aren't always online and still have a pretty high bar.
> the optimizations required are typically unorthodox
Rust's `unsafe` keyword and intrinsics let you do all the unaligned intrinsic-laden data-racey technically-undefined-behavior micro-optimizations you might want to do in C++ in Rust just fine.
It'll hopefully trigger a more stringent code review and force you to justify your pile of bugs, but that's a good thing. Or you can skip the code review if your entire company really disagrees.
> a super strict language slows development down
C++ is also super strict, just in an unenforced-at-compile-time way that result in plenty of late nights chasing heisenbugs. Don't get me wrong - language strictness can slow development down - but that's one of the reasons people eschew C++, too.
As for C++ vs Rust? I'm going to spend more time and be far less certain of catching the issues in a C++ code review than I would be in a Rust code review. And while it took a few months for my development speed in Rust to catch up with my development speed in C++, it did happen.
Rust merely forces you to acknowledge when you're being sloppy.
> Additionally, object ownership can be unclear in a game development setting, which typically makes use of global variables for state.
I have solved so many sources of endless heisenbugs by eliminating some of these global variables. John Carmack as far back as 2013 was using phrases like "horror show" to describe similar parts of his own codebases[1] and has been agitating for more functional styles.
An unclear mudball of global variables is entirely possible - and easy - in Rust if you really want that. You merely need to make it either thread safe, or resort to `unsafe` if you really can't tolerate the overhead of not having threading-related heisenbugs.
I am a game developer that mostly works with c++ and my answer is none so far. The projects delay but nor because of the language.
Undefined behavior is c++'s strength. If it was not, we wouldnt have it in the first place
At every single studio I've worked at I've helped build out crash collecting, symbolizing, or deduplicating infrastructure just to get a lead on where shit is exploding, and seen major productivity outages when tooling crashed frequently enough to disrupt the workflows of my coworkers. Address sanitizer, valgrind, extra debug allocators - I've sunk a lot of time into just making these crashes shallower to debug and quicker to catch.
One of the smallest and quickest projects that comes to mind was an NDS -> iOS and Android port. Do you think most of the time was spent in porting APIs and control schemes? More than half the time on that project was spent just chasing down really stupid memory related crash bugs that were exacerbated in frequency and time by the port. I made damn sure to communicate my concerns about the schedule, and if my memory serves me correctly, we managed to soft launch "only" a week or two late.
C++'s strengths are it's lean portability, speed, and huge existing codebases and tallent pools. Undefined behavior is simply the cost we begrudgingly pay, not it's strength, and even that we often mitigate by trying to figure out ways to write as little C++ as possible - keeping it only for the parts of our codebase that are actually performance sensitive. Tooling is often C#, Python, anything but C++. UB is a pox and constant time sink.
Whenever people call out C++'s UB as it's strength, I'm left wondering how many of their bugs do they actually fix, and how many are begrudgingly fixed by their coworkers. Most of the people whom I've worked with with that attitude don't pull their own weight in the debugging department, so they don't see the full costs of it.
For me majority of game development is feature development and fixing gameplay related bugs. Which will be same regardless of language you use. And depending on language feature development might be even slower
You can say that again!
> If you get a ctd, usually a callstack and a bit of thought is enough for figuring out what is going on.
Very different experiences. Sometimes that happens.
Sometimes the symbols have been evicted from the symbol server. Sometimes the minidump didn't capture relevant memory (and the full dump would be a couple dozen gigs, making external QA reluctant to constantly capture those). Sometimes the crash is the result of memory corruption from unrelated systems minutes ago that doesn't reproduce when you enable any of your debug allocators because reproing relies on pointer reuse in a hashtable. Frequently custom allocators defeat tools like valgrind and address sanitizer, requiring extra work to either bypass or explicitly annotate valid/invalid memory ranges. Sometimes the process only exit(3)s (technically not even a crash!) from an unrelated thread on a specific bit of UI with no relevant callstacks nor logging, and if you open up the windows charm bar for more than 10 seconds without a debugger attached, and you resort to bisecting p4 history once you've spent the several days even figuring out repo steps.
That wasn't even our bug, but it was our workaround... even when the codebase is good, the middleware often isn't! And that is but one of many I've had to deal with.
> C++ is relatively safe when you have well designed systems where ownership is clear enough.
Meanwhile, the poster I was originally replying was pointing out that you can have unclear object ownership full of globals and C++ is somehow supposedly good at dealing with this. Hopefully you're at least agreeing with me here, in disagreeing with that! :)
A lot of gamedev code isn't very well designed, IME, and "relatively" safe can be suprisingly unsafe as well.
> I have a feeling that if my company suddenly flipped to Rust now, the struggling against borrow checker would be a bigger time sink
The first couple months after I picked up Rust, I had that phase. Now it's quite easy for me - sometimes it requires a deep `.clone()` or two, but in the equivalent C++ codebase you wouldn't have even dreamed of not making the deep copy - because in equivalent C++ code it'd be impossible to do the equivalent fancy zero-copy borrowing nonsense even remotely safely.
Game development at large-scale is a mix of systems programming of the kind that Rust excels at and gameplay logic programming which has loose performance requirements and may be written by people who are not primarily coders. So you see a lot of codebases split between two languages, like a C++ core with Lua bindings or something like that.
If we see Rust adoption here I’m expecting it to be from a kind of skunkworks inside the company replacing specific, carefully-chosen systems with Rust code. At my company, that’s how it’s done, and it’s a very slow process. (I don’t work in the game industry, so all I hear is rumors from people that used to work in the game industry.)
Right now, I'm writing something 3D game related. It needs considerable parallelism. The existing tool in this area is mostly single threaded, it's a mess internally, and everyone who looks at it is scared to try to parallelize it.
So I'm writing in Rust. Safe concurrency is a plus. There are some other wins. You can be bolder about not copying things. When decoding an incoming packet with a lot of structure, I'm creating linked data structures where most of the big byte array stuff is borrowed from a packet buffer that went into the structure creator. No allocations; it's all on stack. There's no risk of someone using an item from one of those structures and keeping a reference to data that's going to go away. Wouldn't dare do that in C++.
I get along with the borrow checker just fine. Once you realize that single ownership is a tree, it makes sense. It's the type inference system that causes headaches. Rust has type inference in both directions. There are places where the result type influences what goes in. When the inference system guesses right, it's great. When it can't solve the problem on its own, trying to figure out what it wants is annoying. Go and C++ only have forward type inference; result types are computed by the compiler.
Rust is really a single assignment language, not a functional one. There's a lot of "let foo =", and not much "let mut foo =". After a while, you get the idea that if you write "let mut", you're doing it wrong. Single assignment has most of the benefits of functional, but without multi-line expressions that go on to infinity. Plus you're not limited to a tree of results; you can have directed acyclic graphs, because you can usually re-use the value from a "let".
The type of error objects is still a mess. Rust needs something like Python's exception type hierarchy and a consistent way to convert special error types into more general ones. I notice there's a Rust working group on error handling, again.
Rust needs a good book. Not "The Rust Programming Language". That's too hard for an introductory book and not detailed enough for a reference manual. A book by someone who didn't develop the language is needed.
The library situation has improved quite a bit since the last time I tried Rust, a few years ago. Back then, finding a library to do HTTP was "No, the one you're using is obsolete, use ...". Now I'm finding usable libraries for obscure things like analyzing files from "tcpdump".
They missed a chance on something important to 3D work. Each library which uses 3D vectors has its own structure for them. There's a proposal for a common format, "mint", but it's not getting traction. This is an old headache in 3D programs with components from different sources. Back when I was developing ragdoll physics, I had four 3D vector types in one C++ program.
Anyhow[1] and thiserror[2] really help here, no?
1. https://github.com/dtolnay/anyhow 2. https://github.com/dtolnay/thiserror
I should be able to complete the sentence, "Rust is the future of game development because...," but I can't in any meaningful way.
Here are the highlights of the article, instead:
Rust is the future of game development because Rust has the performance of C++ with the convenience of C#.
Rust is the future of game development because Rust has ownership based memory.
Rust is the future of game development because Rust is popular. (The article doesn't say this explicitly, but implies it is.)
Rust is the future of game development because Rust is still an immature language. (This doesn't actually sell the point, and I'm not sure why the author bothers talking about this.)
What's weird, too, is that the article talks about how hard networking is, but _cart has specifically said in the past, "Yup! High level and low level networking is definitely on our radar, but it also isn't our immediate priority."
It may come as a surprise, but you basically have to bake networking into the engine. It's not easy as an afterthought. Rust doesn't help with this. In fact, multiplayer and all its challenges have nothing to do with Rust.
We had modern client-side prediction roughly 20 years ago, and people still don't take multiplayer seriously.
I think multiplayer is an area where you'd want "fearless concurrency". Rust could do well here.
A better argument might be Rust and Vulcan, though. Even still, you can get very far with just using OpenGL.
Is that it doesn't benefit, or is it that the benefits are too hard to achieve given the nature of memory issues with games that like to have global state and are written in C++? A lot of games do a bunch of things every frame and then increment state. Those can all be parallelized as they only depend on the previous frame's state.
You can't just take any type of game logic and parallelize it either, since there are types of game logic that aren't just dependent on the previous frame. You may be wholly dependent on something that has just occurred earlier in the frame, but has not been networked to clients yet.
Not to be condecending, but you should try making a game and see how well that parallelization idea of yours turns out.
So, the phrase "a tremendous amount of game code doesn't benefit from multithreading" is actually true since most game code is in unreal/unity, but it's not a hard constraint for all game engines.
The problem is that most naive "game engines" which provide nothing more than bindings to OpenGL/bgfx, OpenAL, Box2D, etc. and are really just "game libraries," don't even provide things like out-of-the-box multiplayer or level loading, so the idea that they're going to make the leap from providing basically nothing to providing mechanisms for multithreaded game logic, which requires some sort of gamerules/gamemode abstraction first is not something I think you'll see in practice.
Most game libraries or game frameworks like these only provide things like load, update, draw callbacks with some nice bindings.
I'm not sure what you mean? Are you saying bevy's architecture isn't fitting?
Not to mention that you evidently don't _have to_ do this, seeing as how in Unity you're basically forced to work with raw sockets.
> Not to mention that you evidently don't _have to_ do this, seeing as how in Unity you're basically forced to work with raw sockets.
I don't know how old you are, but by the time 1999 rolled around, id Software had produced essentially the same multiplayer client-side prediction model that has been in major use to this day. It hasn't fundamentally changed.
The fact that Unity cannot reproduce 20+ year old tech is a joke, not an example. In fact, UNET was such a joke it basically tried to ignore this fundamentally unchangeable architecture and they ended up canning it in the end.[1]
[1]: https://blogs.unity3d.com/2019/06/13/navigating-unitys-multi...
Does anyone care what language were any particular games that keep being replayed or remembered fondly?
No. Never.
I dont know if all this would have been better in Rust or other languages.
(It's also substantially faster, but comparing it to Java edition is sort of unfair because there are a myriad of differences between the two in game mechanics, with many of the differences probably being relevant to performance.)
The C++ one didn't have all the same features as the Java one for a while, but it ran fine on weaker hardware than the Java version needed.
If he had started to second guess the programming language, Minecraft probably wouldn't exist as we know it.
This is something our industry seems bent on doing. To hell with stability at the foundational level. Progress is measured in features. And those have gotten pushed to the foundation.
Rust has one of the best Lang->WASM stories out there. The thing that made Flash games so popular was the "You just load up the page in your browser". I see rust fitting very well into that role in the future.
Further, because WASM is a part of the web standard, I don't see it going away anytime soon. Those WASM games will work for a long time into the future.
> No. Never.
I certainly remember games more that still have an active modding community, which is (somewhat) enabled by the choice of programming language.
I doubt Rimworld or Minecraft would have the thousands of mods they do if modders had to write OCaml instead of Java or C#.
Roller Coaster Tycoon was in assembly.
> Does anyone care what language were any particular games that keep being replayed
That seems to be a non-sequitur to me.
What does what people play have to do with what developers are using to create? That's like asking if users care what language serves the web pages at Facebook. The users don't care, but people that make web sites/applications (the developers) might.
Do you know what brand of guitar/piano/keyboard etc your favorite musicians use? I bet other musicians care about that.
I don't think the writer was talking about the the language somehow directly being related to a gamers experience. He's talking about building complex game engines and the like and the benefits he thinks Rust provides there...
Already, games use tools like Blueprints in Unreal to make games with limited to no coding experience, and I expect those tools will continue to get better and better over time.
That said, I do feel most of the examples are not that. The old shareware scene was much closer to the spirit. Now that we are pushing winners only, feels more like corporate control than it does people control. :(
Even on the major platforms, you'll find stuff like Umurangi Generation, a game about taking photographs in a surreal autocratic environment. That game is not a 'winner only', but it's fascinating and only exists because people who want to make that experience had access to tools they could understand and use.
Democratic processes and tools are tools that are widely available to the public. It's not only AAA studios making games, everyone around the world is making games.
As such, I meant the winners to be the few engines that have remained. Feels like a smaller field, but with only bigger players.
The action of making something accessible to everyone.
‘the democratization of information through technology’
‘Kirk has contributed greatly to the democratisation of electronic music and helped it becoming a genre to reckon with.’
The printing press (and printmaking in general) are both examples of democratic art -- making art accessible to the masses.
In some sense blueprints are necessary because using CPP sucks. I can imagine that instead of Blueprints, Rust based engines will use some DSLs.
It is important to understand the difference between parts of a game that are expected to be performant and parts of a game that are expected to be easily changed or modded.
The rest, triple A titles and engine developers may chose something else, but the inertia of C/C++ will make that a very long process.
Right now in the real world of AAA games it is nowhere, it's not even a consideration so calling it "Rust Is the Future of Game Development" right ...
For those who don't work in games, the tech there move very slowly, it's not your typical SV "let's use the latest fun and cutting edge tech".
Whatever is first class for GUI users on Windows in China and Ukraine is going to impact AAA game development far more than any non-GUI technology.
It's not really about tooling. I'm not saying tools. Just Visual Studio. Visual Studio decides what will appear.
Then you have the build process, vendorizing your packages (so you don't fetch them off internet), etc. Right now .sln files and MSBuild rule there (like it or not).
Why would you say that? I have no reason to believe it. C++ and Rust discussions frequently overlap so it's unlikely anyone who uses C++ hasn't heard of it. Game developers, in particular, are exposed to a larger segment of programming languages simply out of necessity. Searching for solutions or functionality will usually lead to esoteric options and the ever-present gamedev talks about how language X solves a portion of your gamedev woes.
They decided that having a unified tech stack for the games themselves was worth more than Rust's advantages. Basically, they decided to re-build Witchbrook on top of Wargroove's engine.
That being said, I guess I should have put an asterisk on there; they aren't using Rust in game anymore, but they are still (apparently, last we heard) using Rust for server-side components. Wargroove's servers are implemented in Rust.
Show them Rust, and they will say "what can it do that my tooling doesn't?", and then you must be silent.
Meanwhile, game developers, as a rule, are interested in (surprise!) game development, not languages. What Rust brings to the table, few game developers are looking for. But Rust builds are notoriously glacial, where game developers are wedded to the edit-build-test cycle.
So, gaming will be one of the last places for Rust to thrive. That doesn't mean no games will be in Rust. Rust coders will compete for jobs using it, rather than game shops competing for Rust coders.
For example: spending an extra hour or three each day, waiting for the compiler, might not seem like progress to everybody. Their assessment is as valid as yours.
Furthermore: you assume that people who hire must also agree with you. But, some people who hire want coders coding more and waiting for builds less. That is a legitimate desire.
The fact remains, and will remain, that C++ can encapsulate in libraries semantics that Rust cannot, and according to the Rust core language developers will not. As a direct consequence, it is possible to program at a higher level in C++ than in Rust. This gap will get larger as more libraries are written that exercise the difference, and as C++ adopts new features that expand the difference.
Within the HN echo chamber, the apparent situation is muddier because technical merits carry little weight vs. trendiness and surface sheen.
How likely game programmers are to use the greater capabilities is neither here nor there; they probably see more effect from the extremely slow compiler.
Which feature are you talking about here?
* Operator overloading: Rust already does this
* Exceptions: this is true, Rust will not do this.
* Partial specialization: is in nightly, will be made stable
* Template function overloading: not in Rust, nobody has said "never" though it is controversial
* overridden move constructors: this is true, it won't happen
* concepts: traits are already concepts and exist today.
The situation is significantly different than you've presented. We do have several features that we need to catch up to C++ in areas, but the big ones are on the way. It's more minor or stylistic, rather than capabilities, that are maybe not gonna be a thing.
> Can I replace my Rails/Django/Flask already?
> Yup! Rust has mature and production ready frameworks in Actix Web and Rocket, and newer ones like Warp and Tide. These provide everything you’d expect from a web framework, from routing and middleware, to templating, and JSON/form handling. There are crates for everything, and more!
I would pay for a reality show where a big Rails application needs to be replaced by Rust by the same engineers who built it.
How would Rust prevent "rushing crude hacks out the door at the last minute"?
Because game developers would be fighting the borrow checker instead of shipping leaky code that compiles without hurdle?
Q: What does a game company call a teetering tower of ugly hacks on top of ugly hacks?
A: Shipped!
Source: 5 years in the games business. The game development process can get messy. My studio doesn't crunch, but elsewhere crunch is the norm, and does anyone think the code is gonna stay beautiful during endless crunch? The old-timers here all have their war stories they tell of last minute ugly hacks tossed in just to get a game out the door on time.
A lot of what makes games fun are the exceptions to the rules. An extra game mechanic in a special circumstance that allows you to do something that the basic rules don't. Or just a mechanic that stops something un-fun from happening (getting stuck, or it being too easy to trick an enemy).
But clean code always follows the rules, and makes it harder to introduce special cases.
I'm not saying software engineering has no place in a game, nor that rust would be bad it it. Just that it's less clear how software engineering will help a game, or if the game will be nudged toward a different style by the language somehow.
Convenience is a relative term. Convenience to what ? Personally, I find that far from the truth. Rust is very powerful, offers lots of flexibility in memory managing and allocation, which makes a difference in gamedev, but overall it's far slower to code in, because of that. And that is very bad for gamedev, in which fast iteration times is crucial. You code something, test it. Scratch it. Fix it. Test it. And so on.
Performance is pretty good and even though Rust seems like a rising star, it won't reach C# levels of tooling for quite some time.
I don't think the population of studios that chose C#'s performance and convenience over C++ but would now choose Rust is all that large.
But hey, lets start talking about bindings. We could be changing all these C#/C++ engines into C#/Rust engines.
Just curious; what's the tooling gap between Rust and C#, according to you?
I work in C# profesionally, and dabble in Rust, and haven't really found Rust tooling lacking yet -- but maybe that's because I'm only working on small hobby projects.
Also, what about debugging? C# does edit & continue and allows arbitrary statement execution during debugging. Does Rust debugger even allow moving the instruction pointer at will?
The GHC RTS is akin to the Lua layer and handles all the high-level logic. For storage and compute-intensive things, we can drop to lower-level primitives for performance and then easily hook into them in our scripting layer. I wouldn't be surprised if fleshing out this domain hints at future useful GHC extensions as well.
I like Rust a lot, but I honestly think the ability to do highly-abstract programming is worth having to deal with a non-literal compilation pipeline. For gamedev at least.
I honestly think it will be astounding what scale of game a single developer will be able to build in Haskell in 3-5 years once all the pioneering is out of the way. Programming a game the size Blasphemous could easily be managed by a single Haskeller I'm pretty sure - leaving resources to focus on art, sound, and storytelling. And that's an easy call - it'll be fun to see just how big and complicated of game logic we can make cheap thanks to good abstractions.
Another related issue is the level of abstraction is so high that it makes it harder to be extremely optimal with memory usage and access, which is something game developers love doing, even sometimes when they don't strictly have to.
I love programming in Haskell, but I'm highly suspect that it will ever be a widely used game programming language. It's very good at expressing computations in the abstract at the expense of being good at telling a physical computer exactly what to do. Game programmers tend to prefer languages that fall in the latter category in my experience.
But I think it'll allow me to be insanely efficient as a gamedev. So I'm a Haskeller-turned-gamedev. Not a gamedev-turned-Haskeller.
Haskell performance and memory usage is kind of like JVM programming. You need a mental model of how GHC and its RTS & GC operate. Having frame-oriented code honestly makes it easier to reason about. We Do need more learning materials about this stuff, but first we need more experience!
But idt it's any different than using GC for gamedev. And manual memory management is well within Haskell's capabilities.
Haskell profiling IME makes space leaks very obvious. That's a too-common paper cut, but once you get cut once you don't make the mistake again :)
The only thing I could realistically see happening anytime soon would be people using it as a scripting language for Godot, but I'm not convinced that working with the Godot abstractions won't rob you off most of the gains you make by using Haskell.
Laziness really isn't an issue. Especially when writing FFI/low-level Haskell. I suspect the heavy-lifting will be written in a more performance-conscious style. And a lot of it will be deferring to industry-standard C libraries. And then you're right, idiomatic Haskell would have its place in the scripting layer.
I honestly don't think there's anything inherent to Haskell that stops it from being used to make high-quality commercial video games. So my plan is to try to build those in Haskell and let the libraries and infrastructure fall out (as it always nicely does using Haskell in my experience.) Honestly, developing high-quality games is more bound by art & creativity than Haskell.
It's something that can compete with C/C++, but has a community as good as Ruby. No other programming language has both.
With the diaspora of Rust engineers from Mozilla, I'd guess things only to improve even further.
I really liked the community chat of Rust. For all beginner questions there is someone standing by to answer it in under 10 minutes. Sure, Rust is hard but having people explain everything to you in a chat when you're stuck is worth gold.
Whenever I see people programming in rust they are usually having to work around the borrow checker, which arguably makes them reason in a better way about their programs and also arguably wastes loads of their time doing something they know is correct but the rust compiler can't reason about.
I don't think rust has "fixed" reliability or performance issues in Firefox has it?
You really want to have some easy to find average coders that can pretty much script your game on top of an engine and framework, and you don't want to spend way too much on them. It could be a different story for some multiplayer AAA games since they have enough lifetime to become mature and start to take every optimization opportunity.
Not meant as a criticism of Rust, but you will unseat COBOL from the finance sector LONG before you get the gaming houses onto rust.
Not impossible, highly improbable though
Rust is not even on the table even in the future.
This is, by far, the most credible argument in the piece. Access and tooling for new platforms is a critical factor for games.
Rust is a cool language, but it's a cool tool, nothing more. I'd rather see the ownership process implemented in some C/C++ dialect. I'm not entirely sure, but I think that C++ concepts, in a way, have the same goals than ownership.
Safety doesn't always matter. It matters for a company like Mozilla and anything that's network/system related, that's for sure, but for games, I'm not so sure.
Also, statically typed languages that compiles to machine code are a niche now, new languages in that area don't really matter. You either have kernel code, or interpreted languages. A big quantity of C/C++ userspace code is fossilized code. Computers are quite fast for a lot of interpreted languages.
Moreover, C++ is actually one of the most difficult languages to use.
That is your opinion, and one shown time and time again is not true.
Here you go,
https://llvm.org/devmtg/2019-04/slides/TechTalk-Horvath-Impl...
https://devblogs.microsoft.com/cppblog/lifetime-profile-upda...
I heard all of the hype, and I completely fell for it. This is not a language for game developers (35 years experience in game development here).
Oh, how about some simple data structures you need. Like developing dynamic graphs with pointers needed to and fro. What a serious PIA.
#include <string_view>
#include <string>
#include <iostream>
int main()
{
std::string_view v = std::string("xyz");
std::cout << v << '\n';
}Edit: NVM, for those wondering the std::string constructor copies the string when it doesnt have to. But the solution here is to just initialize the string_view with the char data instead of the std::string instance
Edit: Ignore me see below
You have a temporary std::string, pointed to by a string_view, which means that it's freed, and the view is dangling, and then used when printing things out.
Just because the memory has been deallocated doesn't mean that the bytes there were changed. The pointer may still point to them, and it may still "work."
Edit: If I move the first line into a function and return that string_view, then with optimizations it still prints nothing, but without optimizations it prints random varying garbage each time I run it, different each time.
A lot of C++'s (and C's) memory "fun" doesn't readily appear when you're inside a particular function because the memory (like here) is on the stack. So your behavior within that function scope looks like what you want. Then you start returning values and, oops, something was a reference to memory on the stack. In which case it more or may not work depending on what else has happened between the value being placed on the stack and its use (I had to run a fun crash course for EEs on stack vs heap, when your only programming experience is a bit of Matlab this is not a topic you'll be familiar with).
I remember people prophesizing the end of C++ because of the introduction of string_views. When writing a text editor over a couple of weeks (a lot of text manipulation) I used string_views extensively and purposely over-used them (returned them a lot or kept them for a long time), because I wanted to see how dangerous they could be and I never got a bug/crash that was related to them. Of course you have to think about what you are doing, but you should be doing that anyway. What I am trying to say is that while it's never "free" to not write bad code, if you get used to it, you don't have to think as hard about it, as you might think.
There are way more common examples of easy ways to break your code, like storing references/pointers to elements in vectors, which then resize or capturing objects in lambdas that get destroyed before the lambda is executed and stuff like that. Even out-of-bounds access to arrays/vectors is a lot more common than that, I think personally.
People freak out because it _doesn't_ crash your program (until it's running in production of course). On my system without optimizations it prints "xyz" just fine, with optimizations it prints nothing, even though I'm accessing to the middle of memory. I think on most systems this will not actually crash unless you have explicit out of bounds memory tracking inserted into code by the compiler every access slowing down your code.
The point is in Rust this wouldn't even compile.
I'd be curious if you ran your text editor through a memory sanitizer like valgrind and how many issues it points out.
How many gaming consoles support rust?
Now, many studios would want it to be directly supported by the console developers themselves, and that's obviously not a thing right now... but there's no technical limitations here.
Is this not just ARC?
Now, it is true that languages that use ARC can do compile-time analysis to remove some refcount traffic, and that you can use run-time ownership tracking in Rust if you'd like.
The difference is what's built into the languages, what is the default vs what is not, and the kinds of patterns those tend to enable.
And remember that Rust must go through an LLVM layer.
Instead, what about Nim? Any hopes for this language to become a mainstream games programming language instead? Since it does transpile down to C code.
By all accounts Java has the most sophisticated runtime out there, it has all the safety features of Rust without fucking around with the borrow checker which seems like a huge piece of complexity just to avoid garbage collection.
Plus, now that Mozilla has gutted the Rust team, one wonders what future Rust has, if any.
Does it, though? I've played titles written in Java and achieved smooth 60 fps back in 2008.
Second, to my knowledge it's still very cumbersome to avoid GC allocations in Java. By comparison, it's easy to reduce calls to global heap allocators in C.
Second, it is relatively easy to do native memory allocation in Java, but apparently people keep forgetting to learn their toolbox properly.
Third, calling malloc() is such an issue that there used to be companies specialised in selling optimised versions of malloc()/free().
To be fair, every application is going to differ, and perhaps games need tighter control of memory than a high performance GC is capable of, but automatic GC does make programming a lot easier.
Hex-Rays and similar are also a thing for native compiled code.
> Even so, manual memory manipulation is easy to get wrong,
Even predating C++11, you should not have been doing manual memory management. I don’t think Mozilla was following best practices. IIRC, there were pointers everywhere. Even before C++11 best practices for C++ were to try for value semantics as much as possible. Mozilla code base was more like C with Classes than best practice C++.
Anyway, you are unlikely to avoid pointers completely in a good C++ codebase. Value semantics are very often the wrong semantics for the code you are trying to write. You can end up with dangling references as easily as you can end up with dangling pointers. If you use std::shared_ptr everywhere, then what you have is a slow & inefficient GC.
"Best practices" is such a red herring. Best practices = don't write bugs, too; yet there are bugs. You can't evaluate a language in theory and ignore what happens in practice any more than you can with any other thing in life. It's the UX, does it do what users expect it to do, and is that the lowest friction path possible to achieve the goal. "You're not following best practices" is basically "you're holding it wrong". While arguably true, it is an attempt to excuse a bad design decision or impedance mismatch.
So let me simplify - if to use a language correctly requires knowing the full history of the language, along with explicitly eschewing some of the key features of the language (except in certain cases when you need them! And they're not deprecated or issue warnings or similar by the compiler), and even extremely experienced developers using the language still make mistakes...the issue is with the language.
Either some of the biggest software companies (Mozilla, Microsoft, Google) are all incompetent or there is a problem with C++ in the real world which still hasn't changed despite "you only need to follow best practices in C++".