I mean, it's not that big of a deal IMHO, in fact that just goes to show how programmers makes mistakes & it's good that the compiler catch these sorts of things. Not having the sample code compiles doesn't really invalidate this video's points (the concept is still correct)
Rust does NOT prevent memory leaks. You can introduce them accidentally via cyclic references when using Rc or Arc. There is also a dedicated function in the standard library, see std::mem::forget
@@j_t_eklund The statement C leaks and Rust does not is clearly nonsense. If you write best practise code in each language, your code should not leak. The only difference I can see is that C makes the optimistic assumption that the developer knows they are doing and Rust makes the opposite assumption. This is all perfectly reasonable given the decades between the inception of each language.
A programming language is a tool more than anything else. A bad programmer will screw stuff in either C or Rust. The same applies to highly skilled and experienced developers. Well written C code shall "hug" both ends of memory allocation tight and things shall work just fine. You can write crappy software in any programming language or IDE.
Straight and to the point! Small nitpick: you can assign to the same name since the old name is no longer valid. No need to append numbers or invent new monikers.
That might introduce bugs if one is not careful, though. You might think the variable being used is the one at the start of your code, but it actually was redeclared after a free and you get the wrong one.
I think there's a little bit of conflation here between "use-after-free" bugs and "memory leak" bugs. The former lead to full-blown undefined behavior, which is a common problem in C and C++, and the way Rust prevents them with ownership, borrowing, and lifetimes is truly new among mainstream languages. The latter lead to gradual memory exhaustion, as you described in the video, but the way Rust prevents them isn't new. It's actually almost identical to what (modern) C++ does. In both Rust and C++, heap memory leaks are prevented by making sure every allocation is owned by some object(s) on the stack(s) that will eventually run a destructor to free that memory. Rust's Vec/Box/Arc are very close mirrors of C++'s vector/unique_ptr/shared_ptr.
use after free is not a bug, you can still get data from free'd pointers because memory doesn't get erased, it's just that it can now be used by the system again.
@@imyasuka There are definitely some cases where reading memory that you just freed will still happen to give you the old value. But there's no way to make that sort of thing reliable, and programs that do that are never portable. The free() function is allowed to trash the memory you gave it, and the optimizer is allowed to optimize heap allocations away such that malloc() and free() are never even called. So even if code like this appears to work, it's likely that it won't work under a different compiler or a different allocator or a different optimization level, or if inconsequential changes are made to nearby code. Equally importantly, use-after-free is explicitly defined to be undefined behavior in the standard, and programs that do it will almost always fail under -fsanitize=address or similar.
@@oconnor663, that's what I said, the program might still return an old value, because that memory hasn't been used yet. Memory is never erased, it's free'd
Hey man, I really appreciate these videos. One thing that I think could make them even more helpful to beginners (like me, at least with Rust) is to either highlight or animate specific sections of text when referencing jargon-heavy syntax explanations. If you highlighted each part of the syntax when describing what was going on, it would allow the video to also help people learn the language itself rather than just its features. Lmk what you think :)
Not good habits. Rust teaches you bad habits by requiring roundabout solutions for otherwise straight forward tasks. Not a good language to learn from.
@@maskettaman1488 If you need roundabout solutions, then you probably have bigger problems. Often those roundabout solutions are what's effectively happening under the hood in other languages, only in Rust their full cost is made apparent.
@@angeldude101 Not true at all. Sane languages don't have these problems in the first place. Even if you assume they do, then they at least have the decency to do it under the hood like you said. Let the compiler or runtime take care of it.. don't pass that burden on to the developer
Rust has atomic reference counting for when you need it they just use the acronym Arc instead. Reference-counting has a runtime-cost like garbage collection, the cost is just paid whenever an Arc leaves scope instead of in a separate thread.
Not to nitpick, but I think you mean smart pointers. The "auto_ptr" has been deprecated for a decade now. Also, "shared_ptr" is the only smart pointer to actually use reference counting. unique_ptr is typically preferred, and it actually works somewhat similarly to the way that rust handles variables.
@@user-py9cy1sy9u Well, I'm creating an object on A the stack, that holds a pointer to an object B on the Heap. When the last copy of A goes out of scope, B is freed. This is closer to manual memory management than to garbage collection where a thread stops everything and scans memory for dangling pointers.
@@1Maklak "Reference counting garbage collection is where each object has a count of the number of references to it. Garbage is identified by having a reference count of zero. An object's reference count is incremented when a reference to it is created, and decremented when a reference is destroyed. When the count reaches zero, the object's memory is reclaimed" Source: Wikipedia Garbage collection is not limited to stop the world mark and sweep. Any system that tracks object`s life time and deallocates memory is a garbage collector.
Most of the code examples in this video won’t actually compile. The very first example uses a never return type yet it returns just that it returns no data. Also there is an example where you pass an immutable reference to a function that expects a mutable reference
The code presented at 00:05 is so bad that the title should be "This is how Rust Stops People Who Dont Know C from using C" (I'm not even sure it works in normal cases, let alone corner cases)
yeah its really badly written even if it didnt leak 100% of the time, it does at least run though which cant be said for some of the Rust code presented 🙂
Thanks for posting this one. I'm enjoying as your stepping into Rust for the embedded world. It's something that I've been interested in digging more into, but it's been a struggle at times.
Thanks for explaining that implicit "drop()" function. That explains a lot about the limits on where you can pass variables/data around. It makes sense in hindsight, but I would probably not have waded into the docs to find this. As rather much of a noob to low-level languages and under-the-hood data management concepts.
i read a whole bunch of books on it and written a thousand or 2 lines, but something clicked finally when you described in terms of double free so thanks
Leaking memory is not always bad: depends on the situation. There are ton of cases where you don't care about freeing memory (for example programs that allocate memory on startup and then terminate without freeing it). Also, if you are doing a ton of dynamic memory allocations, you are doing something wrong. Dynamic memory allocation should be seen as the last resort, and prefer static allocation or stack allocation if possible. I write firmware and it's not unusual to not use dynamic memory allocation at all (in some safety critical contexts it's a requirement). And if dynamic memory allocation is use you typically allocate the memory that you need in the bootstrap of the firmware and then don't free it (continuing to free and allocate memory risks of fragmenting the heap)
- You can explicitly ask rust to leak memory very easily through a function literally called leak - Agreed, which is also why dynamic memory allocation is second-class in rust.
@@igorswies5913 And in other fields where you work near the limit of available RAM, you need to dynamically allocated and deallocate things to be within your memory
Back in the days I started it was assembly code and any issue was my fault. I was able to transition to coding in C without memory leaks very easily coming from a completely unforgiving start. I still prefer C although Objective-C with ARC (automatic reference counting) and Swift extensions to support stronger typing has made ObjC my favorite high-level language. (And I've coded in a bunch of them) I don't like Swift at all, not enough information visible in code.
Cool! I believe that many do not like to make language comparisons, but it is known that C++ with move semantics also gets around the problem involving ownership although it is different. Since you are adding to talk about the new language options for systems programming, it would be interesting to also bring to the channel the zig language. (if you are interested, of course!!)
C++ doesn't really get around the problem, since -> has to return a pointer or a "smart" pointer, so eventually you get a pointer. 'this' is also always a pointer. Just as an example.
@@darrennew8211 how is ‘this’ being a pointer related to this at all? ( C++ does not get around the problem of memory leaks, but neither does Rust; I don’t think there is a single non-GC language without memory leaks )
I only came into the Rust world a few days ago but I am starting to see a pattern of strange phrasing that might not be super accurate. Rust, being compared with C, has more ways to ensure that memory leaks don't happen, and that code is as efficient as possible using the Clippy tool. It's compiler is more feature rich than C, yet any build will run just as fast, if not faster. Suggestions for better code come from the devs themselves, and not from random people form stack exchange. The devs are adamant at getting people educated in Rust despite its complexity, and that is super admirable. Yet I don't see why people from the Rust community bash C specifically for the memory leak issue. even though the only reason it exists is because of less qualified coders who forget to free memory, and not because of the language itself. If you mean Rust and its environment are better at ensuring code runs fast, then yes, that makes sense. But as someone who uses C and C derivatives as well as Rust, you can write super efficient code if you know what you are doing. That goes for most languages. I feel like narratives like this close options for a lot of people. I suggest people check out C and see if it's better for them than Rust. If not, use this. If you like it, don't let people tell you otherwise.
"less qualified coders" there is a reason garbage collected languages exist. I would argue that there is only a very small percentage of people that can ensure that in no way memory leaks exist. And in most cases they use tests and tools like Valgrind to help them. Being "qualified" is good and all, but everyone makes mistakes and letting a machine proof that there is no issue is imo the best option
@@NabekenProG87 that is true not saying it’s a small problem, it’s in fact a big one. Around 70 percent of Microsoft Windows security bugs are caused by memory security issues in C and derivative language code. I still believe that C is a good language for low level control, and if you want a job TODAY, you should learn it. The rhetoric in the rust community is the thing that concerns me. I have no doubt that more reliable and secure languages will prevail in the future, but until other quality of like issues like slow compile times, C will be the reigning language. People like convenience over safety. It’s sad, but we have to take it in stride and improve the better and newer options. Also my comment was inaccurate in the second part, it IS because of the language itself, and I too don't like when languages work against you. I was trying to nail my point in and i missed the head of the nail lmao.
1:18 nit picking here, but technically speaking allocating memory on the stack is also dynamic. The size of the stack isn't known at compile time and can overflow (ex: infinite recursion). Functions can also be given a variable number of arguments. Only memory that is globally allocated is truly "static" (static globals). The distinction you actually mean is between automatically (static globals and stack data) and manually (heap data) managed memory, not static and dynamic. Garbage collection turns heap memory into another form of automatically managed memory, but it is not synonymous with automatic memory management. You can write very large programs in C without ever manually freeing memory if you're careful and only use the stack (many embedded programs are written this way). The stack is **NOT** created at compile time. Stack memory is allocated and freed **at runtime** by moving the stack pointer.
Great explanation !!! I came from the "Java World", learned some basic C++ at uni, but now I'm trying to learn some system programming and got caught up in the "Rust Hype" ... I know that C and C++ has both libraries that allows you to do basically anything you want computer wise ... and Rust still lags behind ... I don't plan to work as a system programmer, but really would like to develop some personal projects. Would anyone try a bit of advice? Go for C and C++ and take advantage of all those years and libraries or follow the "Modern" way but lack of proper support for a lot of libraries?
Yo - professional C++ dev - happy to respond :) Why not learn both? As C++ continues modernizing, many similar features can be learned from both. I like Rust - I've written a bit in it and I enjoy the functional programming influences. Try a bit of everything and pick what best supports your needs and way of thinking. Best to ya.
Every programming language is useful in some way or another. All languages, given you study them hard enough, make you a better software developer on the go, because you train problem solving and this particular skill isn't language-bound. I'd suggest you pick C/C++ because of the extremely solid computer background they help build ground for you to acquire, but I'm pretty sure Rust (or even Java, Python etc.) will do.
If you're looking to stay in your comfort zone, C++ would be a great choice as most of Java's ideas were "borrowed" (pun intended) from C++. However, personally, I think comfort zones suck and Rust would introduce you to an object model very different from Java's.
Technically, it is bad coding practices that lead to memory leaks. It's not entirely the language's fault. And one very bad coding practice is using C (except in rare embedded cases), considering that C++ exists. I like C++'s approach to the problem. It allows you to do things the safe way or the slightly more efficient but unsafe way. When it comes to heap memory, I can't really blame rust for doing it only in the safe way since memory allocations are expencive enough that the extra safety code is nothing in comparison. So nowadays I never use malloc or new. Requiring the developer to manually release resources is really bad imo both for safety and readability. Having them release themselves once they leave scope or the destructor is called for some other reason is much nicer.
All I see here is the underlying rvalue move semantics, compile time assertions via possibly static strings or non-heap allocated strings such as const char* or string view with reference checking via maybe shared_ptrs or some sort of internal state system that handles ref counters (compile time checking can be relatively easily implemented since C++17; a lil more difficult prior to that), at play to be honest. At 5:00, with the gsl library that most compilers ship with nowadays, you get that same compiler warning as well (same with using string_views on sub strings created via the substr() function or a string view created from a local temporary). Granted I mess around primarily in C++ with hobby projects and haven't tried Rust out; but I literally see no point in learning a new syntax for something I only need to know a few extra concepts and some minor standard syntax to pull off... Maybe concurrency life is better in Rust, but for a general case - I honestly don't see the point
Regarding concurrency, data races are impossible in Safe Rust. The borrowing pretty much gives compile time read-write locking, and the Send and Sync traits tightly control what can be sent to other threads.
@@angeldude101 I definitely have to give Rust a shot before totally saying "nah" to it - just that the points in the video weren't compelling; that being said, what you're mentioning sounds like a relatively headache-free approach to multi-threading so that in and of itself is pretty compelling lol out of curiosity, does this guarantee work across futures as well?
@@XxxGuitarMadnessxxX Any task that gets sent to another thread needs to implement Send to make sure it doesn't cause any race conditions. Most types in Rust are Send with the notable exception of interior mutable types like Cell and RefCell, which are effectively the thread unsafe versions of Atomic_ and RWLock. Futures aren't actually required to be Send because they don't actually required multithreading. Futures that aren't Send are only capable of being run on single-threaded runtimes, while multithreaded runtimes do require that the Futures in question implement Send.
I have learned SFINAE in the past. I am glad I no longer need to remember it. The final straw was the C++ failure to develop new solutions at language level, instead of making language hacks on top of language hacks. Dig into rust standard library: you will find complicated but reasonably straightforward system-level code. Dig into C++ standard library - you will find hacks upon hacks.
the last example is not quite right, while the code shown does not compile, the explanation is wrong. You _can_ create multiple *immutable* borrows, but only one *mutable* borrow.
05:20 What you said about not being able to have two borrows coexist is not fully true. In Rust, you can have either 1 mutable reference on scope, or multiple inmutable/simple references to the same variable.
Well simply make sure you are aware of every dynamic allocation you make and make sure that you free it when you stop using it, it's not really a problem if you know what you are doing
This sounds like sarcasm but I think you might be serious. "Don't fuck up" is also a great argument for not needing any high-level programming constructs at all. Who needs variables with names when you can just remember what value is each register at all times? Why let a compiler tell you that you're doing something wrong when you can just do it right in the first place? Might as well just breath manually while you're at it.
It doesn’t actually stop anything. You can still fail on memory leaks because vectors can actually be used as allocators and that memory is then also never given back. The lifetime problem is extremely hard problem.
Not a counter argument at all, but it might be interesting to note that Perl has the same implicit drop(), except borrowing increases the reference's "ref count" and the drop() equivalent decreases the "ref count" and then frees the memory if the ref count goes to 0. This can cause problems with circular references; Perl has a weaken() function to set a flag on a reference that basically says to decrease the ref count of the whole circle when the ref count of the thing being weakened is only referenced by the circle it's in.
I was just thinking today about how great it was that Rust just keeps you from doing dumb stuff to keep you safe. I like the idea that it does "garbage collection at compile time"
I do like these videos but the jabs at Java for not being efficient were tired a long time ago. I still hear people complain about how applets were slow and how Java sucks compared to Python, etc. Java can be slow, but Python and other interpreted languages are almost always slow. Why do we cut them so much slack? I’d prefer Java to avoid Pythons many foot guns AND slowness in most situations where my code is not a throwaway script.
Just a small nickpick.. The example you showed was BAD. C compared to Rust is like hmm.. You shooting yourself in the leg and blaming the gun. C being the gun in this case. C as a language, Doesn't do shit. If something is wrong, It's the programmers fault, Not the languages..
the C code shown 10 seconds in was extremely badly written and is not an honest example of a subtle memory leak: 1, it technically leaks memory in all cases since the allocated memory is never freed 2, allocating memory on each iteration of the loop rubs salt in the wound, and is very slow this is my attempt at writing the same program: int main(int argc, char* argv[]) { int l[512], t = 0; for(int i = 0; i < argc; i++){ l[i] = strlen(argv[i]); t += l[i] + 1; } char* s = malloc(t); for(int i = 0; i < argc; i++){ strcpy(s, argv[i]); s += l[i]; *s++ = ' '; } *--s = 0; s -= t - 1; printf("You entered: %s ", s); free(s); return 0; } notice how malloc is only called once, and the memory is freed when it is no longer in use. by simply remembering every time you call malloc you must eventually call free you will literally never run into this issue, no need to learn rust.
C has a lot of useful tools, the problem is they are not built in. While most people should be using extra tooling with C its not common. That's why rust tooling is nice, most things are built and shipped with the compiler. Even better they are on by default. C is a great language and so is C++. Give rust a try once you understand it you may just like it.
Everyone hates java bc it's so hard to type. But literally it's less bug prone, is readable, and is great for dda. Imagine if you could directly access memory and have it gc like Go. It'd be the perfect C replacement
If you compare Rust to pure C or C++98 it looks great. But if you compare it to C++17 (used *properly*) I think it’s a far less convincing proposition.
Java isn't that bad and tbh modern java is SO MUCH better. I kinda feel like old java built up all this hate that modern java just can't shake even when the hate isn't really valid anymore. To be clear I understand that a GC/runtime is ALWAYS more bloated than a language without but I'm not sure java is a worse offender than any other modern GC language.
C++ std::unique_ptr I am quite impressed by Rust's static checking though. You have to enable every warning possible on the C++ side of things plus use linters to get anywhere close
I will always love C, but I have tried rust for a bit and have come to like it too. The compiler for Rust won’t really ever let u write “bad” code. Especially with clippy. It warns u of every mistake and unideal code. It’s both great at helping u learn rust and also making u question the many years you’ve spent programming 😂
You CAN borrow multiple times, but you cannot borrow multiple times *mutably*. Also you can't mix and match. You can borrow immutably multiple times, but unless all those borrows are done, you cannot borrow mutably afterwards.
That example in the beginning of the video is just plain wrong. It doesn't prove that C is inadequate, only humans are inadequate, or programmers should take their time and write their work carefully and not rush because of a deadline or the boss complaining.
Most system code generation tools or things like SCADE or Matlab SimuLink will generate C code to use, so at a minimum you need to be able interface with C code for a lot of embedded systems stuff
And from my experience, if you try embedded with rust, you will still need to understand C examples or C auto-generated code. But basic embedded C is not that hard.
Another reason the garbage collector takes performance is as I have heard that every time the garbage collector goes in the program actually stops completley while the garbage collector frees the memory and there is no way for the programmer to override it and say "wait with GC until this is finished first". This is a possible issue in for example games. Lets say u are at a boss fight and ends up getting killed because the garbage collector goes in at just the wrong time just when u were about to land a critical hit and freezes up the game right then. It however dont seem to be an issues with game engines like Unity that uses C# wich is garbage collected but I remember someone doing a test that showed a clear FPS/performance drop when the garbage collector activated. I guess the only reason we dont really notice it still is because todays CPUs even on mobile devices are now so powerful that this performance drop during garbage collection is simply not enough to cause issues. On the other hand Unreal Engine wich uses C++ also dont need you to free memory manually but also have some form of garbage collection system for the C++ part. I have seen u can change its settings in the progect settings menu but never looked at it more then noticed that it is there. I dont know how UE handles the garbage collection compared to Unity and C# where the garbage collection is built into the language itself although I have no idea how Unity handles this under the hood and as I have not created any extremley heavy game in Unity enough for GC to be noticeable I have not been able to notice this myself either and all games made with Unity in general seems also to have no real performance /stutter issues, again the powerful CPUS of today I think might be what offsets this, its simply more then enough for the task even if some CPU cycles is wasted now and then from GC.
It's not just processors that are getting more efficient year after year. Memory freeing algorithms are also getting more efficient. Also running the garbage collector in a separate thread or a separate goroutine eliminates the problem of program hangs. The areas of manually managed memory languages are shrinking
C is NOT an applications programming language. It’s an architecture independent macro assembly language with good library support. It’s great for systems programming and hard real time. For pretty much anything else, you could find a better tool to get the job done.
Really, who has problems with memory leaks in C/C++? That's like the Cobol people saying you shouldn't use C because you could accidentally format your hard drive in it. Rust's solution seems a bit heavy handed for a non problem. Or at least a problems from 20 year old compilers.
@Intuition Yes, Some of the worst code I've ever seen was from an engineering company that installed the automated conveyor system in the distribution warehouse. The hardware was excellent. Top notch. But the software...... Yikes. Took months just to stop it from crashing. Who in their right mind would use SQL for a temporary FIFO link list where timing is critical. Their solution, Hire someone to constantly move all the missed boxes from he end of the conveyor back to the start. Sheesh. But even with those yahoos I don't remember memory leaks being a problem. Course. with it crashing all the time it may not of came up as a problem.
Another exercise in shilling Rust by making false statements against other languages. C does not leak memory. C itself places all variables on the stack or in statically loaded chunks depending on how the variable is qualified. Can code written in C can leak memory? Of course. We call this a "bug" and it happens when people start allocating their own memory and resources and forgetting to release them.
Here is the thing, C essentially "says" screw people that want to program in low level and are not as skilled/knowledgeable, then comes a language that makes it difficult for people to fuck it up while retaining similar performance/control. I believe you can see why people like it.
They get caught immeadiatly on your IDE. If you don't have rust analyzer on the IDE the compiler messages are very helpfull and clear too. The whole point of Rust is in fact, making sure you catch these problems in compile time rather than beeing surprised by them during runtime.
Huh, nice and clear. Any protection for neophytes like me...creating recursive functions allocating memory in stack and hitting the heap? Don't ask me how I know! :-D
Rust guarantees that overflowing the stack will safely crash your program rather than causing UB. I believe C and C++ can make similar guarantees depending on what compiler flags you use. One of the common ways this can come up in Rust and C++, besides accidental infinite loops, is if you forget to override the default destructor for a Box-based (Rust) or unique_ptr-based (C++) linked list.
@@SandwichMitGurke im just learning os dev im hoping it will become sth good, since i know rust its a no brainer to use it, cuz it provides a lot of benefits vs c, if u are interested theres a comunity for rust os dev i can add u :)
@@echoptic775 best luck to you. I don't have anything to do with OS development and don't really have interest in it either, sorry. I'm learning Rust atm for game development / games in browser with wasm and embedded systems.
3:04 I thought since this language had all the Bells and whistles; it could monitor the use of variable/pointer. Like take a page out of valgrinds book
i haven't wrote any project in rust. however the more I look at it the more it feels like what I wish c++ was. when I find time from uni I will definitely try to do a project in rust. it sounds like a really good language. if anyone wants to point me to possible applications as well that would be great.
I really love rustlang but I am getting no project ideas to use it with. I want to code more in rustlang but there is always better ecosystem on some other language. I went through the rustlang book but how do I take it to the next level now? I really like JS because you get this immediate feedback like with webapps.
The textbook "Programming Rust" gives a list of different applications of Rust as examples of what is called "systems programming", which they define as "resource-constrainted" programming. Here's the list: * Operating systems * Device drivers of all kinds * Filesystems * Databases * Code that runs in very cheap devices, or devices that must be extremely reliable * Cryptography * Media codecs (software for reading and writing audio, video, and image files) * Media processing (for example, speech recognition or photo editing software) * Memory management (for example, implementing a garbage collector) * Text rendering (the conversion of text and fonts into pixels) * Implementing higher-level programming languages (like JavaScript and Python) * Networking * Virtualization and software containers * Scientific simulations * Games I've used Rust for the last 3 items on this list and can say it's quite well suited for them. However, for making games, it's best for simple games, games on resource-constrained hardware (NES, GBA, etc.), or linked with a proper game engine (Godot, Unity). Otherwise, you'll be putting in a lot of effort to build from scratch what a game engine will give you for free -- particularly on the 3D graphics side. Also, if you're interested in early game consoles, Rust is great for writing emulators. I've written a few simple emulators in C++ and in Rust, and the latter is just a better experience and product all around. It's a very fun and rewarding project, and at the end you can use to play actual games (or make your own using Rust)!
@@alxjones wow this is really helpful, I'll trying taking a look at the "programming rust" book. Can you please point me to the correct edition and authors for that book? This is probably the best comment ever!! Thanks!!!
@@pinch-of-salt Programming Rust, 2nd Edition by Jim Blandy, Jason Orendorff, Leonora F. S. Tindall It's about $30 USD for 1200 pages packed full of useful information. Good read front-to-back or skipping around, and a great reference to have on the shelf. It's *not* a book about systems programming, though. That list of applications is in the introduction and is about as deep as it gets into any of those subjects. If you're looking for something like that, this is not it; it's just a really solid text on the Rust programming language.
I see, a solution without a problem. If a person is unable to correctly allocate and free memory, they should look for a different career. Memory management is a tiny challenge compared to the complexity of libraries that one must use in daily work, networking, multi-threading, etc. C is a great language, it will outlive Rust, Go, Java, etc. C can be used to manipulate registers on a CPU, and also to do symbolic math. It also scales well, even for huge projects.
Everyone makes mistakes. After all, to err is only human, and assuming we're all human here, that means every single one of us is fallible and very much capable of making a mistake. No matter how small the actual chance of making that mistake, literally everyone makes mistakes from time to time. And, assuming you're a human being of course, that includes you, me and anyone else currently reading this comment. Given that fact, I see incredible value in a solution that, quite literally, makes it impossible to screw up your applications' memory management, unless you're purposefully circumventing the safeguards by surrounding your code with the unsafe keyword, of course.
@@TheBauwssss Wise words. It's just not helpful to say "oh I am so experienced that my code can't have bugs and logical errors". And one thing that isn't considered in this type of arguments is, that experience just comes from ... guess what, experience. It's totally normal that someone new from college or university does mistakes that experienced programmers don't. But if only the experienced programmers code, the new ones can't get experience because they never learned from practical work.
An expert programmer can avoid memory leaks and UB in a small-to-medium codebase, but at this point it's an established fact that *teams* of expert programmers working in large codebases cannot avoid these bugs. Expert programmers develop memory discipline over time, but not everyone's memory discipline is the same, and components of large programs have a tendency to miscommunicate about who owns what in untested edge cases.
Java probably has the most efficient garbage collector at this point. Would love for you to cite your source or reasoning why Java should be poster child for inefficient GC.
Even loving Rust, hearing "inefficient" and a image of Java doesn't make sense. I could say I shared this view years ago, but after seeing what people can do with Java, nah that shit is efficient as fuck.
This strategy can be enhance with ide tools i guess otherwise it is not of much help in envs where you have some extra kilobytes and some Hertz to play around a GC still rocks
the concept of "ownership and borrowing" is just an abstraction of rust's garbage collection (just like c/c++ memory management in just a safer way maybe) or am I wrong and is it only me? here is how I see it c/c++ garbage collection is manual (blazingly fast but leads to memory leaks) go/java/c# garbage collection is automatic (fast, safe and leads to dev's productivity) rust garbage collection like c/c++, manual but is a must (blazingly fast and safe)
Can someone explain the "edge cases" he talks about right at the beginning (0:12?) it seems like this code should _almost always_ leak memory, since it never frees anything. I might be misunderstanding something though.
You can do that in multiple ways. If you are allocating a new string it just copys, but if you want non allocation it would hold an immutable reference. The benefit to the non allocation part in rust is that the original string cannot be changed from underneath you, it also cannot cause a lifetime issue. So yes this is possible.
Basically the same way. The rules don't change with larger programs. You use lifetimes within function scopes and structures. If you know lifetimes, borrow rules, and ownership, it doesn't get much more complicated.
There are a variety of types for expressing different ownership scenarios. Box for unique ownership of a heap allocation, Vec for owned dynamic arrays, Rc for ref-counted pointers (thread unsafe, but this is compiler-checked so you can safely use it around threads anyway) and Arc for the thread-safe version, RefCell for thread-unsafe interior mutability (dynamically checked safe mutable access from re-entrant code), and Mutex for the thread-safe version. The real power of having the compiler have your back in all these cases is that even if you have a huge and complicated system combining all these things you can have peace of mind that they won't conspire to create a nasty data race or double-free bug. C++ does not give you that, even if it gives you all the same ownership semantics types. C just uses T* for everything and leaves it to the programmer to be "disciplined" even past the one-brain barrier.
Just a small nitpick: the "Good Rust" code at 04:00 doesn't compile since you'll need to pass `&mut s` instead of only `&s`. But otherwise it's good!
Ah crap, good catch. Thank you!
@@LowLevelTV Shouldn't you have initialized string_so_far to 0? Seems like it's read before initialization.
@@LowLevelTV Wait, did you really not hit compile on the examples? Lame.
@Jani SIr ooohhhhh... this just cost 'm a subscriber. I thought this was a quality channel.
I mean, it's not that big of a deal IMHO, in fact that just goes to show how programmers makes mistakes & it's good that the compiler catch these sorts of things. Not having the sample code compiles doesn't really invalidate this video's points (the concept is still correct)
5:12 can be referenced multiple times if the variable is not referenced as mutable.
Rust does NOT prevent memory leaks. You can introduce them accidentally via cyclic references when using Rc or Arc. There is also a dedicated function in the standard library, see std::mem::forget
Box::new(value).leak() will also leak memory, and quite voluntarily in this case
@@j_t_eklund It is, yes
@@j_t_eklund ah yes following good practices, which totally cannot be done in C
@@j_t_eklund The statement C leaks and Rust does not is clearly nonsense. If you write best practise code in each language, your code should not leak. The only difference I can see is that C makes the optimistic assumption that the developer knows they are doing and Rust makes the opposite assumption. This is all perfectly reasonable given the decades between the inception of each language.
A programming language is a tool more than anything else. A bad programmer will screw stuff in either C or Rust. The same applies to highly skilled and experienced developers. Well written C code shall "hug" both ends of memory allocation tight and things shall work just fine. You can write crappy software in any programming language or IDE.
Straight and to the point!
Small nitpick: you can assign to the same name since the old name is no longer valid. No need to append numbers or invent new monikers.
Ah fair point. Thank you
That might introduce bugs if one is not careful, though. You might think the variable being used is the one at the start of your code, but it actually was redeclared after a free and you get the wrong one.
it is a good thing.. but go into the beginners' perspective.. isn't it really tricky to understand for a non-rust programmer?
I think there's a little bit of conflation here between "use-after-free" bugs and "memory leak" bugs. The former lead to full-blown undefined behavior, which is a common problem in C and C++, and the way Rust prevents them with ownership, borrowing, and lifetimes is truly new among mainstream languages. The latter lead to gradual memory exhaustion, as you described in the video, but the way Rust prevents them isn't new. It's actually almost identical to what (modern) C++ does. In both Rust and C++, heap memory leaks are prevented by making sure every allocation is owned by some object(s) on the stack(s) that will eventually run a destructor to free that memory. Rust's Vec/Box/Arc are very close mirrors of C++'s vector/unique_ptr/shared_ptr.
use after free is not a bug, you can still get data from free'd pointers because memory doesn't get erased, it's just that it can now be used by the system again.
@@imyasuka There are definitely some cases where reading memory that you just freed will still happen to give you the old value. But there's no way to make that sort of thing reliable, and programs that do that are never portable. The free() function is allowed to trash the memory you gave it, and the optimizer is allowed to optimize heap allocations away such that malloc() and free() are never even called. So even if code like this appears to work, it's likely that it won't work under a different compiler or a different allocator or a different optimization level, or if inconsequential changes are made to nearby code. Equally importantly, use-after-free is explicitly defined to be undefined behavior in the standard, and programs that do it will almost always fail under -fsanitize=address or similar.
@@oconnor663, that's what I said, the program might still return an old value, because that memory hasn't been used yet. Memory is never erased, it's free'd
@@imyasuka you're being pedantic about bad practice, there is no reason why you should try to access memory post-free
@@kylemetscher4923, I just said that it's not a bug bro, where was I advocating for practical usage?
0:10 "in a couple of edge cases". Well since there is no "free" anywhere, these couple of edge cases are 100%
Hey man, I really appreciate these videos. One thing that I think could make them even more helpful to beginners (like me, at least with Rust) is to either highlight or animate specific sections of text when referencing jargon-heavy syntax explanations. If you highlighted each part of the syntax when describing what was going on, it would allow the video to also help people learn the language itself rather than just its features. Lmk what you think :)
Yeah but C is still awesome
Totally agree!
@Appley Systems C was my first love.
C? C? You C that bullshit? :)
@@dorktales254 Yep
Yeah but the next thing after Rust from what we've learned with Rust might make C less awesome comparatively.
all I got from this video was that rust forces you to use good habbits.
If by "use good habits" you mean "not causing catastrophic runtime errors that the compiler won't tell you about," then yeah.
Rusts entire premise is: what if we simply didn’t allow programmers to make stupid mistakes that can be checked at compiletime
Not good habits. Rust teaches you bad habits by requiring roundabout solutions for otherwise straight forward tasks. Not a good language to learn from.
@@maskettaman1488 If you need roundabout solutions, then you probably have bigger problems. Often those roundabout solutions are what's effectively happening under the hood in other languages, only in Rust their full cost is made apparent.
@@angeldude101 Not true at all. Sane languages don't have these problems in the first place.
Even if you assume they do, then they at least have the decency to do it under the hood like you said. Let the compiler or runtime take care of it.. don't pass that burden on to the developer
This makes me appreciate automatic pointers from CPP. They use reference counting and the destructor frees memory when going out of scope.
Rust has atomic reference counting for when you need it they just use the acronym Arc instead. Reference-counting has a runtime-cost like garbage collection, the cost is just paid whenever an Arc leaves scope instead of in a separate thread.
Not to nitpick, but I think you mean smart pointers. The "auto_ptr" has been deprecated for a decade now. Also, "shared_ptr" is the only smart pointer to actually use reference counting. unique_ptr is typically preferred, and it actually works somewhat similarly to the way that rust handles variables.
reference counting is a form of garbage collection but no C++ guy will call it that way.
@@user-py9cy1sy9u Well, I'm creating an object on A the stack, that holds a pointer to an object B on the Heap. When the last copy of A goes out of scope, B is freed. This is closer to manual memory management than to garbage collection where a thread stops everything and scans memory for dangling pointers.
@@1Maklak "Reference counting garbage collection is where each object has a count of the number of references to it. Garbage is identified by having a reference count of zero. An object's reference count is incremented when a reference to it is created, and decremented when a reference is destroyed. When the count reaches zero, the object's memory is reclaimed"
Source: Wikipedia
Garbage collection is not limited to stop the world mark and sweep. Any system that tracks object`s life time and deallocates memory is a garbage collector.
Most of the code examples in this video won’t actually compile. The very first example uses a never return type yet it returns just that it returns no data. Also there is an example where you pass an immutable reference to a function that expects a mutable reference
About the Double Borrow: you can borrow as many time as want, but you can only borrow mutable once
The code presented at 00:05 is so bad that the title should be "This is how Rust Stops People Who Dont Know C from using C" (I'm not even sure it works in normal cases, let alone corner cases)
yeah its really badly written even if it didnt leak 100% of the time, it does at least run though which cant be said for some of the Rust code presented 🙂
Thanks for posting this one. I'm enjoying as your stepping into Rust for the embedded world. It's something that I've been interested in digging more into, but it's been a struggle at times.
Thanks for explaining that implicit "drop()" function. That explains a lot about the limits on where you can pass variables/data around. It makes sense in hindsight, but I would probably not have waded into the docs to find this. As rather much of a noob to low-level languages and under-the-hood data management concepts.
In the end of the day. You can't live without C
i read a whole bunch of books on it and written a thousand or 2 lines, but something clicked finally when you described in terms of double free so thanks
Leaking memory is not always bad: depends on the situation. There are ton of cases where you don't care about freeing memory (for example programs that allocate memory on startup and then terminate without freeing it). Also, if you are doing a ton of dynamic memory allocations, you are doing something wrong. Dynamic memory allocation should be seen as the last resort, and prefer static allocation or stack allocation if possible. I write firmware and it's not unusual to not use dynamic memory allocation at all (in some safety critical contexts it's a requirement). And if dynamic memory allocation is use you typically allocate the memory that you need in the bootstrap of the firmware and then don't free it (continuing to free and allocate memory risks of fragmenting the heap)
Just do that in unsafe rust code?
- You can explicitly ask rust to leak memory very easily through a function literally called leak
- Agreed, which is also why dynamic memory allocation is second-class in rust.
not everybody is doing firmware and in many fields much less development time is more important than optimising for the microseconds
@@igorswies5913 true
@@igorswies5913 And in other fields where you work near the limit of available RAM, you need to dynamically allocated and deallocate things to be within your memory
I would personally also talk about the box type, because that's pretty important.
Back in the days I started it was assembly code and any issue was my fault. I was able to transition to coding in C without memory leaks very easily coming from a completely unforgiving start. I still prefer C although Objective-C with ARC (automatic reference counting) and Swift extensions to support stronger typing has made ObjC my favorite high-level language. (And I've coded in a bunch of them) I don't like Swift at all, not enough information visible in code.
Cool! I believe that many do not like to make language comparisons, but it is known that C++ with move semantics also gets around the problem involving ownership although it is different.
Since you are adding to talk about the new language options for systems programming, it would be interesting to also bring to the channel the zig language. (if you are interested, of course!!)
I like zig
C++ doesn't really get around the problem, since -> has to return a pointer or a "smart" pointer, so eventually you get a pointer. 'this' is also always a pointer. Just as an example.
@@darrennew8211 how is ‘this’ being a pointer related to this at all?
( C++ does not get around the problem of memory leaks, but neither does Rust; I don’t think there is a single non-GC language without memory leaks )
@@chri-k Because you can't make every pointer a smart pointer.
@@darrennew8211 what even is a smart pointer?
( i know little C++, and especially little modern C++ )
Variables can also be cloned if they’re of a type that implements the “Clone” trait.
Great explaination, really helps to clarify the concept of ownership and borrowing...
I only came into the Rust world a few days ago but I am starting to see a pattern of strange phrasing that might not be super accurate.
Rust, being compared with C, has more ways to ensure that memory leaks don't happen, and that code is as efficient as possible using the Clippy tool. It's compiler is more feature rich than C, yet any build will run just as fast, if not faster. Suggestions for better code come from the devs themselves, and not from random people form stack exchange. The devs are adamant at getting people educated in Rust despite its complexity, and that is super admirable.
Yet I don't see why people from the Rust community bash C specifically for the memory leak issue. even though the only reason it exists is because of less qualified coders who forget to free memory, and not because of the language itself.
If you mean Rust and its environment are better at ensuring code runs fast, then yes, that makes sense. But as someone who uses C and C derivatives as well as Rust, you can write super efficient code if you know what you are doing. That goes for most languages. I feel like narratives like this close options for a lot of people. I suggest people check out C and see if it's better for them than Rust. If not, use this. If you like it, don't let people tell you otherwise.
"less qualified coders" there is a reason garbage collected languages exist. I would argue that there is only a very small percentage of people that can ensure that in no way memory leaks exist. And in most cases they use tests and tools like Valgrind to help them.
Being "qualified" is good and all, but everyone makes mistakes and letting a machine proof that there is no issue is imo the best option
@@NabekenProG87 that is true not saying it’s a small problem, it’s in fact a big one. Around 70 percent of Microsoft Windows security bugs are caused by memory security issues in C and derivative language code. I still believe that C is a good language for low level control, and if you want a job TODAY, you should learn it. The rhetoric in the rust community is the thing that concerns me. I have no doubt that more reliable and secure languages will prevail in the future, but until other quality of like issues like slow compile times, C will be the reigning language. People like convenience over safety. It’s sad, but we have to take it in stride and improve the better and newer options. Also my comment was inaccurate in the second part, it IS because of the language itself, and I too don't like when languages work against you. I was trying to nail my point in and i missed the head of the nail lmao.
1:18 nit picking here, but technically speaking allocating memory on the stack is also dynamic. The size of the stack isn't known at compile time and can overflow (ex: infinite recursion). Functions can also be given a variable number of arguments. Only memory that is globally allocated is truly "static" (static globals).
The distinction you actually mean is between automatically (static globals and stack data) and manually (heap data) managed memory, not static and dynamic.
Garbage collection turns heap memory into another form of automatically managed memory, but it is not synonymous with automatic memory management. You can write very large programs in C without ever manually freeing memory if you're careful and only use the stack (many embedded programs are written this way).
The stack is **NOT** created at compile time. Stack memory is allocated and freed **at runtime** by moving the stack pointer.
Thought this was talking about the game and I was like “Lmao you ever play that tirefire?”
Awesome concise video. Subbed!
Welcome!
5:13 You can borrow twice or more, but only with immutable references.
Great explanation !!!
I came from the "Java World", learned some basic C++ at uni, but now I'm trying to learn some system programming and got caught up in the "Rust Hype" ... I know that C and C++ has both libraries that allows you to do basically anything you want computer wise ... and Rust still lags behind ... I don't plan to work as a system programmer, but really would like to develop some personal projects.
Would anyone try a bit of advice? Go for C and C++ and take advantage of all those years and libraries or follow the "Modern" way but lack of proper support for a lot of libraries?
Yo - professional C++ dev - happy to respond :)
Why not learn both? As C++ continues modernizing, many similar features can be learned from both. I like Rust - I've written a bit in it and I enjoy the functional programming influences. Try a bit of everything and pick what best supports your needs and way of thinking. Best to ya.
Every programming language is useful in some way or another. All languages, given you study them hard enough, make you a better software developer on the go, because you train problem solving and this particular skill isn't language-bound.
I'd suggest you pick C/C++ because of the extremely solid computer background they help build ground for you to acquire, but I'm pretty sure Rust (or even Java, Python etc.) will do.
If you're looking to stay in your comfort zone, C++ would be a great choice as most of Java's ideas were "borrowed" (pun intended) from C++. However, personally, I think comfort zones suck and Rust would introduce you to an object model very different from Java's.
I swear to god I thought you were gonna say "First we need to talk about parallel universes" at 1:13
Technically, it is bad coding practices that lead to memory leaks. It's not entirely the language's fault. And one very bad coding practice is using C (except in rare embedded cases), considering that C++ exists. I like C++'s approach to the problem. It allows you to do things the safe way or the slightly more efficient but unsafe way. When it comes to heap memory, I can't really blame rust for doing it only in the safe way since memory allocations are expencive enough that the extra safety code is nothing in comparison. So nowadays I never use malloc or new. Requiring the developer to manually release resources is really bad imo both for safety and readability. Having them release themselves once they leave scope or the destructor is called for some other reason is much nicer.
Its like the only thing I ever hear people talk about with Rust: garbage collection. Yay?
Tell that to Linux kernel project.
@@ukyoize (except in rare embedded cases) Not quite the same but a think an OS qualifies. Although you could do that with Rust too.
All I see here is the underlying rvalue move semantics, compile time assertions via possibly static strings or non-heap allocated strings such as const char* or string view with reference checking via maybe shared_ptrs or some sort of internal state system that handles ref counters (compile time checking can be relatively easily implemented since C++17; a lil more difficult prior to that), at play to be honest. At 5:00, with the gsl library that most compilers ship with nowadays, you get that same compiler warning as well (same with using string_views on sub strings created via the substr() function or a string view created from a local temporary). Granted I mess around primarily in C++ with hobby projects and haven't tried Rust out; but I literally see no point in learning a new syntax for something I only need to know a few extra concepts and some minor standard syntax to pull off... Maybe concurrency life is better in Rust, but for a general case - I honestly don't see the point
Regarding concurrency, data races are impossible in Safe Rust. The borrowing pretty much gives compile time read-write locking, and the Send and Sync traits tightly control what can be sent to other threads.
@@angeldude101 I definitely have to give Rust a shot before totally saying "nah" to it - just that the points in the video weren't compelling; that being said, what you're mentioning sounds like a relatively headache-free approach to multi-threading so that in and of itself is pretty compelling lol out of curiosity, does this guarantee work across futures as well?
@@XxxGuitarMadnessxxX Any task that gets sent to another thread needs to implement Send to make sure it doesn't cause any race conditions. Most types in Rust are Send with the notable exception of interior mutable types like Cell and RefCell, which are effectively the thread unsafe versions of Atomic_ and RWLock.
Futures aren't actually required to be Send because they don't actually required multithreading. Futures that aren't Send are only capable of being run on single-threaded runtimes, while multithreaded runtimes do require that the Futures in question implement Send.
I have learned SFINAE in the past. I am glad I no longer need to remember it.
The final straw was the C++ failure to develop new solutions at language level, instead of making language hacks on top of language hacks.
Dig into rust standard library: you will find complicated but reasonably straightforward system-level code. Dig into C++ standard library - you will find hacks upon hacks.
@@OrbitalCookie to be fair, the concepts library added in C++20 pretty much eliminated the explicit need for SFINAE
memory leaks are safe behavior in rust, and not what the ownership checker is for...
Very informative, love your creations, can you please make a video on how html is painted on the screen means actual hardware
Nice explanation bro
Rewatching this video, the Rust example feels exactly like passing by reference in C.
Thanks!
Mark! Thank YOU, my guy. Any time.
`cargo check` is your friend
Great video. You deserve a lot more view. Keep up the good work
Thanks, will do!
the last example is not quite right, while the code shown does not compile, the explanation is wrong. You _can_ create multiple *immutable* borrows, but only one *mutable* borrow.
At 1:52, I think marking the return type as ! is incorrect because that function will indeed return.
Example at 4:00 does not compile, because the function expects a mutable borrow, and you are passing a borrow (reference to s, not mutable reference)
05:20 What you said about not being able to have two borrows coexist is not fully true.
In Rust, you can have either 1 mutable reference on scope, or multiple inmutable/simple references to the same variable.
Well simply make sure you are aware of every dynamic allocation you make and make sure that you free it when you stop using it, it's not really a problem if you know what you are doing
Computers are meant for automation and good languages allow you to write safe code where you do not have to remember everything.
This sounds like sarcasm but I think you might be serious. "Don't fuck up" is also a great argument for not needing any high-level programming constructs at all. Who needs variables with names when you can just remember what value is each register at all times? Why let a compiler tell you that you're doing something wrong when you can just do it right in the first place? Might as well just breath manually while you're at it.
It doesn’t actually stop anything. You can still fail on memory leaks because vectors can actually be used as allocators and that memory is then also never given back. The lifetime problem is extremely hard problem.
Not a counter argument at all, but it might be interesting to note that Perl has the same implicit drop(), except borrowing increases the reference's "ref count" and the drop() equivalent decreases the "ref count" and then frees the memory if the ref count goes to 0. This can cause problems with circular references; Perl has a weaken() function to set a flag on a reference that basically says to decrease the ref count of the whole circle when the ref count of the thing being weakened is only referenced by the circle it's in.
You *can* double borrow actually, as many times as you like. However, none of them can be mutable, otherwise, like you said, race condition
I was just thinking today about how great it was that Rust just keeps you from doing dumb stuff to keep you safe. I like the idea that it does "garbage collection at compile time"
great video. Thank you!
I do like these videos but the jabs at Java for not being efficient were tired a long time ago. I still hear people complain about how applets were slow and how Java sucks compared to Python, etc. Java can be slow, but Python and other interpreted languages are almost always slow. Why do we cut them so much slack? I’d prefer Java to avoid Pythons many foot guns AND slowness in most situations where my code is not a throwaway script.
Just a small nickpick.. The example you showed was BAD. C compared to Rust is like hmm.. You shooting yourself in the leg and blaming the gun. C being the gun in this case. C as a language, Doesn't do shit. If something is wrong, It's the programmers fault, Not the languages..
Thanks, I thought nobody else pointed how bad the example was.
You made me believe Rust isn't that much Rigid as I thought, thank you , I subscribed!
heh just kidding, subscribed way before, I love your content
the C code shown 10 seconds in was extremely badly written and is not an honest example of a subtle memory leak:
1, it technically leaks memory in all cases since the allocated memory is never freed
2, allocating memory on each iteration of the loop rubs salt in the wound, and is very slow
this is my attempt at writing the same program:
int main(int argc, char* argv[])
{
int l[512], t = 0;
for(int i = 0; i < argc; i++){
l[i] = strlen(argv[i]);
t += l[i] + 1;
}
char* s = malloc(t);
for(int i = 0; i < argc; i++){
strcpy(s, argv[i]);
s += l[i];
*s++ = ' ';
} *--s = 0; s -= t - 1;
printf("You entered: %s
", s);
free(s);
return 0;
}
notice how malloc is only called once, and the memory is freed when it is no longer in use.
by simply remembering every time you call malloc you must eventually call free you will literally never run into this issue, no need to learn rust.
Just don't make any errors, yeah thats perfectly sane
Rust basically forces you to have good memory practices.
we can double borrow as immutable &s
Go Go Golang, ineficient depends of what you need.
when rust programmers talk about C like static analyzers don't exist it fails to win me over at all
C has a lot of useful tools, the problem is they are not built in. While most people should be using extra tooling with C its not common.
That's why rust tooling is nice, most things are built and shipped with the compiler. Even better they are on by default.
C is a great language and so is C++. Give rust a try once you understand it you may just like it.
5:12 you can use immutable references as much times as you want as it just reads data, but not mutable references
Everyone hates java bc it's so hard to type. But literally it's less bug prone, is readable, and is great for dda. Imagine if you could directly access memory and have it gc like Go. It'd be the perfect C replacement
If you compare Rust to pure C or C++98 it looks great. But if you compare it to C++17 (used *properly*) I think it’s a far less convincing proposition.
Java isn't that bad and tbh modern java is SO MUCH better. I kinda feel like old java built up all this hate that modern java just can't shake even when the hate isn't really valid anymore. To be clear I understand that a GC/runtime is ALWAYS more bloated than a language without but I'm not sure java is a worse offender than any other modern GC language.
C++ std::unique_ptr
I am quite impressed by Rust's static checking though. You have to enable every warning possible on the C++ side of things plus use linters to get anywhere close
I will always love C, but I have tried rust for a bit and have come to like it too. The compiler for Rust won’t really ever let u write “bad” code. Especially with clippy. It warns u of every mistake and unideal code. It’s both great at helping u learn rust and also making u question the many years you’ve spent programming 😂
Easier way to not leak memory: Just have the OS free the entire app.
so restart the program every time you want to free memory?
You CAN borrow multiple times, but you cannot borrow multiple times *mutably*. Also you can't mix and match. You can borrow immutably multiple times, but unless all those borrows are done, you cannot borrow mutably afterwards.
That example in the beginning of the video is just plain wrong. It doesn't prove that C is inadequate, only humans are inadequate, or programmers should take their time and write their work carefully and not rush because of a deadline or the boss complaining.
The example may even crash since string_so_far isn't initialized to be null!!!
Also, I think everyone Will just use realloc for that kind of situations.
I’m bored coding applications, I want to do some embedded, should I overlook C because rust can entirely outcast it? Should I still master C anyways?
Rust is cool but C is still required knowledge for embedded developers. I just like being controversial ;)
Most system code generation tools or things like SCADE or Matlab SimuLink will generate C code to use, so at a minimum you need to be able interface with C code for a lot of embedded systems stuff
And from my experience, if you try embedded with rust, you will still need to understand C examples or C auto-generated code. But basic embedded C is not that hard.
Generally there's no memory leak should be happen in "C" if you call "free" function after every "malloc" in a proper way.
Another reason the garbage collector takes performance is as I have heard that every time the garbage collector goes in the program actually stops completley while the garbage collector frees the memory and there is no way for the programmer to override it and say "wait with GC until this is finished first". This is a possible issue in for example games. Lets say u are at a boss fight and ends up getting killed because the garbage collector goes in at just the wrong time just when u were about to land a critical hit and freezes up the game right then. It however dont seem to be an issues with game engines like Unity that uses C# wich is garbage collected but I remember someone doing a test that showed a clear FPS/performance drop when the garbage collector activated. I guess the only reason we dont really notice it still is because todays CPUs even on mobile devices are now so powerful that this performance drop during garbage collection is simply not enough to cause issues. On the other hand Unreal Engine wich uses C++ also dont need you to free memory manually but also have some form of garbage collection system for the C++ part. I have seen u can change its settings in the progect settings menu but never looked at it more then noticed that it is there. I dont know how UE handles the garbage collection compared to Unity and C# where the garbage collection is built into the language itself although I have no idea how Unity handles this under the hood and as I have not created any extremley heavy game in Unity enough for GC to be noticeable I have not been able to notice this myself either and all games made with Unity in general seems also to have no real performance /stutter issues, again the powerful CPUS of today I think might be what offsets this, its simply more then enough for the task even if some CPU cycles is wasted now and then from GC.
It's not just processors that are getting more efficient year after year. Memory freeing algorithms are also getting more efficient.
Also running the garbage collector in a separate thread or a separate goroutine eliminates the problem of program hangs.
The areas of manually managed memory languages are shrinking
Better title: this is how Rust is based
C is NOT an applications programming language. It’s an architecture independent macro assembly language with good library support. It’s great for systems programming and hard real time. For pretty much anything else, you could find a better tool to get the job done.
seems like memory leak is just programmers fault in your case
Yeah it always is nobody writes code that doesn’t have bugs rust just makes it harder to create certain bugs and helps prevent them
Really, who has problems with memory leaks in C/C++? That's like the Cobol people saying you shouldn't use C because you could accidentally format your hard drive in it. Rust's solution seems a bit heavy handed for a non problem. Or at least a problems from 20 year old compilers.
@Intuition Yes, Some of the worst code I've ever seen was from an engineering company that installed the automated conveyor system in the distribution warehouse. The hardware was excellent. Top notch. But the software...... Yikes. Took months just to stop it from crashing. Who in their right mind would use SQL for a temporary FIFO link list where timing is critical. Their solution, Hire someone to constantly move all the missed boxes from he end of the conveyor back to the start. Sheesh. But even with those yahoos I don't remember memory leaks being a problem. Course. with it crashing all the time it may not of came up as a problem.
Thank you
Another exercise in shilling Rust by making false statements against other languages. C does not leak memory. C itself places all variables on the stack or in statically loaded chunks depending on how the variable is qualified. Can code written in C can leak memory? Of course. We call this a "bug" and it happens when people start allocating their own memory and resources and forgetting to release them.
Here is the thing, C essentially "says" screw people that want to program in low level and are not as skilled/knowledgeable, then comes a language that makes it difficult for people to fuck it up while retaining similar performance/control.
I believe you can see why people like it.
I hope that all those "forbidden" things will be caught by the compiler, with a reasonably clear diagnostics.
They get caught immeadiatly on your IDE. If you don't have rust analyzer on the IDE the compiler messages are very helpfull and clear too. The whole point of Rust is in fact, making sure you catch these problems in compile time rather than beeing surprised by them during runtime.
00:10 "... this program will fail to free memory..." well, yeah, you didn't tell it to free the memory, duh.
Still do not see more benefits using Rust over C++ smart pointers.
Depends on what you do but proper threading is a big one.
C leaks memory because you make mistakes.
you see, no one is perfect and people sometimes make mistakes, so environments where these mistakes cannot be made have been created
You can double borrow but you can not have 2 mutable references to a variable.
Huh, nice and clear. Any protection for neophytes like me...creating recursive functions allocating memory in stack and hitting the heap? Don't ask me how I know! :-D
Rust guarantees that overflowing the stack will safely crash your program rather than causing UB. I believe C and C++ can make similar guarantees depending on what compiler flags you use. One of the common ways this can come up in Rust and C++, besides accidental infinite loops, is if you forget to override the default destructor for a Box-based (Rust) or unique_ptr-based (C++) linked list.
As someone who started writing an os in rust, i love that i found this channel
A robust OS made with rust where memory safety is at its core?
Sounds great actually
@@SandwichMitGurke im just learning os dev im hoping it will become sth good, since i know rust its a no brainer to use it, cuz it provides a lot of benefits vs c, if u are interested theres a comunity for rust os dev i can add u :)
@@echoptic775 best luck to you.
I don't have anything to do with OS development and don't really have interest in it either, sorry.
I'm learning Rust atm for game development / games in browser with wasm and embedded systems.
@@SandwichMitGurke thats cool i tried rust game dev in bevy but lost interest in it, myb ill pick it up again in the future. What engine are u using?
@@SandwichMitGurke Make YOU can write a game engine in rust!
Sounds like references, unique_ptr and shared_ptr from C++ combined
3:04
I thought since this language had all the Bells and whistles; it could monitor the use of variable/pointer.
Like take a page out of valgrinds book
i haven't wrote any project in rust. however the more I look at it the more it feels like what I wish c++ was. when I find time from uni I will definitely try to do a project in rust. it sounds like a really good language. if anyone wants to point me to possible applications as well that would be great.
I really love rustlang but I am getting no project ideas to use it with.
I want to code more in rustlang but there is always better ecosystem on some other language.
I went through the rustlang book but how do I take it to the next level now? I really like JS because you get this immediate feedback like with webapps.
The ecosystem is pretty decent. If you’re webdev as you state then you probably have no reason to ever use rust. It’s not for your usecase.
The textbook "Programming Rust" gives a list of different applications of Rust as examples of what is called "systems programming", which they define as "resource-constrainted" programming. Here's the list:
* Operating systems
* Device drivers of all kinds
* Filesystems
* Databases
* Code that runs in very cheap devices, or devices that must be extremely reliable
* Cryptography
* Media codecs (software for reading and writing audio, video, and image files)
* Media processing (for example, speech recognition or photo editing software)
* Memory management (for example, implementing a garbage collector)
* Text rendering (the conversion of text and fonts into pixels)
* Implementing higher-level programming languages (like JavaScript and Python)
* Networking
* Virtualization and software containers
* Scientific simulations
* Games
I've used Rust for the last 3 items on this list and can say it's quite well suited for them.
However, for making games, it's best for simple games, games on resource-constrained hardware (NES, GBA, etc.), or linked with a proper game engine (Godot, Unity). Otherwise, you'll be putting in a lot of effort to build from scratch what a game engine will give you for free -- particularly on the 3D graphics side.
Also, if you're interested in early game consoles, Rust is great for writing emulators. I've written a few simple emulators in C++ and in Rust, and the latter is just a better experience and product all around. It's a very fun and rewarding project, and at the end you can use to play actual games (or make your own using Rust)!
@@alxjones wow this is really helpful, I'll trying taking a look at the "programming rust" book. Can you please point me to the correct edition and authors for that book?
This is probably the best comment ever!! Thanks!!!
@@pinch-of-salt Programming Rust, 2nd Edition by Jim Blandy, Jason Orendorff, Leonora F. S. Tindall
It's about $30 USD for 1200 pages packed full of useful information. Good read front-to-back or skipping around, and a great reference to have on the shelf.
It's *not* a book about systems programming, though. That list of applications is in the introduction and is about as deep as it gets into any of those subjects. If you're looking for something like that, this is not it; it's just a really solid text on the Rust programming language.
I see, a solution without a problem. If a person is unable to correctly allocate and free memory, they should look for a different career. Memory management is a tiny challenge compared to the complexity of libraries that one must use in daily work, networking, multi-threading, etc. C is a great language, it will outlive Rust, Go, Java, etc. C can be used to manipulate registers on a CPU, and also to do symbolic math. It also scales well, even for huge projects.
Everyone makes mistakes. After all, to err is only human, and assuming we're all human here, that means every single one of us is fallible and very much capable of making a mistake. No matter how small the actual chance of making that mistake, literally everyone makes mistakes from time to time. And, assuming you're a human being of course, that includes you, me and anyone else currently reading this comment. Given that fact, I see incredible value in a solution that, quite literally, makes it impossible to screw up your applications' memory management, unless you're purposefully circumventing the safeguards by surrounding your code with the unsafe keyword, of course.
@@TheBauwssss Wise words. It's just not helpful to say "oh I am so experienced that my code can't have bugs and logical errors". And one thing that isn't considered in this type of arguments is, that experience just comes from ... guess what, experience. It's totally normal that someone new from college or university does mistakes that experienced programmers don't. But if only the experienced programmers code, the new ones can't get experience because they never learned from practical work.
An expert programmer can avoid memory leaks and UB in a small-to-medium codebase, but at this point it's an established fact that *teams* of expert programmers working in large codebases cannot avoid these bugs. Expert programmers develop memory discipline over time, but not everyone's memory discipline is the same, and components of large programs have a tendency to miscommunicate about who owns what in untested edge cases.
If you think you can avoid memory leaks just by "gitting gud" you didn't work on a project serious enough.
@@TheBauwssss Lol imagine being a human
*cringe*
Java probably has the most efficient garbage collector at this point. Would love for you to cite your source or reasoning why Java should be poster child for inefficient GC.
Even loving Rust, hearing "inefficient" and a image of Java doesn't make sense. I could say I shared this view years ago, but after seeing what people can do with Java, nah that shit is efficient as fuck.
This strategy can be enhance with ide tools i guess otherwise it is not of much help in envs where you have some extra kilobytes and some Hertz to play around a GC still rocks
what should i do instead of double borrowing at the end>?
the concept of "ownership and borrowing" is just an abstraction of rust's garbage collection (just like c/c++ memory management in just a safer way maybe) or am I wrong and is it only me?
here is how I see it
c/c++ garbage collection is manual (blazingly fast but leads to memory leaks)
go/java/c# garbage collection is automatic (fast, safe and leads to dev's productivity)
rust garbage collection like c/c++, manual but is a must (blazingly fast and safe)
So basically we have to create a programming language to hold the hands of the programmer.
Yes, because programmers are human and make mistakes all the time.
It's pretty obvious the first snippet always leaks memory because you forgot to free the memory. Don't know what you're talking about.
I like Rust!
Can someone explain the "edge cases" he talks about right at the beginning (0:12?) it seems like this code should _almost always_ leak memory, since it never frees anything. I might be misunderstanding something though.
c# am I joke for you?
...Rust explicitly, by developer intent, does not prevent memory leaks.
Ok but what if I want two variables from an existing one? Something like this?
let start="Hello, ";
let h1=start+"Timmy!";
let h2=start+"Sarah!";
You can do that in multiple ways. If you are allocating a new string it just copys, but if you want non allocation it would hold an immutable reference.
The benefit to the non allocation part in rust is that the original string cannot be changed from underneath you, it also cannot cause a lifetime issue.
So yes this is possible.
you can't add static strings in rust
2:52 Ok but why can't you drop both? You said it could lead it the program crashing but why?
This is interesting but I'm wondering how you handle complicated scenarios.
Basically the same way. The rules don't change with larger programs. You use lifetimes within function scopes and structures.
If you know lifetimes, borrow rules, and ownership, it doesn't get much more complicated.
There are a variety of types for expressing different ownership scenarios. Box for unique ownership of a heap allocation, Vec for owned dynamic arrays, Rc for ref-counted pointers (thread unsafe, but this is compiler-checked so you can safely use it around threads anyway) and Arc for the thread-safe version, RefCell for thread-unsafe interior mutability (dynamically checked safe mutable access from re-entrant code), and Mutex for the thread-safe version. The real power of having the compiler have your back in all these cases is that even if you have a huge and complicated system combining all these things you can have peace of mind that they won't conspire to create a nasty data race or double-free bug. C++ does not give you that, even if it gives you all the same ownership semantics types. C just uses T* for everything and leaves it to the programmer to be "disciplined" even past the one-brain barrier.