Always test with sanitizers, asserts and enable all the warnings 😎 (I just can't understand why the compiler didn't throws an hard error if you forget to return a value...)
It really depends on the specific compiler and flags. Most modern compilers will add a return instruction even if you don't include it in the source code so that you can exit from the function. 'int main()' is a perfect example of the compiler automatically adding a return instruction on your behalf. But if you don't specify any return value, what does it return? Let's start by saying that there are multiple function calling conventions. The calling convention I use in the compilers I write (I don't remember if the C standard does it the same way, but it gotta be similar anyway) works as following: - make space on the stack for the return value by pushing the stack pointer by the static size of the return value type (the type of the return value must have a statically known size, otherwise you can return a pointer to a heap-allocated value. Pointers always have a static size). (This step is usually optimized by passing the return value through registers if the size is small enough to fit into a register). - push onto the stack the arguments to the function being called (usually this step is optimized by passing most arguments through registers). - push the current program counter onto the stack (so that the CPU can later jump to the instruction next to the function call when returning. - jump to the address of the function being called and execute its instructions On most architectures, the return instruction (sometimes called 'ret') just pops the topmost element off the stack, interprets it as the return address and jumps to it, effectively returning from where the function was called. Remember that the return value is either located on the stack or in a register, so it exists even if you don't specify any with a return statement in your source code. However, the return value is not automatically initialized and it's your responsibility as the programmer to do so correctly. C and C++, unlike safe Rust, do allow uninitialized values. Because of this, a function of the type 'int foo()' does not need to initialize the return value of type 'int'. That said, I think any compiler should complain about a function returning an unspecified value, except maybe for the 'int main()' function.
Also I swear I have seen compilers WARN you about forgetting to return from a non-void function. And also about forgetting to initialize a variable. The latter probably requires an increased warning level. Moral of the story: Always use the biggest warning level you can and always tell the compiler to treat warnings as errors.
@@lowlevelgamedev9330 I suspect that you get a lot of dumb warnings that's why you have been conditioned to ignore them. Try explicitly turning off the the dumb ones. I suspect those are very few, but produce a lot of noise. Also search StackOverflow on how to disable warnings on MSVC coming from external includes.
Some useful advice, since the order of static initialization of globals isn't defined, put them all in one source file and declare them extern in a header that every other module includes. If all of your globals are in one place and defined top-down, then you'll be fine. Just remember to minimize your usage of globals. Also, avoid codependent structs and classes. That's a sure way of getting weird bugs and compilation fails that you won't necessarily understand. I can't remember the last time I had a buffer overflow issue because for static arrays I have a macro I defined years ago that is in my "standard" header which simply does sizeof( array ) / sizeof( *array ) and I use a custom array type for dynamic arrays which includes a length member.
"Never assume you know what the problem is" I dont know why, but I feel that. I've been surprised so often at what the actual error happened to be. I rarely say im 100% sure about something related to c++ 😅
very fun bug i once got with stack coreption a example: void SetTo10(int& Value) { Value = 10; } char A; SetTo10((int&)A); then i learned don't cast values if funcion is expecting a refrence
As someone who programs Java for work and then uses C++ in my spare time, I do like how many more things the Java compiler outright forbids that C++ only lightly warns you about
Best to avoid static initialization entirely. It seems simple, but it can definitely cause you headaches down the line. Watchpoints are also worth mentioning. I.e. expressions the debugger watches for changes. Try to make them hardware watchpoints so they're fast.
It has happened to me when doing CP. My code sometimes gave correct answers but sometimes it did not. I was like "What in the quantum is this?", the bug was indeed undefined behavior. I forgot to return the value from the function XD.
2:34 which is part of the reason that it is bad practice to use a c style array. if you were following beat practices you would've been useing std::array[or std::vector]::at which throws if you try to access a out of bounds value
@@redpepper74 I think it throws [If you have exceptions enabled of course]. I said at instead because it is granted to be a constant member function. Where as there are cases where the index overload isn't.
Macros are not evil, like anything called "evil" in programming it is because some people don't know how to use them correctly and cause far worse errors in the process.
@@rubynaxela8524 I think I've seen it used like a super-break in nested loops. Sometimes, its much neater than setting a flag, break, then checking that flag outside the inner loop
An advice for dealing with undefined behavior or errors coming from different file/source code that is not part of the project. You can use the call stack to trace where the code was called from and go back until you find code that is part of your project. At least for me this helped me a lot when I got a random error from stbi_image and didn’t know what caused it.
to me, it was simpler to just switch to C entirely. yes, you may have to write more code sometimes, but at least you can truly master it. and also, no worries about implicit stuff that C++ does all the time.
One of the worst errors I've dealt with is when I opened a very large and old project that I had completely forgotten its existence. I try to compile and I get very ambiguous errors in the xmemory file. Boy that took a few days to debug,
In one of previous videos, you told us, that you allocate memory as less as possible. In game, you have game loop where you update and draw all your objects, and I sure that you couple them in one vector or list using some common interface, so I have a question, how are you using vector of Interface based objects without memory allocation in cpp, or if you are not, what other technics you are using to get this result
the signature of std::vector is template class vector; this templated argument Allocator manages how memory is allocated for the vector, you can for example write your own allocator so that it manages a pool so that instead of calling new, malloc or something else to get more memory from system, you call it once but large enough to store everything and you manage it yourself, i.e. construct or destruct other objects, this provides a speedup because you don't have to ask system for memory every time or you can free everything when you exit (which you can also do with the default allocator); this is just one way and is in my opinion the cleanest because it can be made generic
yo so, you can't get away with not allocating memory ever. But the idea is to allocate only when needed. So for growing arrays, I use vectors because they are conviniend and they clear the memory when I exit the scope. To answer your question, you can watch that long one hour video about my minecraf clone, but basically I have ome vector for each entity type and I have some tricks to iterate through all of them. The idea is that if no entities are created, there is no memory allocated so the game moves fast.
so you can use the polimorfic allocator verison, for the normal vector you can indeed pass an allocator but the api for that is very wierd and has a very wierd limitation, so it is like it doesn'f even exist unofortunatelly :((( What I would do is I would add a temporary arena if needed. Like one that clears every frame
What I do in the game I'm writing from scratch: I allocate a chunk of virtual memory and then use that. The OS and hardware then map that memory as it's needed into physical memory. This means I could even request unreasonably huge amounts of memory for a game that just get more entities the longer you paly that can't get unloaded (automation/factory builders). This means manually taking care of that memory and using/reusing it while the game runs, but it also means the only real point of failure in regards to allocations is in the beginning. There might be slow downs related to the memory mapping I am not privy to yet. And it'd be an interesting thing to see if it's worse than memory allocations or not, but that's for future me to discover.
You have to watch a bit further, where you then can see the getData function. int data = 10; is set inside the function getData(), but int data outside the function is using the return value of getData(), and that is undefined.
@@AntonioNoack I replied here before your comment but the reply is gone😕. I'm too lazy to rewrite it but in short, it's not just because the variable was created inside the function but also because he returned a reference to it, not the value itself. And since value was created on the stack, it got erased before return was called.
Macros are not evil but they are easily abused and can be obtuse on how to use them. I will only use them as a last resort in some cases and maybe to cut down on repetitive stuff. Otherwise, I try to avoid them when possible because I hate the pain of leaked macros.
macros can definitely be useful. i'm working on a project, where i have to access a specific value a lot, but "this->memory[this->registers[registerIndexes::ri_ISPT]]" is a mouthful so i just used a macro to reduce it to smth smaller, then undefined it at the end of the file
In such cases I like to define a separate function for accessing the value. Compiler will inline calls to one-line functions 99.9% of the time in release mode (-O). Or even defining a lambda locally in the function where said value is accessed often.
It might be also good to define lambadas for accessing in single file or even method. If you’re using multiple object which share methods but don’t share interfaces the concept might be helpful. Even if the codebase gets a little bit bigger, you’re guaranteed to have Much cleaner error messages, than in macros, that are just copy and paste. At least imo
@@lowlevelgamedev9330 After you comment I did some digging on StackOverflow. It is legal C++ to point to one element past the end. Dereferencing it is undefined behavior. This can be used as a marker for the end. Think of it in the context of STL containers. All the end() iterators of stl containers are defined as "pointing to one element past the end". Hence "return array+arraysize;" is a valid implementation for and end() method.
@@lowlevelgamedev9330 The last bit I forgot. By allowing one-past-end element to be valid, that probably means that the next item on the stack (aka the next declared int variable) would be 2 elements past the end. So your buff[33] works on corrupting the other variable.
i like your videos, but find it so hard to follow as a non native english speaker aswell. if you would talk a little slower i think it would be much easier to follow. The content is so good so i find it frustrating i cant understand sometimes
sometimes warnings are good, other times the compiler doesn't like your code and you get 20+ warnings, and it is unfixable (nothing i tried to to fix them worked and nothing i tried to make the code unstable worked) that's my experience with warnings lol
what? no, also like half of the games on steam use custom engines, tho don't take my word for it, I am just speaking out of memory, there are statistics online, you can use whatever you want they don't care
so when he throws arrows and the particles come out after arrows hit are constructors? and does he use destructors after it so that gets removed? am i right to understand that?
basically the colors are static variables. They are constructed once when the program starts, and they have that value for the whole program. I just use the color values. But they are wrong because they were initialized wrong when the program started
@marcsfeh This not about the specific execution model of a CPU. While a computation platform is generally deterministic, the exact state of a system is usually not reoccurring. Most undefined behavior comes from access to where it shouldn't be/it was not expected, or race conditions. Race conditions depend on many factors in the OS, that are different every time. Rust eliminates undefined behavior mainly through the borrow checker, which ensures every possible access to data is known and can be handled. It also provides many well engineered constructs to deal with uncertain situations at runtime. All this stems from Rust's strict policy against undefined behavior. Memory safety is one part of this. Usually, Memory safety can be advertised better.
yo, its not really for me and I don't think it fits gamedev. I preffer to be more flexible while writing code, and the safety that rust gives I can get from the way I structure my code. So it isn't really for me. I don't even use const in my code for context lol 😂😂
Avoid all these problems by moving to Rust. 🤷 EDIT: since my answer to the guy below wasn't published, I have to assume that the author of this channel doesn't like when facts are not in his favor. Hence I will state here that: 1. there is an operating system written in Rust and is called Redox OS. 2. That Rust is used in the Linux kernel itself. 3. Rust is used in gamedev and there are game engines built with Rust, for example the Bevy game engine. 4. After programming for 20+ years (15+ in C++, 7+ in JS/TS) I can safely state that, for C++ developers, there are absolutely no excuses why NOT move to Rust.
@@averdadeeumaso4003 safe != high-level. Just because someone uses e.g. winit/glutin instead of glfw, or even glium instead of raw opengl calls, that doesn't mean the person isn't a low-level game developer. The safe API wrappers are a pretty thin layer in the overall game engine architecture.
@@averdadeeumaso4003 I don't exactly get what you mean, but those low level apis can be used from rust and also alot of windows componets are being rewrite in rust. rust is also now part of the linux kernel.
Always test with sanitizers, asserts and enable all the warnings 😎
(I just can't understand why the compiler didn't throws an hard error if you forget to return a value...)
it actually has, but sometimes it can't figure that out corectly.
It really depends on the specific compiler and flags. Most modern compilers will add a return instruction even if you don't include it in the source code so that you can exit from the function. 'int main()' is a perfect example of the compiler automatically adding a return instruction on your behalf.
But if you don't specify any return value, what does it return?
Let's start by saying that there are multiple function calling conventions. The calling convention I use in the compilers I write (I don't remember if the C standard does it the same way, but it gotta be similar anyway) works as following:
- make space on the stack for the return value by pushing the stack pointer by the static size of the return value type (the type of the return value must have a statically known size, otherwise you can return a pointer to a heap-allocated value. Pointers always have a static size). (This step is usually optimized by passing the return value through registers if the size is small enough to fit into a register).
- push onto the stack the arguments to the function being called (usually this step is optimized by passing most arguments through registers).
- push the current program counter onto the stack (so that the CPU can later jump to the instruction next to the function call when returning.
- jump to the address of the function being called and execute its instructions
On most architectures, the return instruction (sometimes called 'ret') just pops the topmost element off the stack, interprets it as the return address and jumps to it, effectively returning from where the function was called.
Remember that the return value is either located on the stack or in a register, so it exists even if you don't specify any with a return statement in your source code. However, the return value is not automatically initialized and it's your responsibility as the programmer to do so correctly. C and C++, unlike safe Rust, do allow uninitialized values. Because of this, a function of the type 'int foo()' does not need to initialize the return value of type 'int'.
That said, I think any compiler should complain about a function returning an unspecified value, except maybe for the 'int main()' function.
@@nicholas_obert "But if you don't specify any return value, what does it return?" A compiler-Error.
that's why I enable 20+ warnings on top of -Wall and -Wextra in GCC
This is the right solution to many of the issues
I like headbanging though
He isn’t talking about metal
@@mr.hashundredsofprivatepla3711 Ngl, C++ is pretty metal.
I do too but not while debugging
Also I swear I have seen compilers WARN you about forgetting to return from a non-void function. And also about forgetting to initialize a variable. The latter probably requires an increased warning level. Moral of the story: Always use the biggest warning level you can and always tell the compiler to treat warnings as errors.
well in msvc those things will be reported as errors not warnings fortunatelly, I actually ignore warnings 😂
@@lowlevelgamedev9330 I suspect that you get a lot of dumb warnings that's why you have been conditioned to ignore them. Try explicitly turning off the the dumb ones. I suspect those are very few, but produce a lot of noise. Also search StackOverflow on how to disable warnings on MSVC coming from external includes.
I can never bring myself to ignore warnings. -Werror every time!
Some useful advice, since the order of static initialization of globals isn't defined, put them all in one source file and declare them extern in a header that every other module includes. If all of your globals are in one place and defined top-down, then you'll be fine. Just remember to minimize your usage of globals. Also, avoid codependent structs and classes. That's a sure way of getting weird bugs and compilation fails that you won't necessarily understand. I can't remember the last time I had a buffer overflow issue because for static arrays I have a macro I defined years ago that is in my "standard" header which simply does sizeof( array ) / sizeof( *array ) and I use a custom array type for dynamic arrays which includes a length member.
I love the Minecraft music in the background. Nice video!
thanks 💪
Wait y’all know about -Wall -Werror -Wextra -Shadow compilation flags right? Right??
Don't forget our good buddy -pedantic
Mmmh, you should have mentioned tools like Valgrind, which are runtime sanitizers.
Always use fsanitize address and fsanitize undefined behavior flags, Wpedantic also helps
"Never assume you know what the problem is"
I dont know why, but I feel that. I've been surprised so often at what the actual error happened to be.
I rarely say im 100% sure about something related to c++ 😅
very fun bug i once got with stack coreption
a example:
void SetTo10(int& Value) { Value = 10; }
char A;
SetTo10((int&)A);
then i learned don't cast values if funcion is expecting a refrence
As someone who programs Java for work and then uses C++ in my spare time, I do like how many more things the Java compiler outright forbids that C++ only lightly warns you about
Forgetting to declare a destructor as virtual is one of my (least) favourite
clang-tidy to the rescue!
Best to avoid static initialization entirely. It seems simple, but it can definitely cause you headaches down the line.
Watchpoints are also worth mentioning. I.e. expressions the debugger watches for changes. Try to make them hardware watchpoints so they're fast.
how can you forget to return a value to the function that asks for a return value? I believe the compiler will complain.
It has happened to me when doing CP. My code sometimes gave correct answers but sometimes it did not. I was like "What in the quantum is this?", the bug was indeed undefined behavior. I forgot to return the value from the function XD.
2:34 which is part of the reason that it is bad practice to use a c style array.
if you were following beat practices you would've been useing std::array[or std::vector]::at which throws if you try to access a out of bounds value
Wait does indexing a std::array still let you read out of bounds?
@@redpepper74 I think it throws [If you have exceptions enabled of course]. I said at instead because it is granted to be a constant member function. Where as there are cases where the index overload isn't.
Macros are not evil, like anything called "evil" in programming it is because some people don't know how to use them correctly and cause far worse errors in the process.
They're evil. Sure they have some obscure use cases though.
goto
@@rubynaxela8524 I think I've seen it used like a super-break in nested loops. Sometimes, its much neater than setting a flag, break, then checking that flag outside the inner loop
The X-macro technique is very useful.
An advice for dealing with undefined behavior or errors coming from different file/source code that is not part of the project. You can use the call stack to trace where the code was called from and go back until you find code that is part of your project. At least for me this helped me a lot when I got a random error from stbi_image and didn’t know what caused it.
Remember that a++ + a++ is undefined behavior
to me, it was simpler to just switch to C entirely. yes, you may have to write more code sometimes, but at least you can truly master it. and also, no worries about implicit stuff that C++ does all the time.
Don't use raw pointers and manage resources with RAII.
Here's a strange thing I noticed: For ints a and b, the expression a + b + b ist not necessarily equivalent to a + 2 * b.
One of the worst errors I've dealt with is when I opened a very large and old project that I had completely forgotten its existence. I try to compile and I get very ambiguous errors in the xmemory file. Boy that took a few days to debug,
there's also -fsanitize=undefined for UB
Why couldn't you use constexpr in your case ?
long story, glm didn't let me for some reason, no idea why honestly, it gave me compiler errors
@@lowlevelgamedev9330 yeah right, it probably doesn't have constexpr constructors.
In one of previous videos, you told us, that you allocate memory as less as possible.
In game, you have game loop where you update and draw all your objects, and I sure that you couple them in one vector or list using some common interface, so I have a question, how are you using vector of Interface based objects without memory allocation in cpp, or if you are not, what other technics you are using to get this result
the signature of std::vector is
template
class vector;
this templated argument Allocator manages how memory is allocated for the vector, you can for example write your own allocator so that it manages a pool so that instead of calling new, malloc or something else to get more memory from system, you call it once but large enough to store everything and you manage it yourself, i.e. construct or destruct other objects, this provides a speedup because you don't have to ask system for memory every time or you can free everything when you exit (which you can also do with the default allocator); this is just one way and is in my opinion the cleanest because it can be made generic
yo so, you can't get away with not allocating memory ever. But the idea is to allocate only when needed. So for growing arrays, I use vectors because they are conviniend and they clear the memory when I exit the scope. To answer your question, you can watch that long one hour video about my minecraf clone, but basically I have ome vector for each entity type and I have some tricks to iterate through all of them. The idea is that if no entities are created, there is no memory allocated so the game moves fast.
so you can use the polimorfic allocator verison, for the normal vector you can indeed pass an allocator but the api for that is very wierd and has a very wierd limitation, so it is like it doesn'f even exist unofortunatelly :(((
What I would do is I would add a temporary arena if needed. Like one that clears every frame
What I do in the game I'm writing from scratch:
I allocate a chunk of virtual memory and then use that. The OS and hardware then map that memory as it's needed into physical memory. This means I could even request unreasonably huge amounts of memory for a game that just get more entities the longer you paly that can't get unloaded (automation/factory builders).
This means manually taking care of that memory and using/reusing it while the game runs, but it also means the only real point of failure in regards to allocations is in the beginning.
There might be slow downs related to the memory mapping I am not privy to yet. And it'd be an interesting thing to see if it's worse than memory allocations or not, but that's for future me to discover.
How do you orginize your games? I mean how are you orginizing your objects, scenes, dialog and more?
1:12 how is that done
getData() returns a reference to a local variable. It's an undefined behaviour. Usually you would get segmentation fault here.
You have to watch a bit further, where you then can see the getData function.
int data = 10; is set inside the function getData(), but int data outside the function is using the return value of getData(), and that is undefined.
@@AntonioNoack I replied here before your comment but the reply is gone😕.
I'm too lazy to rewrite it but in short, it's not just because the variable was created inside the function but also because he returned a reference to it, not the value itself. And since value was created on the stack, it got erased before return was called.
#1 using cpp
Macros are not evil but they are easily abused and can be obtuse on how to use them.
I will only use them as a last resort in some cases and maybe to cut down on repetitive stuff. Otherwise, I try to avoid them when possible because I hate the pain of leaked macros.
macros can definitely be useful. i'm working on a project, where i have to access a specific value a lot, but "this->memory[this->registers[registerIndexes::ri_ISPT]]" is a mouthful so i just used a macro to reduce it to smth smaller, then undefined it at the end of the file
In such cases I like to define a separate function for accessing the value. Compiler will inline calls to one-line functions 99.9% of the time in release mode (-O). Or even defining a lambda locally in the function where said value is accessed often.
@@felps3213 yeah but i think macros are just simpler in this usecase tbh
Be aware of simple macro names, you don't want to accidentally undefine someone else's library macro.
@@elijahshadbolt7334 dw i always check if a macro name is in use before i do smth like that TwT
It might be also good to define lambadas for accessing in single file or even method. If you’re using multiple object which share methods but don’t share interfaces the concept might be helpful.
Even if the codebase gets a little bit bigger, you’re guaranteed to have Much cleaner error messages, than in macros, that are just copy and paste.
At least imo
0:58 none of these examples even compile, lol.
You probably meant "buff[32]" instead of "buff[33]". Using 33 means it is 2 elements past the end. The valid range of your array is 0-31.
actually I meant 2 elements, it seems like the last element was uses as a guard or something in debug to check for this kind of overflows
@@lowlevelgamedev9330 oh, ok.
@@lowlevelgamedev9330 After you comment I did some digging on StackOverflow. It is legal C++ to point to one element past the end. Dereferencing it is undefined behavior. This can be used as a marker for the end. Think of it in the context of STL containers. All the end() iterators of stl containers are defined as "pointing to one element past the end". Hence "return array+arraysize;" is a valid implementation for and end() method.
@@lowlevelgamedev9330 The last bit I forgot. By allowing one-past-end element to be valid, that probably means that the next item on the stack (aka the next declared int variable) would be 2 elements past the end. So your buff[33] works on corrupting the other variable.
the new keyword is pure evil
tell me you've never coded without telling me you've never coded
i like your videos, but find it so hard to follow as a non native english speaker aswell. if you would talk a little slower i think it would be much easier to follow. The content is so good so i find it frustrating i cant understand sometimes
Subtitles might help
sometimes warnings are good, other times the compiler doesn't like your code and you get 20+ warnings, and it is unfixable (nothing i tried to to fix them worked and nothing i tried to make the code unstable worked)
that's my experience with warnings lol
yes lol, that's why I ignore them 😂😂
Paste your problematic code here 😁
@@balijosu 600 lines of code, that's way to many bruv
i would need to make a pastebin and search for the code because it is months old
@@atackhelikopter4303 I'm ready when you are 🙂
How do you have your c++ game published on steam? I thought they only allow unity or unreal unless you contact them i guess
what? no, also like half of the games on steam use custom engines, tho don't take my word for it, I am just speaking out of memory, there are statistics online, you can use whatever you want they don't care
so when he throws arrows and the particles come out after arrows hit are constructors? and does he use destructors after it so that gets removed? am i right to understand that?
basically the colors are static variables. They are constructed once when the program starts, and they have that value for the whole program. I just use the color values. But they are wrong because they were initialized wrong when the program started
@@lowlevelgamedev9330 Oooooohhhhh.... ok ok got it. I had to read it 5 times to get it LMAO
Bro writes c99 and presents it as c++ problems bruh
Yeah I was confused on this as well.
camaka
cameka
first
lets goo 😂😂
Nr 1) C++
Reminder to keep knives and ropes away while using *C++*
I love c++ I really do but most libraries make me wanna die
well most cpp devs use their own libraries for this reason, so maybe give it a try to make your own library, you will like it 💪
@@lowlevelgamedev9330 nah the libraries I use are server libraries and I would rather die than make one of those all by myself
When you realize that Rust's main feature is to prevent undefined behavior... 🦀
@marcsfeh This not about the specific execution model of a CPU. While a computation platform is generally deterministic, the exact state of a system is usually not reoccurring. Most undefined behavior comes from access to where it shouldn't be/it was not expected, or race conditions. Race conditions depend on many factors in the OS, that are different every time. Rust eliminates undefined behavior mainly through the borrow checker, which ensures every possible access to data is known and can be handled. It also provides many well engineered constructs to deal with uncertain situations at runtime. All this stems from Rust's strict policy against undefined behavior. Memory safety is one part of this. Usually, Memory safety can be advertised better.
hey Low Level Game Dev, what do you think about using rust?
yo, its not really for me and I don't think it fits gamedev. I preffer to be more flexible while writing code, and the safety that rust gives I can get from the way I structure my code. So it isn't really for me. I don't even use const in my code for context lol 😂😂
@@lowlevelgamedev9330 lol makes sense, thanks for the reply 😂
1. Choosing C++ over any other language.
what's the problem with C++ in game engine? One of the best languages to use.
Avoid all these problems by moving to Rust. 🤷
EDIT: since my answer to the guy below wasn't published, I have to assume that the author of this channel doesn't like when facts are not in his favor.
Hence I will state here that: 1. there is an operating system written in Rust and is called Redox OS.
2. That Rust is used in the Linux kernel itself.
3. Rust is used in gamedev and there are game engines built with Rust, for example the Bevy game engine.
4. After programming for 20+ years (15+ in C++, 7+ in JS/TS) I can safely state that, for C++ developers, there are absolutely no excuses why NOT move to Rust.
Operating Systems APIs don't use Rust, low level devs must use C and C++
@@averdadeeumaso4003 safe != high-level. Just because someone uses e.g. winit/glutin instead of glfw, or even glium instead of raw opengl calls, that doesn't mean the person isn't a low-level game developer. The safe API wrappers are a pretty thin layer in the overall game engine architecture.
@@averdadeeumaso4003 There is an operating system written in Rust called Redox OS. Also, Rust is used in the Linux kernel.
Tbh, rust makes game dev even more complicated and don't give advantages
@@averdadeeumaso4003 I don't exactly get what you mean, but those low level apis can be used from rust and also alot of windows componets are being rewrite in rust. rust is also now part of the linux kernel.