Ok so I need to: 1. Write it in C 2. Rewrite it in Rust 3. Rewrite it in unsafe Rust 4. Rewrite it in Zig 5. Take ketamine 6. Rewrite it in C++ ? 7. Enjoy
@@baxiry. nope, it does not. Macros are much more than just some compile time computation. Macros are for implementing embedded DSLs, i.e., macro is a compiler that runs in compile-time, and does all the things a standalone compiler can do, including arbitrary optimisation.
I really don't know nearly enough about the subject to say anything usefull, but my impression of unsafe rust is that it is designed so you can dip in it to solve a specific problem, then wrap it in a safe api so you can use that with regular rust. If you're writing the whole thing in unsafe mode then you might as well use another language.
Yeah. That's kinda the point of the article. Zig is better than Unsafe Rust for apps that would previously be written in something like C for precise memory management and freedom of control
@@sebastiangudino9377 but the point of Rust is that you *can* do that precise memory management and freedom of control, but safely. When you're messing with low level stuff that is not safe, use unsafe, when you're not don't. If your program is even slightly sane, it's not going to be mostly low level memory management, and the safety guarantees outside that code are extremely useful.
@@SimonBuchanNz I see your point, but have you ever actually used unsafe rust? Seems like you know about it, but you don't know how it is really like. Unsafe is for very small self contained blocks of code that you are using inside a bigger generally memory safe project. It's pretty different from the more management you do in C or in Zig, where there is no borrow checker to fight with. So yeah, your point IS valid. But seems to come from lack of experience with either memory management in general (Outside of rust) or with unsafe rust in particular. Using unsafe rust for a big project might be a good indicator for why things like Zig even exist
@@sebastiangudino9377 Err, yes? A lot of FFI, including code dealing with complex threading behavior, a memory allocator (a buddy allocator) and some manual atomics threading code. It's mostly going down the safety requirement checklist of everything you're using to make sure they're met, which often turns out to be a lot more than you expected, but not exactly tough most of the time. The fact that types have alignment, you can't read unitialized bytes, etc, are all pretty intuitive and often directly follow from hardware, so they're also required by every other language, you just don't get the warning labels. Not breaking the rules of references can be occasionally difficult, for example when you need the offset of a field, but there's always a decent answer. And MIRI is there to catch you if you mess up, unlike C or C++, where the likelihood that you *ever* get any slightly complicated bit of code completely UB free is a joke. So I have to ask, have you written *correct* C dealing with such "precise memory management and freedom of control" before? Because if you think unsafe Rust is at all difficult in comparison, then I'm going to completely disbelieve you and anything you say. Every moment of C is like unsafe Rust but without any decent documentation for avoiding broken code and all the wrong defaults constantly guiding you to creating broken code.
That's an incredibly well written article. The author was trying as much as possible to be objective and present things as they are an not just trying to sell you on his own opinions :)
I learnt python and typescript and was going for rust. I saw zig and thought "yeah i'll go with zig". Now i started learning assembly. I have no idea what I'm doing...
Zig doesn't need to re-establish all of the history of C in order to replace C. It made sure to have more than just the typical basic C interop so that this could be true. It integrates with existing C infrastructure without compromise, so the transition from C to Zig is painless imo. You can literally have an ongoing legacy C project and just start writing parts of it in Zig instead, just switching to use Zig as your compiler.
"then you have to fulfill all those decades of libraries" that's the neat part, you don't! zig has excellent inteop with C code and it's super easy to use & run C code from your zig program, i've done it before with creating PNG files and found it very easy despite having very little C experience. at most you might want to write a wrapper for the endpoints so you're not exposing C types in your zig code, but that's all you really need to do
Yeah, to me it almost feels like zig is the kotlin of the java world, in the way it works nicely together with C (and kotlin working nicely with java). Which made many java projects, including android, switch to kotlin; part by part. The zig compiler can also target different glibc versions and with nice cross compilation I can easily see why C devs would lean to zig even if they only want to start with compiling C code.
@@lesto12321 sure, but a big selling point of zig is that it's extremely low friction. Most languages have ffi nowadays but zig aims to be very easy to integrate into C codebases
The space that zig fills for me is a better C, in every way. Better error handling (goodbye goto and initialized checks), no null pointers, stricter type checking, comptime (both for generics and for metaprogramming), being able to include C headers and zig also generates C headers when you use export so you can use your zig code from C without writing bindings. Being able to compile c and c++ code and switch out part by part is why it's easier to replace C with zig than other languages, along with that automatic binding. This is what kotlin did, and kotlin has replaced java in a lot of projects (including android). But most importantly for me, is that zig produces binaries that are even smaller than C binaries. Hello world in rust is 5mb (static) while zig is 2kb (static). At my previous job a 5mb increase in disk space / memory usage was classified as a bug and had to be fixed before release. It's also especially important for a unix-like environment where you want to have many small binaries, that can easily fit in cache (true also for "serverless") and slow devices like my pinephone. A 2000 times increase in binary size is unacceptable for me, no matter how good the language or the environment is. And zig is really the only modern language that is willing to focus on the whole build environment and make it better than everything else (cross compilation, even for c and c++, with just one argument, pure machine code backend, etc. Also has C backend to be able to run the code everywhere).
Interested perspective about the binary size, never thought about it in this way. This could even improve performance, especially with the 3D cache we are seeing with AMD.
Hello world is 5mb and 2kb? Classic shitposting. On a serious note, Rust does have a compile time problem, the size problem is *largely just a side effect of the compiler making trade-offs to compensate. Let’s not get it twisted, you still need to muck about with compiler flags in both for constrained environments. Zig is definitely a good way to write C though, I personally love it. *if you are comparing languages and not std size
While still significantly higher than your zig equivalent, you can easily reduce the static rust binary from 4.3 mb down to 276 kb using a few flags (namely strip). I wouldn't be surprised if you could optimize that even further but my Rust knowledge is very limited.
The reason why Rust doesn't have ++ is because in Rust assignments are not expressions. In C `x++` is equivalent to `x+=1` because both not only increment x but also evaluate to `x+1`. In Rust `x+=1` evaluates to nothing, it's only a statement. So if you wanted to introcude ++ into Rust you have to make a choice whether you want it to work like in C and be inconsistent with +=1 or simply be an alias for +=1 and be inconsistent with expectations. The Rust team decided either was bad and didn't add it at all.
expectations that x++ is an expression? Are people expecting that x += 1 is an expression too? And if yes, isn't it the same problem? I don't really get why not add some syntactic sugar, and some Increment trait, it really wouldn't be such a tragedy
"Why would use too much unsafe Rust?" Well it is common if you are working in something like OpenGL, XLib, and other things. Using these in Rust is quite annoying some times.
I actually find it quite fun to wrap FFI in safe Rust apis. The main problem is that you often find out that nobody thought about documenting whether you can use handles across threads etc.
I'm not sure about interfacing with C libraries, but from what I'm aware, a _kernel_ generally uses less unsafe than this, and it's pretty hard to get any lower level than an OS kernel.
@@nilspin OpenGL in particular is a back box of a global state machine (which rust rightfuly hates) and is implemented in C. And because Rust considers any C code inherently unsafe, you will have to wrap almost every function call in unsafe blocks because you'll constantly pass around raw pointers.
Technically the post and pre (inc|dec)rement unary operators are holdovers from C back when C compilers were architecture specific, in this unary operator's case back when they were invented the C compilers were targeting the pdp11. The pdp11 has specific post and pre increment machine operation that these unary operators would directly map to.
Actually, this seems to be a myth. At least I read that recently in some article on the evolution of C. Let me know if you need me to find it again, I apologise for not providing the reference right away (I am on my phone), but I think it should be easy to google.
Zig is C but without null pointers, has out of bounds checking, no preprocesser, no make files. Zig is what c should’ve been. It can even translate C code to zig. But we all know C developers are masochists and a tad too arrogant to leave their beloved language behind.
To be honest i have yet to read of any so called arrogant c programmers fully bashing zig. There seems to be, as far as i can tell, a general openness to it and like of it. Similar to Odin. Especially because the interop means they can add at their own convenience. If you know any that hate zig let me know, the number one complaint so far has been lack of 1.0. Not lack of enjoyment with the language.
9:25 The reason you get UB with the double mutable references is because the compiler can assume there exists only one alias. This means that an optimizing compiler can elide some reads from memory after calling a function. But if that function mutated the aliased memory, you now have a stale representation in the caller.
My impression is: If you are writting a lot of unsafe Rust as your product... maybe do not use Rust? Some packages in Rust are filled with unsafe code, but because they dealt with very specific operations that are carefully monitored and checked, so that by using the package you do not have to write the unsafe code yourself. But if your whole point of your program is to write unsafe Rust, why? Just why? Rust is designed for a type of problems, in which memory safety is paramount, and it requires to rethink your problems for the new paradigm. If you cannot rethink your problem in a way that leads you to use less unsafe Rust, then why not use C anyway? "But I want to do it in this way!" well then use other more suited language, no? I think that the problem is that the article is "Why a scewdriver is better than a hammer in some situations: My experience fixing a PC" and my conclusion after the article is "yeah, no shit, Sherlock". It felt like reading the constant struggle of a man trying to fix a window glass with twizers and a blow torch: In theory one could make that work, but why wouldn't you user glass glue instead?
I do agree that if you're finding yourself writing a lot of `unsafe` rust it's probably not the best language for the job. As much as I and seemingly everyone else loves rust, it isn't a good fit for every application.
I think the creator of zig said it pretty well in an interview before. Basically, while Rust has better safety in an ideal world, using unsafe code is basically just putting up signs saying "there be dragons" as prevention. Meanwhile zig has a more consistent level of safety, however it's not quite able to reach the heights of rusts borrow checker
This is not strictly true lol, even in insecure mode Rust's borrow-checker still exists, and there are parts of the code where naturally insecure patterns will arise when we are dealing with layers closer to the hardware, it has nothing to do with how consistently secure a language is, but how generally secure it is.
The idea of rust too is that you're spending as much time as possible in that safe ideal world, and the unsafe blocks are few and far between. So you do your unsafe thing, get out of unsafe and return something safe for your code to use, wrapping it in an appropriate Option or Result type if the unsafe operation might fail. If you find yourself using unsafe a lot, you probably want to rethink what you're doing, because there's likely a better way. Usually I'd guess it comes about as a result of trying to replicate a design pattern from another language that just doesn't work well in Rust. And if you do that sorta thing, you're basically trying to force the circular piece into the square hole. Honestly I think one of the biggest flaws with how Rust is presented is the whole "rewrite it in rust" meme, simply because Rust unlike a lot of other languages, just isn't designed as the sort of thing that you can just take your favorite lines of code and do a 1 for 1 conversion. Unless you absolutely have zero choice, try to do things the Rust way. If you try to keep coding like you're writing C or C++, you're probably going to have a bad day.
@@taragnor Hmmm, I think the last part is wrong, because we say "rewrite in Rust", and not "copy-and-paste in Rust", so it is expected that you would have some work redoing some things in the language instead just redoing the same thing.
@@diadetediotedio6918 It really is up for interpretation, and sadly people just see the meme as a promotion of Rust's benefits but don't think about where said benefits come from or what rewriting Rust actually should entail, and then when they give in to give it a try they try to write in a way they're used to, get frustrated with the inevitable trouble that entails, and get disappointed away from the language and its community.
Regarding the ++ debate, I personally agree that rust's iterators, ranges etc. eliminate 90% of its regular uses and when it's just on a single line, having += makes it easier to see that that variable is being changed. Like seeing the plus immediately makes it easier to grok what that line is doing. So for me it's about readability and if I'm incrementing something even in typescript I still use += quite often, leaving ++ only for loops.
After writing unsafe Rust for some low-level data structures and algorithms, I can confirm that it can be really annoying for certain use cases. Miri is a huge help, but it's annoying that you need a separate tool just to look for your leaked pointers, undefined behaviour, etc. Zig does a much better job of handling these use cases. That being said, I still would generally prefer Rust because the rest of the ecosystem is so much stronger. Iterators, functional programming, etc is just so much nicer in Rust, and I love still having those features, and for me personally, I feel it's worth dealing with the increased overhead of undefined behaviour. Rust definitely is harder to use and make safe (when writing unsafe Rust) then C/C++/Zig though, which is annoying at times. If you have to interface with a lot of C libraries, I can really see why someone would prefer using Zig.
Hey Prime! I really love your content and thanks for teaching me NeoVim. I just added 3 keymaps and felt like I started a road that is making me a better, more efficient programmer, while having fun! Thanks! :)
My experience with unsafe rust has been more or less mundanely fine. One of the libraries I worked on was for a secret storage system, and we build a non-contiguous memory guard system into it. Of course this required a ton of unsafe rust. The Key/Value store in the system also required some unsafe rust for encoding and decoding the memory into various encryption schemes. There were points where we hit undefined behaviors but that's to be expected. The general rule of thumb that I learned is to add asserts into the code blocks so that if undefined behavior happens, it will trigger an error message thats actually useful. My experience with Zig has also been pretty mundane. I could see it being used for various small things but I am not sure about how useful it would be for a large project.
Yea this pretty much sold it for me. After suffering setting up gradle for kotlin in VS code, i feel pure dopamine just reading the words "better build system". Zig is next on list.
I've never had to write unsafe rust, but my understanding is that unsafe doesn't mean: now we have C lang, but rather, I'm doing something that is not provably safe by the compiler. Unsafe is really an unfortunate name/keyword as I think it lends to the idea that sometimes it's ok to "not be safe", when we really mean "less strict validation".
There are people who believe the name "unsafe" was a poor choice and the keyword should have actually been "safe". Because Rust unsafe blocks are really a promise to the compiler that you _know_ what you are doing is ok even though the compiler cannot prove it.
Even though I love Rust, the unsafe barrier has been the reason I struggle to use it on my day to day work, we work on embedded, low-latency realtime embedded, default rust implementation was pretty good just we knew we could do better, to squeeze those extra instructions per cycle we had to rewrite everything in unsafe blocks, it was sooo hard, ended up rewriting on C++
@@ratgr Sounds interesting. Any insights why Zig wasn't considered/chosen? Was the language - being 0.xx - to immature for professional use? Or was C++ just a skill available in the team that it was a pure time-decision to default back to that?
@@micha-ix1iy We had a good amount of code on C++ anyways, it was just a language that most of the team is good at, we do have a couple of large project on Rust now, but we stopped Rust on all our embedded development and went back to C++. I still think Zig is too inmature, and we have to figure out how to make it work with owr chips, and learn it too, maybe next year. Now with rust as a quasi-failure don't think it will be easy to try another language soon
Most of the comparisons between a language like Rust or Zig and C/C++, are using extremely old versions of the C/C++ standards. C++ now has smart pointers, or pointers that can clean up after themselves, string and vector classes can handle a lot of the buffer overruns. C just requires that the code be careful, and that may mean writing most of an application in Python, and then just the stuff that needs higher performance, gets written in C. Just like back in the 1980's we wrote most stuff in BASIC, and the higher performance bits in Assembler. A lot of programs started by stuffing the assembler bit in high memory, then using the SYS function to call it when needed.
smart pointers don't make c++ any less terrible to write in (imo). safer, yeah, but let's be honest at this point c++ is just the javascript of the compiled world. years upon years of weird features stacked on top of each other... just that in c++ if you don't do things the hygenic modern way you get buffer overflows and memory leaks instead of accidental type coercion errors and callback hell. the only reason either of them are still used is because they're already established standards.
@@lunafoxfire The critical problem with most languages is they try to be everything for everyone. Back when I started you wrote nearly everything in BASIC and then stuff that was too slow or ugly to write in BASIC was written in Assembler. When I was in college we learned, COBOL, FORTRAN, BASIC, Pascal and assembler. Today they want A language to do everything. Personally I would rather use Python with the stuff that is too slow or ugly to write in Python, in C. What often makes C++ goofy is the fact it needs to be mostly compatible with K&R C, even though that hasn't been the C standard for over 30 years.
@@lunafoxfire That's why you ignore all the ideologues that tell you you need to use STL algorithms and containers literally everywhere. Who cares if they seethe if you "write C in C++" but only use the features you want?
So, Zig is literally a c/c++ and zig compiler/build system all-in-one. It interfaces with C and can export easily to C ap just like every other programming language. It is a c++ replacement, however, not a C replacement, and it is literally paring down most of the language to the essentials. This is different from Rust that is trying to match features and replacements, Zig is looking at the most useful form that works across the most use cases, and just makes that the canonical form in the language. This is much closer to the C philosophy where the go was to have a versatile but small language that can be used everywhere. Zig is trying to do the same thing for C++ and all the rest of the various languages at the same level of abstraction.
On another TH-cam channel a task was given to people who wrote in different computer languages including assembler language. I believe it was 105 different languages finding a long list of prime numbers. It wasn't about safer code - but the fastest running code. Zig took 1st place and Rust took 2nd place, and Zig was twice as fast as Rust. The focus is on writing clean code easily that runs faster than any other computer language. The language is still in development but the initial results are startling. There is a team of people trying to see about optimizing C code - but include the best C libraries that run on linux, windows, and mac - so that the language can be run on any operating system. I think C programmers might like learning Zig because of that.
The C interoperability is a big one for me. Both Rust and Zig have their advantages and disadvantages, but for a lot of teams there are simply fewer obstacles for Zig adoption.
Hey mister. I don't play around with pointers... You better remember that. When Stroustrup said "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off", he should now add "Rust doesn't permit you weapons at all and even if you try to get an illegal weapon, it makes it as difficult as it can". No methods or nice pointer dereferences for bad boys.
As soon as you hit undefined behaviour, the compiler will go "oh no, you didn't" and optimize the surrounding code as if you hadn't written what you wrote. And frequently undefined behaviour propagates, basically deleting any operation that interacts with your "undefined behavour result", and without those results the optimizer will optimize based on their non-existance, and so in the end the compiler ends up just writing something arbitrary instead.
For the topic of var++ If var++ is an expression and returns a value like in C, then foo(var++, var++) could be undefined. Even if it was a defined, this will be much harder to read IMO. And if it's a statement, I'm good with += 1.
This was really interesting! I like both Rust and Zig but have only done a small amount of toy code in each, and no unsafe Rust at all. Would be interesting to see you try something that needs unsafe Rust and see how you go.
I know the title is click bait but both of these languages are great new choices for different applications. I feel like un-safe rust is pointless though and zig or just c would be better if you can't afford the borrowing overhead. Also I feel like Zig is a true replacement for C where as Rust is more a true replacement of C++, Java, and C#. Still the results are really interesting and Zig will be more on my radar in the future.
I spent two months writing many core codes using zig and rust. It is my humble and honest experience, zig is not mature, but has so much to offer. Concurrency is not what Rust promises, either we should use unsafe code or use rwlock, and many extra code to manage the life span of variables. It takes so much time to jump through the hoops. Zig is fast and does enough checking to avoid memory leaks
12:38 The problem with "++" is that, as soon as you allow "some"-fix increment, people will ask for the other one (prefix / postfix). Then, the language will have to deal with whatever `++i++` should mean, and that goes down a rabbit hole. The decision about the semantics of that will influence some other areas of the language semantics, just like it did for C++.
I've implemented the VM that this post talks about in rust multiple times and in zig once. The zig implementation wes by far the easier of the two. Even with knowing where the annoying bits are you end up with either a bunch of custom wrapper types to help abstract away all the annoyingness of the unsafe pointers or you just end up with a bunch of annoying unsafe pointers. Either way, it's not very ergonomic and fun
Yes, even in C and C++ the compiler can introduce bugs by assuming that there's no undefined behavior and optimizing it out. If you relied on UB, then the compiler may very well transform your code into something dangerous. For this reason I like to compile and test with -O3 (instead of -Og for example) because O3 is much more likely to flush out any UB in your program.
-O3 can sometimes hide bugs for the same reason. For example if you read from a null pointer, but don't use the result for anything. Compiler will remove it and program will behave well. On -O0 it will 100% segfault.
@@araarathisyomama787 that's a good point. testing with O3 and Og seems to work best although that sounds like something the compiler would warn you about (reading from pointer and discarding the result)
The benefit of Zig is that, it provides safe semantics so I am able to write both. But let’s be honest here, the unsafe is still unsafe however much you sugar coat it. Sure there are abilities to make you code safe in Zig. But it is never about the ability to do things right, but instead the ability to do wrong that has landed us into hell with C++. My problem with Zig is that, it provides these dangerous abilities on a silver plate to the users.
This article doesn't justify why they need to write unsafe rust at all. Without that, rust isn't getting a fair shake here. The problem is that 90% of the time, people who write unsafe rust actually don't realize that the borrow checking model means you have to write code differently. Idioms you are used to are illegal in safe rust for good reason and there are usually low cost alternatives - though I'll admit here that my actual experience with the language is limited. All that I'm left to wonder from this article is whether this person doesn't know how to write memory type safe code.
I have read this article before; but I still appreciate ThePrimeagen reading for me again since I sometimes don't pickup all the little things. Thank you :)
I've been trying to keep myself excited to continue learn code. This channel has been good motivation, breaking up the boring documentation searching. I always learn something, even if it's just something niche about a language I'll probably never pick up.
I feel like people always confuse unsafe with wrong, yes it should be avoided, no not at the cost of more complicated/less performant code. Using unsafe as just another tool to write more understandable code would be a better approach than saying unsafe rust as a whole is wrong.
C has been my my language for about 10 years and I see rust as the proper C replacement. With no_std, a standard build system and package manager, awesome macros and the lack of/alternative to OOP it's basically all I ever wanted. Zig sure is a weird in-between thing and I can't wait to see where it'll be in 10 years.
I don't see how Rust can be replacement for C. For some big C++ projects - maybe. But not for C. Rust just carries too much overhead that is unacceptable in the context where C is used. And Rust's safety model is not even useful in most cases where C is used.
@@sk-sm9sh which overhead exactly? you can decide for yourself which features and/or crates you use and thus have very good control over binary size and runtime performance. For example, if you wanna parse CLI args you don't have to use clap, you can also use argh. You also have tons of options regarding code size vs performance: generics vs dyn, std vs no_std, ... In every place where I use C, Rust would be very useful. I write firmwares for both MCUs and low-spec Linux systems and C is both very verbose and error-prone. With rust being a general/multi purpose language it surprisingly fits both of these usecases very well. Admittedly, no_std isn't quite there yet due to crate/driver availability.
@@sk-sm9sh I can also provide an argument from the other side: I think that Rust is closer to C than it is to C++ in terms of it's language design choices. And I get the impression that many C++ devs wouldn't wanna use Rust instead of C++ anyway - either because they don't like the concepts and they don't fit their way of thinking or because they simply don't like the syntax.
@@sk-sm9sh sry for spamming but I just had another thought about `And Rust's safety model is not even useful in most cases where C is used.`: A huge portion of C software actually lives in Linux userspace. Most CLI commands are written in C and Rust tools like fd and rg have started to replace them. Also tons of services like bluez or systemd are written in C as well. And in those code bases you can see a lot of boilerplate to work around missing C features like automatic destructor calling.
@@MichaelZimmermann why don't you want to give zig a try? It's an easy drop in for any C project. With Rust is it really producing same size binaries as C? In unix cli tools environment small binary size kind of matters as it's used in so many diverse environments.
Nobody can tell you what the undefined behaviour is. By definition, it is undefined. It may depend on the OS, the CPU architecture, be changed from compiler version to compiler version, be dependent on heap/stack layout, whether building in debug or release mode, etc. etc.
In virtually any real-world scenario, unsafe code in Rust will be restricted to strictly extremely low-level matters like communicating with the hardware or doing some operations that would be impossible in everyday language. We can quote here on the issue of the benefits of the approach of creating security wrappers in Rust to interact with unsafe code Asahi Lina herself, who has already said quite clearly how much the borrow-checker (which by the way exists in unsafe scopes also in some level) and the compiler in general made her experience of developing the M1 GPU driver much less complicated and more pleasant than it would have been without these features on other languages. So, IMHO, if you're using this much unsafe code like this you've probably already started off on the wrong foot in what your code should be.
@@qx-jd9mh Per the Curry-Howard correspondence type/borrow checking is theorem-proving. Type systems give theorem-proving great ergonomics by integrating it directly into the language. It's much more difficult to maintain separate proofs about code written in a different language than the proof language. That is a real advantage of Rust. I think the Rust community should instead focus on improving the type system to make it more expressive and easy to work with. A good first step would be to bring it up to parity with Haskell, but the end goal would be a full-blown dependent type system extended with linear types, capabilities and regions (which would subsume borrow-checking). This would eliminate the unsafe subset of the language entirely and enable whole-program verification even in the presence of manual memory management.
@@kieranblazier4058 Nothing like being restricted to ineffective theorem proving techniques... ATS doesn't cut corners when it comes to compile time guarantees. ATS is hard but so is high performance systems programming. You cannot pretend that everyone is qualified to write code that runs as fast as possible and is safe. It's weird because you don't usually see people complaining about the high barrier to entry to become a surgeon, yet you are people whine about the difficulty of ATS.
The ++ is probably related to how it's technically a returned value and maybe something to do with rust mutability. Like you can do arr[i++]; but you can't do arr[i+=1]; for example in other langs.
I think a good example of good usage of unsafe rust is PyO3 project which provides bindings between python and rust. In benchmarks it consistently produces code that is just as fast as cpython's implementations of the same algorithms. And while it does naturally use unsafe wrappers at the API boundary, it exposes a perfectly safe API for production use. Given all this, one can draw 2 conclusions: 1. Unsafe is not for use all over your code. It is for making 2-3 line wrappers around the sketchy bits of your code. 2. Writing performant code in rust is just as feasible as in any other language, given that you understand what the compiler expects you to write. Every time you put an unsafe block in your code you clobber the optimizer, which is not great for perf. Zig compiler can, potentially, reason better about raw pointers than rustc can, which is where much of your performance gap could be.
@@32zim32 I'm pretty sure there is no way to achieve "no bugs" state in practice. But given its wide adoption across tens of projects, it is likely far safer than anything you'd make by hand for a particular project.
The undefined behaviour of having multiple references when one or more of them are mutable is that the compiler assumes it doesn't happen. It will optimise the code assuming it follows the rules and that will likely break something. The problem with UB is maybe nothing happens, maybe it crashes the app, maybe it causes results to be just slightly wrong and isn't noticed for a long time.
26:00, I don't even remember when I had some serious issue, regarding to pointer indexing in C++. I wrote a class that inherits a container, and checks the index. I can turn that on/off anytime, for the entire project, by changing just 1 line! It's also hard to get a trouble about pointer dereferencing, because everything is 'begin() + K, end() - N', valid range of containers. There's no space here for pointer issue. And when I send a nullable pointer to a f(), it uses to be null by default, which means I want to give the user the choice of sending it or not. In this context, it's obvious that I'll check the pointer soon. If it's a 'const char *' (for a string literal), and I want to earn some performance by not checking it, I set its default to "". So I don't have issues with pointer at all! 28:39, he meant that failing on those checks forced him to give up on pointers. These are much faster, because indexing always come all the way from the beginning. And failing to UB is not an option.
I can't believe so many people are opposed to the ++ operator. I don't really feel strongly enough about it to complain, but I prefer ++ for some reason, just looks neater to my special eyes. Assuming that people are voting based on UX preference and not technical reasons that might negatively effect rust or performance. Though I really don't see how it would be possible that adding such a thing to a compiled language could negatively impact performance. That said, I do kind of dislike having multiple different syntaxes(?) to do the exact same thing, that are different enough to throw you for a loop the first time you see it. Especially if one of them ends up being totally superior to the other. But ++ feels like its almost embedded in the programming zeitgeist now that I don't think it applies there.
Tooling, UB and syntax... Yes if you want to do unsafe it currently makes it so that you "better just spread around that unsafe" or face possible UB if you want to provide a better api with references for the called instead of pointers. On the contrary for this kind of nasty work there are tools and UBs are also more researched in some langauge like c/c++ while likely zig avoids most of these issues. This is very good take. I feel the issue is that its hard to do this "marshalling" kind of work. I mean marshalling between native and managed is also usually very big pain in the ass - I don't know if you ever tried, but basically the safest for those cases is to do the simplest - dumbest, c-like thing with handles as integers and try avoiding this marshalling. I think I would follow the same strategy for unsafe rust + rust boundary as this strategy of mine for managed / native boundaries. It would be totally not idiomatic, but likely work better than whatever I see here.
People in the stream comments saying things like "The reason I write rust is to avoid unsafe" and "The author of the article missed the point of rust" are the ones that missed the point of Rust. The point isn't to always write safe code. It's to create safe abstractions over unsafe operations and then use those generally instead of the unsafe all the time. That's why the std lib is full of unsafe.
But that is the point: All that unsafe code in the std lib is there so that you do not have to do it. If your normal, not-base-of-ecosystem script is full of unsafe Rust, then you are doing it wrong. It seems to me that the unsafe-dense packages are the "we put a lot of work into this, so that you do not have to do it" packages. If you are writting one of those, then why are you complaining that Rust is hard? You are literally going against the normal tenants of the language, of course it is hard. If you are not doing it to create a layer of abstraction to easy the rest of your work, but instead that is your whole work, then use another language!
@@JackDespero The point is Rust is harder than it has to be. Not because of the rules, but because of the ergonomics. For example raw pointers have terrible ergonomics which pushes you towards converting them to references which means you bump into borrow checker rules. Raw pointers have pointer arithmetic methods, but not operators. This is fine, but it makes your code more verbose. Or when you're working with threads, pointers dont impl Send or Sync even though there is nothing technically wrong with that. So you may convert to int, pass, convert back, but that has pointer provenance issues. Or you have to wrap them in a new type and unsafe impl Send and Sync which works fine, but is a bunch of boiler plate. Or another thing. UnsafeCell doesn't impl Copy which means you can't have a Copy type with interior mutability. You "can" do &a as *const _ as *mut _ to work around it, but that is UB so won't actually work. These are the sorts of things that make people say unsafe Rust is hard. Also, there are lots of reasons to use unsafe outside of foundation layer crates. You almost always know things about your program that the compiler doesn't. For example you might push something to a Vec, next line you do unsafe { .last().unwrap_unchecked() } because you know there is something there. A lot of the time you can rely on compiler optimisations to do these things, but that only works in a release build. This is why you see posts on Reddit all the time saying that Python, JS, etc are faster than Rust in debug. Unsafe is part of the language. A part to use carefully, not something to avoid. You shouldn't be scared of it. You should strive to understand it because it's an incredibly useful and powerful tool.
"Carbon will be the true successor of C++". That's a bold prediction right there. My (equally bold) prediction is that Carbon will be the Google+ of programming languages.
Lol, I think cppfront has a better shot since it's modeling the C -> C++ and JS -> TS route. Being able to just start writing cpp2 anywhere in your cpp project is amazing for getting people to adopt your language.
lmao you know i think this every time and the debate rages like this "i bet its going to suck, Carbon is such a *lame* name, wait but they DID make GO.. Yea and G+" Only way to know is to wait and find out! Also gives me a chuckle, every government is trying to reduce carbon footprint even before its out!
i can see ++ being a issue with the fact that everything is a expression in rust, i mean in C it is the the equivalent of doing a var = var + 1; in a line under the actual line. not on it so you will end with ambigious va2 = var1++ type of issues issues every time you use it in a expression
"tooling and syntax make unsafe rust hard to understand" I think the problem is a bit deeper. The compiler assuming that borrow checker rules are being followed possibly causes some values to be overwritten without any context to why, debugging this type of problem is probably a HUGE pain. (if this doesnt happen, then someone please correct me, I haven't actually messed with unsafe rust yet)
The compiler ensure some of the borrow-checker rules in unsafe Rust too, just not all of them or too strictly. Also, the syntax and tooling are great IMHO.
Every time i see someone gripe about the rust mutable/immutable reference rules, I can't help but substitute Austin Powers saying "I too like to live dangerously". I mean the rust team didn't institute the many readers or one writer rule for clickbait... there's an actual reason for it and if you want to violate it (and you can) you had better REALLY know what you're doing and anyone saying "This is really easy to violate" doesn't fill me with confidence that they've done their due diligence. In the end I feel like is sort of missing the point of safety in rust. Alternatively, i'm just reading too much into it and i'm the asshole. Regarding "I should play with some unsafe rust": there's a rust tutorial called "Learning rust the dangerous way" which (imo) is a really excellent read and it starts with converting a c package into unsafe rust and then converting it over to safe rust with some fairly small changes. Highly recommend.
@DanteNotAvailable you are right. Only those who know something about electronics understand that once the state has changed in electronic circuits you cannot query about it anywhere unless the hardware manufacturer has provided someway to do that. The unsafe is technically a wrapper around a point of imminent crash.
I was kind of left under the impression that making things hard in unsafe mode works as a sort of moral suasion. I feel like it is felt like that by the community (shame on libraries with unsafe code) and it is annoying to people who know what they are doing and simply want to get things done.
Rust is just not great for low level stuff like kernel programming, database system programming, or virtual machine programming because this field is all about "unsafe" memory manipulation and pointer arithmetics and Rust brings no tools that do it more safely. Basically Rust comes with idea that "yeah you shouldn't do pointer arthmetics" but this is stupid because when it comes to performance optimized algorithms almost always they come with pointer arithmetics. You typically don't need this in high level applications because someone wrote low level lib in C that you can load in Rust or because operating system had solved most difficult memory allocation and memory access issues for you or because someone wrote database system that you connect over TCP. Good tool here would be not the one that tells "oh you shouldn't be doing pointers" but a tool that can help prove that when I'm doing pointer arithmetics I'm not creating bugs for example running out of bounds.
i think of it more as a competition for what makes a great systems language. c is great, but there is definitely better solutions. Rust really is an amazing systems language and i think it has a huge potential to be the primary usage. Zig is just the other side of the c story. which will ultimately win? No idea, but i would put my money on Rust since it offers more
@@ThePrimeTimeagen I like a lot of aspects about Rust, but I feel like C++ is still the "best" solution we have. Pros of Rust: - better/safer defaults - better/more standard toolchain - easier to maintain (biggest plus) Pros of C++: - more creative freedom to tackle a problem - faster writing speed - probably better performance if you go to the extremes (this is arguable tho, so treat this as an optional point) - more mature libraries and a much bigger ecosystem So why do I think C++ is still the best we have: We can achieve the same level of safety in C++ that we have in Rust. It is just that Rust has more sane defaults, but this impacts the writing speed, also the borrow checker does. And I think it is often more important to get a working something out and improve on that. Rust forces you to deal with a lot of things that you know won't be a problem and that can take you out of flow. This also could be due to my lack of experience with Rust, so i might edit this in the future when i have more experience with the language. also on the safety side: most systems have a ton of exploit mitigations now, so that memory bugs are mostly not exploitable or at least very hard to exploit. Also managememt doesn't care about security often too much. Except if it is a huge immediate risk. But I'm really giving Rust a fair chance and I do like a lot about it. So as said I might come back and update this comment.
Zack has accumulated more experience with systems in his 21 years of life on this planet than most devs have at their peak. I think you're hallucinating stuff like how 'mericans hallucinate commies everywhere they go.
13:00 I thought not having ++ was silly... Until I spent an afternoon tracking down a bug by another developer who wasn't as smart as they thought. After not having it for a little, It just stopped bothering me, and now kinda like how it could avoid some minor bugs.
Comment for 16:00 In languages that define ++ you can use it as an expression like a = 1; b = a++. This would result in a == 2 but b == 1. I think this is just a bit of confusingness that is unneccesary. There would also a loose agreement in a custom Trait implementation that the previous value should be returned when incrementing
The point of Rust is so that I write safe code, and gives me the option to write unsafe in extreme edge cases. If the majority of my code needs to be unsafe I would bother with C/C++
UnsafeCell Whoever wrote this seems to have forgotten that this exists and works as a middle-ground beyond safe Rust and the C-in-Rust abomination. It and the types built around it allow you to mutate values from behind shared references without triggering undefined behavior since the compiler knows to relax the aliasing rules when UnsafeCell is involved. It's even more annoying to access the interior value with UnsafeCell than with a raw pointer, but since you still have access to references above it, it's much easier to use some of the ergonomics of safe Rust like slices and iterators. While not for UnsafeCell, Cell (which is built on UnsafeCell) has methods to convert between a slice of Cells and a slice inside a Cell.
Yeah I don't know. The article rightly pointed out the perils of unsafe Rust, but if you're application is mostly unsafe code then Rust is probably just not a good choice in the first place. But even then, one thing I like a lot about Rust is that I *can* write safe code. Outside of unsafe I know my Rust code is safe. Zig makes working with pointers safer, but it's exactly that: Safer. Not safe. And that's ALL of your zig code. In that regard I would much rather write a bit of yucky unsafe Rust and a lot of very nice and safe, safe Rust instead of writing the entire thing in non-safe Zig
While I also have not done enough unsafe Rust it seemed like they should have gone about it diffently. Most likely they did not need two &mut's to the same data at the same time. That was just how they were storing the pointers. They could have used unsafe_cell to help clean it up. It would not remove pointers entirely but it would rearrange how they used them. I'll try to pull there code and see if it makes a difference.
He checked miri for runtime UB errors in case of Rust. How did he assert that Zig is safe without checking for UB? It says that Zig is safer, but I didn't find any instance where he explained how.
I believe it’s because the zig compiler checks aren’t turned off for unsafe zig code and zig also has runtime checks. He had to use Miri to check for UB because rusts compiler doesn’t check unsafe blocks.
In Rust no aliasing of mut references is not just a rule followed by the borrow checker, to prevent some errors. the Rust compiler assumes that that can never ever happen and uses that to do wild optimizations. But in unsafe Rust code, the borrow checker cannot help us, and the compiler will screw us if we break the assumptions of the compiler. That is not the case is C. In C aliasing is totally legal. (No experience with Zig, but I would assume the same here) So there is a whole class of UB that is common and easy to introduce in Rust, that just doesn't exist in C.
@@Ockerlord I always use black box when using unsafe rust to prevent those kinds of optimisations. Since I'm going bare metal, may as well optimize it manually. I'm not so sure about Zig. Making concurrent apps would be a pain in the ass even if it can detect some errors at the runtime. I use Rust for safety guarantees, not for speed.
@@emptydata-xf7ps that's not how unsafe works. Unsafe gives you (iirc) exactly 4 "superpowers": * You can dereference pointers * You can access static muts * You can call unsafe fns * You can use assembly. Everything else about the language, borrow checker included, works exactly the same.
@@SimonBuchanNz I know how unsafe works. That’s not the argument here. He asked the difference in compilers. And I said zig doesn’t turn off compiler checks for unsafe code while rust does.
The Rust part of that article kinda feels like the person didn't understand the point of making safe interfaces to the parts that need unsafe. doing it all in unsafe is kinda distinctly against the point, no?
I learned C, and while i didnt yet master C, i wanted to try out Rust, (or god forbid C**) but Cp+ is well spaghetti and the rust fundation did a major blunder, so Zig sounds like this angel coming for the rescue
Psst: here's a great secret. C DOES NOT NEED REPLACING. C with valgrind has fixed the bad code problem. All the power and speed of C is found in C. Learn to make peace with pointers and just don't do stupid things and you'll be fine.
Yeah, I was using my C library in Rust to feel like OOP style, I mean using methods on the object. But unsafe Rust wasn't really great. I don't know Rust compiler optimize or not, but wrapping my c functions in rust using unsafe made me think about performance. Do I really need to wrap unnecessary function calls every c functions? So i go back to C and it was so much better than unsafe rust.
This just falls back to the ole "using the right tool for the job". If you find yourself having to write unsafe Rust code everywhere (and being annoyed by said unsafe Rust), it's probably not the ideal language to be using for that project.
Ok so I need to:
1. Write it in C
2. Rewrite it in Rust
3. Rewrite it in unsafe Rust
4. Rewrite it in Zig
5. Take ketamine
6. Rewrite it in C++ ?
7. Enjoy
You forgot Cobol, HolyC, Ada, and D -- the CHAD stack of systems programming.
Rewrite in Haskell to experience God mode
@@biskitpagla and Finally assembly, just to be sure.
@@biskitpagla Then Lisp, Lua, V, Java, Kotlin (the same thing, lol) etc.
The ket intake a really essential part of the process there
I am a C developer wanting to switch to Rust. This article is like a demon whispering in my ear “forget Rust, go for Zig”
Unsafe Rust... different from safe Rust.
You’ll have the ability to iterate quicker with Zig, the Rust compiler can be quite slow I’m afraid. Although Zig is pre v1
Zig does not have procedural macros, Rust does. Any language without procedural macros is infinitely inferior.
'comptime' eliminates the need for macros
@@baxiry. nope, it does not. Macros are much more than just some compile time computation. Macros are for implementing embedded DSLs, i.e., macro is a compiler that runs in compile-time, and does all the things a standalone compiler can do, including arbitrary optimisation.
I really don't know nearly enough about the subject to say anything usefull, but my impression of unsafe rust is that it is designed so you can dip in it to solve a specific problem, then wrap it in a safe api so you can use that with regular rust. If you're writing the whole thing in unsafe mode then you might as well use another language.
this is a good observation
Yeah. That's kinda the point of the article. Zig is better than Unsafe Rust for apps that would previously be written in something like C for precise memory management and freedom of control
@@sebastiangudino9377 but the point of Rust is that you *can* do that precise memory management and freedom of control, but safely. When you're messing with low level stuff that is not safe, use unsafe, when you're not don't. If your program is even slightly sane, it's not going to be mostly low level memory management, and the safety guarantees outside that code are extremely useful.
@@SimonBuchanNz I see your point, but have you ever actually used unsafe rust? Seems like you know about it, but you don't know how it is really like. Unsafe is for very small self contained blocks of code that you are using inside a bigger generally memory safe project. It's pretty different from the more management you do in C or in Zig, where there is no borrow checker to fight with.
So yeah, your point IS valid. But seems to come from lack of experience with either memory management in general (Outside of rust) or with unsafe rust in particular. Using unsafe rust for a big project might be a good indicator for why things like Zig even exist
@@sebastiangudino9377 Err, yes? A lot of FFI, including code dealing with complex threading behavior, a memory allocator (a buddy allocator) and some manual atomics threading code. It's mostly going down the safety requirement checklist of everything you're using to make sure they're met, which often turns out to be a lot more than you expected, but not exactly tough most of the time.
The fact that types have alignment, you can't read unitialized bytes, etc, are all pretty intuitive and often directly follow from hardware, so they're also required by every other language, you just don't get the warning labels.
Not breaking the rules of references can be occasionally difficult, for example when you need the offset of a field, but there's always a decent answer.
And MIRI is there to catch you if you mess up, unlike C or C++, where the likelihood that you *ever* get any slightly complicated bit of code completely UB free is a joke.
So I have to ask, have you written *correct* C dealing with such "precise memory management and freedom of control" before? Because if you think unsafe Rust is at all difficult in comparison, then I'm going to completely disbelieve you and anything you say. Every moment of C is like unsafe Rust but without any decent documentation for avoiding broken code and all the wrong defaults constantly guiding you to creating broken code.
That's an incredibly well written article. The author was trying as much as possible to be objective and present things as they are an not just trying to sell you on his own opinions :)
i think he ackshually did a great job too. i was very impressed
This marks a stark difference with Rust furries.
@@SbF6H Rust furries is WILD
I learnt python and typescript and was going for rust. I saw zig and thought "yeah i'll go with zig".
Now i started learning assembly. I have no idea what I'm doing...
@@legendrags thank God you did not go with Rust
Zig doesn't need to re-establish all of the history of C in order to replace C. It made sure to have more than just the typical basic C interop so that this could be true.
It integrates with existing C infrastructure without compromise, so the transition from C to Zig is painless imo. You can literally have an ongoing legacy C project and just start writing parts of it in Zig instead, just switching to use Zig as your compiler.
Yeah, when I learn you can just include c headers in zig I was over the moon with joy
@@sebastiangudino9377I am no2 using Zig as my C and C++ compiler. It has been very nice so far.
"then you have to fulfill all those decades of libraries"
that's the neat part, you don't! zig has excellent inteop with C code and it's super easy to use & run C code from your zig program, i've done it before with creating PNG files and found it very easy despite having very little C experience. at most you might want to write a wrapper for the endpoints so you're not exposing C types in your zig code, but that's all you really need to do
very much interesting
Yeah, to me it almost feels like zig is the kotlin of the java world, in the way it works nicely together with C (and kotlin working nicely with java). Which made many java projects, including android, switch to kotlin; part by part. The zig compiler can also target different glibc versions and with nice cross compilation I can easily see why C devs would lean to zig even if they only want to start with compiling C code.
isnt the same in rust? you get out of the box C interop, BOTH ways, c calling rust, and rust calling c
Yes, you can use Rust to talk to C, but then you lose any of the safety guarantees afforded by Rust, at the API end points.
@@lesto12321 sure, but a big selling point of zig is that it's extremely low friction. Most languages have ffi nowadays but zig aims to be very easy to integrate into C codebases
5 years of Zig preferred.
already there
The space that zig fills for me is a better C, in every way. Better error handling (goodbye goto and initialized checks), no null pointers, stricter type checking, comptime (both for generics and for metaprogramming), being able to include C headers and zig also generates C headers when you use export so you can use your zig code from C without writing bindings. Being able to compile c and c++ code and switch out part by part is why it's easier to replace C with zig than other languages, along with that automatic binding. This is what kotlin did, and kotlin has replaced java in a lot of projects (including android).
But most importantly for me, is that zig produces binaries that are even smaller than C binaries. Hello world in rust is 5mb (static) while zig is 2kb (static). At my previous job a 5mb increase in disk space / memory usage was classified as a bug and had to be fixed before release. It's also especially important for a unix-like environment where you want to have many small binaries, that can easily fit in cache (true also for "serverless") and slow devices like my pinephone.
A 2000 times increase in binary size is unacceptable for me, no matter how good the language or the environment is. And zig is really the only modern language that is willing to focus on the whole build environment and make it better than everything else (cross compilation, even for c and c++, with just one argument, pure machine code backend, etc. Also has C backend to be able to run the code everywhere).
Interested perspective about the binary size, never thought about it in this way.
This could even improve performance, especially with the 3D cache we are seeing with AMD.
Hello world is 5mb and 2kb? Classic shitposting. On a serious note, Rust does have a compile time problem, the size problem is *largely just a side effect of the compiler making trade-offs to compensate. Let’s not get it twisted, you still need to muck about with compiler flags in both for constrained environments. Zig is definitely a good way to write C though, I personally love it.
*if you are comparing languages and not std size
I don't know shit about either of these languages, but are you comparing a zig program with dynamic linking to a rust program with static linking?
@@SR-ti6jj he's talking about the default hello world binary size, without using compiler flags, and probably not using no-std as well
While still significantly higher than your zig equivalent, you can easily reduce the static rust binary from 4.3 mb down to 276 kb using a few flags (namely strip). I wouldn't be surprised if you could optimize that even further but my Rust knowledge is very limited.
The reason why Rust doesn't have ++ is because in Rust assignments are not expressions.
In C `x++` is equivalent to `x+=1` because both not only increment x but also evaluate to `x+1`. In Rust `x+=1` evaluates to nothing, it's only a statement.
So if you wanted to introcude ++ into Rust you have to make a choice whether you want it to work like in C and be inconsistent with +=1 or simply be an alias for +=1 and be inconsistent with expectations. The Rust team decided either was bad and didn't add it at all.
Wait so if assignments aren't expressions what are they?
@@ausername27 statements
i don't wanna be pedantic but `x++` evaluates to `x` and `++x` evaluates to `x+1` (have fun figuring out `++x++`)
expectations that x++ is an expression? Are people expecting that x += 1 is an expression too? And if yes, isn't it the same problem? I don't really get why not add some syntactic sugar, and some Increment trait, it really wouldn't be such a tragedy
+= is an expression, but it returns ()
x++ would be { let x2 = x; x+=1; x2 }
and ++x would be { x+=1; x }
29 years of zig experience required.
It's only 29 now? Sheesh, nobody wants to work anymore, these Zoomers are so lazy!
Just get yourself a black hole.
Entry level? hahahahaah
It's possible. Zero Wing was released in the 1989.
lol
"Why would use too much unsafe Rust?"
Well it is common if you are working in something like OpenGL, XLib, and other things.
Using these in Rust is quite annoying some times.
Do you know any articles/personal experience why writing low level graphics is not very comfortable with Rust?
@@nilspin Because it's unsafe C nonsense. Stringly typed apis full of magic numbers ( c enums ), raw pointers, etc.
I actually find it quite fun to wrap FFI in safe Rust apis. The main problem is that you often find out that nobody thought about documenting whether you can use handles across threads etc.
I'm not sure about interfacing with C libraries, but from what I'm aware, a _kernel_ generally uses less unsafe than this, and it's pretty hard to get any lower level than an OS kernel.
@@nilspin OpenGL in particular is a back box of a global state machine (which rust rightfuly hates) and is implemented in C. And because Rust considers any C code inherently unsafe, you will have to wrap almost every function call in unsafe blocks because you'll constantly pass around raw pointers.
Technically the post and pre (inc|dec)rement unary operators are holdovers from C back when C compilers were architecture specific, in this unary operator's case back when they were invented the C compilers were targeting the pdp11. The pdp11 has specific post and pre increment machine operation that these unary operators would directly map to.
Actually, this seems to be a myth. At least I read that recently in some article on the evolution of C. Let me know if you need me to find it again, I apologise for not providing the reference right away (I am on my phone), but I think it should be easy to google.
How did the post operation work? Did it store the value in a register and THEN increment it in place? If so that's a pretty cold instructions!
Zig is C but without null pointers, has out of bounds checking, no preprocesser, no make files. Zig is what c should’ve been. It can even translate C code to zig. But we all know C developers are masochists and a tad too arrogant to leave their beloved language behind.
i could see c being replaced, but again... its c ;)
to play devil's advocate, it is easy to say C is "stupid" when it s a 50 years-ish old language 🙂
To be honest i have yet to read of any so called arrogant c programmers fully bashing zig. There seems to be, as far as i can tell, a general openness to it and like of it. Similar to Odin.
Especially because the interop means they can add at their own convenience. If you know any that hate zig let me know, the number one complaint so far has been lack of 1.0. Not lack of enjoyment with the language.
9:25 The reason you get UB with the double mutable references is because the compiler can assume there exists only one alias. This means that an optimizing compiler can elide some reads from memory after calling a function. But if that function mutated the aliased memory, you now have a stale representation in the caller.
My impression is: If you are writting a lot of unsafe Rust as your product... maybe do not use Rust? Some packages in Rust are filled with unsafe code, but because they dealt with very specific operations that are carefully monitored and checked, so that by using the package you do not have to write the unsafe code yourself. But if your whole point of your program is to write unsafe Rust, why? Just why?
Rust is designed for a type of problems, in which memory safety is paramount, and it requires to rethink your problems for the new paradigm.
If you cannot rethink your problem in a way that leads you to use less unsafe Rust, then why not use C anyway?
"But I want to do it in this way!" well then use other more suited language, no?
I think that the problem is that the article is "Why a scewdriver is better than a hammer in some situations: My experience fixing a PC" and my conclusion after the article is "yeah, no shit, Sherlock". It felt like reading the constant struggle of a man trying to fix a window glass with twizers and a blow torch: In theory one could make that work, but why wouldn't you user glass glue instead?
I do agree that if you're finding yourself writing a lot of `unsafe` rust it's probably not the best language for the job. As much as I and seemingly everyone else loves rust, it isn't a good fit for every application.
It really does always go back to the old adage of "using the right tool for the job"
I think the creator of zig said it pretty well in an interview before. Basically, while Rust has better safety in an ideal world, using unsafe code is basically just putting up signs saying "there be dragons" as prevention.
Meanwhile zig has a more consistent level of safety, however it's not quite able to reach the heights of rusts borrow checker
This is not strictly true lol, even in insecure mode Rust's borrow-checker still exists, and there are parts of the code where naturally insecure patterns will arise when we are dealing with layers closer to the hardware, it has nothing to do with how consistently secure a language is, but how generally secure it is.
A delineation is still useful.
The idea of rust too is that you're spending as much time as possible in that safe ideal world, and the unsafe blocks are few and far between. So you do your unsafe thing, get out of unsafe and return something safe for your code to use, wrapping it in an appropriate Option or Result type if the unsafe operation might fail. If you find yourself using unsafe a lot, you probably want to rethink what you're doing, because there's likely a better way. Usually I'd guess it comes about as a result of trying to replicate a design pattern from another language that just doesn't work well in Rust. And if you do that sorta thing, you're basically trying to force the circular piece into the square hole.
Honestly I think one of the biggest flaws with how Rust is presented is the whole "rewrite it in rust" meme, simply because Rust unlike a lot of other languages, just isn't designed as the sort of thing that you can just take your favorite lines of code and do a 1 for 1 conversion. Unless you absolutely have zero choice, try to do things the Rust way. If you try to keep coding like you're writing C or C++, you're probably going to have a bad day.
@@taragnor
Hmmm, I think the last part is wrong, because we say "rewrite in Rust", and not "copy-and-paste in Rust", so it is expected that you would have some work redoing some things in the language instead just redoing the same thing.
@@diadetediotedio6918 It really is up for interpretation, and sadly people just see the meme as a promotion of Rust's benefits but don't think about where said benefits come from or what rewriting Rust actually should entail, and then when they give in to give it a try they try to write in a way they're used to, get frustrated with the inevitable trouble that entails, and get disappointed away from the language and its community.
Regarding the ++ debate, I personally agree that rust's iterators, ranges etc. eliminate 90% of its regular uses and when it's just on a single line, having += makes it easier to see that that variable is being changed. Like seeing the plus immediately makes it easier to grok what that line is doing. So for me it's about readability and if I'm incrementing something even in typescript I still use += quite often, leaving ++ only for loops.
After writing unsafe Rust for some low-level data structures and algorithms, I can confirm that it can be really annoying for certain use cases. Miri is a huge help, but it's annoying that you need a separate tool just to look for your leaked pointers, undefined behaviour, etc. Zig does a much better job of handling these use cases. That being said, I still would generally prefer Rust because the rest of the ecosystem is so much stronger. Iterators, functional programming, etc is just so much nicer in Rust, and I love still having those features, and for me personally, I feel it's worth dealing with the increased overhead of undefined behaviour. Rust definitely is harder to use and make safe (when writing unsafe Rust) then C/C++/Zig though, which is annoying at times. If you have to interface with a lot of C libraries, I can really see why someone would prefer using Zig.
Not only do we need ++ but also +++ for adding 2 and +!:() for adding 78.
😅
Hey Prime! I really love your content and thanks for teaching me NeoVim.
I just added 3 keymaps and felt like I started a road that is making me a better, more efficient programmer, while having fun!
Thanks! :)
you are not appreciating his effort unless you are using rust.
lets go!
@@musdevfrog I'm curently at the Chapter 15 of the Rust book my brother! :)
@@Rana-yk6xn what’s the book name? Please
@No One The Rust Book
My experience with unsafe rust has been more or less mundanely fine. One of the libraries I worked on was for a secret storage system, and we build a non-contiguous memory guard system into it. Of course this required a ton of unsafe rust. The Key/Value store in the system also required some unsafe rust for encoding and decoding the memory into various encryption schemes. There were points where we hit undefined behaviors but that's to be expected. The general rule of thumb that I learned is to add asserts into the code blocks so that if undefined behavior happens, it will trigger an error message thats actually useful.
My experience with Zig has also been pretty mundane. I could see it being used for various small things but I am not sure about how useful it would be for a large project.
I can see a decent amount of people use zig’s build system for C. The build system is so much better than make/cmake in my experience
i think you just sold me on zig
Yea this pretty much sold it for me. After suffering setting up gradle for kotlin in VS code, i feel pure dopamine just reading the words "better build system". Zig is next on list.
I've never had to write unsafe rust, but my understanding is that unsafe doesn't mean: now we have C lang, but rather, I'm doing something that is not provably safe by the compiler. Unsafe is really an unfortunate name/keyword as I think it lends to the idea that sometimes it's ok to "not be safe", when we really mean "less strict validation".
there is pretty good explanations in this article about the tricky parts.
mut pointers yes
mut pointers to refs is where the issues are
There are people who believe the name "unsafe" was a poor choice and the keyword should have actually been "safe".
Because Rust unsafe blocks are really a promise to the compiler that you _know_ what you are doing is ok even though the compiler cannot prove it.
Even though I love Rust, the unsafe barrier has been the reason I struggle to use it on my day to day work, we work on embedded, low-latency realtime embedded, default rust implementation was pretty good just we knew we could do better, to squeeze those extra instructions per cycle we had to rewrite everything in unsafe blocks, it was sooo hard, ended up rewriting on C++
@@ratgr Sounds interesting. Any insights why Zig wasn't considered/chosen? Was the language - being 0.xx - to immature for professional use? Or was C++ just a skill available in the team that it was a pure time-decision to default back to that?
@@micha-ix1iy We had a good amount of code on C++ anyways, it was just a language that most of the team is good at, we do have a couple of large project on Rust now, but we stopped Rust on all our embedded development and went back to C++. I still think Zig is too inmature, and we have to figure out how to make it work with owr chips, and learn it too, maybe next year. Now with rust as a quasi-failure don't think it will be easy to try another language soon
Most of the comparisons between a language like Rust or Zig and C/C++, are using extremely old versions of the C/C++ standards. C++ now has smart pointers, or pointers that can clean up after themselves, string and vector classes can handle a lot of the buffer overruns. C just requires that the code be careful, and that may mean writing most of an application in Python, and then just the stuff that needs higher performance, gets written in C. Just like back in the 1980's we wrote most stuff in BASIC, and the higher performance bits in Assembler. A lot of programs started by stuffing the assembler bit in high memory, then using the SYS function to call it when needed.
smart pointers don't make c++ any less terrible to write in (imo). safer, yeah, but let's be honest at this point c++ is just the javascript of the compiled world. years upon years of weird features stacked on top of each other... just that in c++ if you don't do things the hygenic modern way you get buffer overflows and memory leaks instead of accidental type coercion errors and callback hell. the only reason either of them are still used is because they're already established standards.
@@lunafoxfire The critical problem with most languages is they try to be everything for everyone. Back when I started you wrote nearly everything in BASIC and then stuff that was too slow or ugly to write in BASIC was written in Assembler.
When I was in college we learned, COBOL, FORTRAN, BASIC, Pascal and assembler. Today they want A language to do everything. Personally I would rather use Python with the stuff that is too slow or ugly to write in Python, in C. What often makes C++ goofy is the fact it needs to be mostly compatible with K&R C, even though that hasn't been the C standard for over 30 years.
@@lunafoxfire That's why you ignore all the ideologues that tell you you need to use STL algorithms and containers literally everywhere. Who cares if they seethe if you "write C in C++" but only use the features you want?
So, Zig is literally a c/c++ and zig compiler/build system all-in-one. It interfaces with C and can export easily to C ap just like every other programming language.
It is a c++ replacement, however, not a C replacement, and it is literally paring down most of the language to the essentials. This is different from Rust that is trying to match features and replacements, Zig is looking at the most useful form that works across the most use cases, and just makes that the canonical form in the language.
This is much closer to the C philosophy where the go was to have a versatile but small language that can be used everywhere. Zig is trying to do the same thing for C++ and all the rest of the various languages at the same level of abstraction.
On another TH-cam channel a task was given to people who wrote in different computer languages including assembler language. I believe it was 105 different languages finding a long list of prime numbers. It wasn't about safer code - but the fastest running code. Zig took 1st place and Rust took 2nd place, and Zig was twice as fast as Rust. The focus is on writing clean code easily that runs faster than any other computer language. The language is still in development but the initial results are startling. There is a team of people trying to see about optimizing C code - but include the best C libraries that run on linux, windows, and mac - so that the language can be run on any operating system. I think C programmers might like learning Zig because of that.
The C interoperability is a big one for me. Both Rust and Zig have their advantages and disadvantages, but for a lot of teams there are simply fewer obstacles for Zig adoption.
Hey mister. I don't play around with pointers... You better remember that.
When Stroustrup said "C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off", he should now add "Rust doesn't permit you weapons at all and even if you try to get an illegal weapon, it makes it as difficult as it can". No methods or nice pointer dereferences for bad boys.
As soon as you hit undefined behaviour, the compiler will go "oh no, you didn't" and optimize the surrounding code as if you hadn't written what you wrote. And frequently undefined behaviour propagates, basically deleting any operation that interacts with your "undefined behavour result", and without those results the optimizer will optimize based on their non-existance, and so in the end the compiler ends up just writing something arbitrary instead.
Thats why debug builds exist.
@@marcossidoruk8033 and what does your debug build change about the compiler trying to optimize ub when it's time to actually release your product?
For the topic of var++
If var++ is an expression and returns a value like in C, then
foo(var++, var++)
could be undefined. Even if it was a defined, this will be much harder to read IMO.
And if it's a statement, I'm good with += 1.
That line would be dangerous in C as well, because of how sequence points work.
This was really interesting! I like both Rust and Zig but have only done a small amount of toy code in each, and no unsafe Rust at all. Would be interesting to see you try something that needs unsafe Rust and see how you go.
I know the title is click bait but both of these languages are great new choices for different applications. I feel like un-safe rust is pointless though and zig or just c would be better if you can't afford the borrowing overhead. Also I feel like Zig is a true replacement for C where as Rust is more a true replacement of C++, Java, and C#. Still the results are really interesting and Zig will be more on my radar in the future.
I spent two months writing many core codes using zig and rust.
It is my humble and honest experience, zig is not mature, but has so much to offer. Concurrency is not what Rust promises, either we should use unsafe code or use rwlock, and many extra code to manage the life span of variables.
It takes so much time to jump through the hoops. Zig is fast and does enough checking to avoid memory leaks
12:38 The problem with "++" is that, as soon as you allow "some"-fix increment, people will ask for the other one (prefix / postfix). Then, the language will have to deal with whatever `++i++` should mean, and that goes down a rabbit hole. The decision about the semantics of that will influence some other areas of the language semantics, just like it did for C++.
was looking for this comment
it's UB in C++!?
@@tk36_real what isn't UB in C++? /s 🤣
@@tk36_realif you mean ++i++ is UB, no, it simply doesn't compile.
The real move is, use zig for very low level stuff, and use rust for a bit higher up
Edit, replace unsafe rust with zig
I've implemented the VM that this post talks about in rust multiple times and in zig once. The zig implementation wes by far the easier of the two. Even with knowing where the annoying bits are you end up with either a bunch of custom wrapper types to help abstract away all the annoyingness of the unsafe pointers or you just end up with a bunch of annoying unsafe pointers. Either way, it's not very ergonomic and fun
yeah, rust isn't the tool for every job, but it can do a lot of jobs :)
Crazy to watch this video and see the 180. Great job on having an open mind!
Yes, even in C and C++ the compiler can introduce bugs by assuming that there's no undefined behavior and optimizing it out. If you relied on UB, then the compiler may very well transform your code into something dangerous. For this reason I like to compile and test with -O3 (instead of -Og for example) because O3 is much more likely to flush out any UB in your program.
-O3 can sometimes hide bugs for the same reason. For example if you read from a null pointer, but don't use the result for anything. Compiler will remove it and program will behave well. On -O0 it will 100% segfault.
@@araarathisyomama787 that's a good point. testing with O3 and Og seems to work best although that sounds like something the compiler would warn you about (reading from pointer and discarding the result)
clang has -fsanitize=undefined you can throw in your debug builds to detect UB at compile time (ymmv though)
The benefit of Zig is that, it provides safe semantics so I am able to write both. But let’s be honest here, the unsafe is still unsafe however much you sugar coat it. Sure there are abilities to make you code safe in Zig. But it is never about the ability to do things right, but instead the ability to do wrong that has landed us into hell with C++. My problem with Zig is that, it provides these dangerous abilities on a silver plate to the users.
Rust is used in Blockchain for nodes and smart-contacts. Rust is used for WASM. It will grow huge.
This article doesn't justify why they need to write unsafe rust at all. Without that, rust isn't getting a fair shake here.
The problem is that 90% of the time, people who write unsafe rust actually don't realize that the borrow checking model means you have to write code differently. Idioms you are used to are illegal in safe rust for good reason and there are usually low cost alternatives - though I'll admit here that my actual experience with the language is limited.
All that I'm left to wonder from this article is whether this person doesn't know how to write memory type safe code.
you ever try writing a mark and sweep in rust? The borrow checker fucking hates you
I have read this article before; but I still appreciate ThePrimeagen reading for me again since I sometimes don't pickup all the little things.
Thank you :)
yayayayaya
Zog doesn't need to replace the vast world of C libraries - at least in the short term. It's designed from the ground up to interop seamlessly with C.
I've been trying to keep myself excited to continue learn code. This channel has been good motivation, breaking up the boring documentation searching. I always learn something, even if it's just something niche about a language I'll probably never pick up.
I feel like people always confuse unsafe with wrong, yes it should be avoided, no not at the cost of more complicated/less performant code. Using unsafe as just another tool to write more understandable code would be a better approach than saying unsafe rust as a whole is wrong.
Looking forward to zig 1.0
C has been my my language for about 10 years and I see rust as the proper C replacement. With no_std, a standard build system and package manager, awesome macros and the lack of/alternative to OOP it's basically all I ever wanted.
Zig sure is a weird in-between thing and I can't wait to see where it'll be in 10 years.
I don't see how Rust can be replacement for C. For some big C++ projects - maybe. But not for C. Rust just carries too much overhead that is unacceptable in the context where C is used. And Rust's safety model is not even useful in most cases where C is used.
@@sk-sm9sh which overhead exactly? you can decide for yourself which features and/or crates you use and thus have very good control over binary size and runtime performance.
For example, if you wanna parse CLI args you don't have to use clap, you can also use argh. You also have tons of options regarding code size vs performance: generics vs dyn, std vs no_std, ...
In every place where I use C, Rust would be very useful. I write firmwares for both MCUs and low-spec Linux systems and C is both very verbose and error-prone. With rust being a general/multi purpose language it surprisingly fits both of these usecases very well. Admittedly, no_std isn't quite there yet due to crate/driver availability.
@@sk-sm9sh I can also provide an argument from the other side: I think that Rust is closer to C than it is to C++ in terms of it's language design choices. And I get the impression that many C++ devs wouldn't wanna use Rust instead of C++ anyway - either because they don't like the concepts and they don't fit their way of thinking or because they simply don't like the syntax.
@@sk-sm9sh sry for spamming but I just had another thought about `And Rust's safety model is not even useful in most cases where C is used.`: A huge portion of C software actually lives in Linux userspace. Most CLI commands are written in C and Rust tools like fd and rg have started to replace them. Also tons of services like bluez or systemd are written in C as well. And in those code bases you can see a lot of boilerplate to work around missing C features like automatic destructor calling.
@@MichaelZimmermann why don't you want to give zig a try? It's an easy drop in for any C project. With Rust is it really producing same size binaries as C? In unix cli tools environment small binary size kind of matters as it's used in so many diverse environments.
Nobody can tell you what the undefined behaviour is. By definition, it is undefined. It may depend on the OS, the CPU architecture, be changed from compiler version to compiler version, be dependent on heap/stack layout, whether building in debug or release mode, etc. etc.
In virtually any real-world scenario, unsafe code in Rust will be restricted to strictly extremely low-level matters like communicating with the hardware or doing some operations that would be impossible in everyday language. We can quote here on the issue of the benefits of the approach of creating security wrappers in Rust to interact with unsafe code Asahi Lina herself, who has already said quite clearly how much the borrow-checker (which by the way exists in unsafe scopes also in some level) and the compiler in general made her experience of developing the M1 GPU driver much less complicated and more pleasant than it would have been without these features on other languages.
So, IMHO, if you're using this much unsafe code like this you've probably already started off on the wrong foot in what your code should be.
Rust fanatics don't seem to grasp that a theorem prover can provide compile-time guarantees for what would be unsafe code
@@qx-jd9mh Per the Curry-Howard correspondence type/borrow checking is theorem-proving. Type systems give theorem-proving great ergonomics by integrating it directly into the language. It's much more difficult to maintain separate proofs about code written in a different language than the proof language. That is a real advantage of Rust. I think the Rust community should instead focus on improving the type system to make it more expressive and easy to work with. A good first step would be to bring it up to parity with Haskell, but the end goal would be a full-blown dependent type system extended with linear types, capabilities and regions (which would subsume borrow-checking). This would eliminate the unsafe subset of the language entirely and enable whole-program verification even in the presence of manual memory management.
@@kieranblazier4058 Nothing like being restricted to ineffective theorem proving techniques... ATS doesn't cut corners when it comes to compile time guarantees. ATS is hard but so is high performance systems programming. You cannot pretend that everyone is qualified to write code that runs as fast as possible and is safe. It's weird because you don't usually see people complaining about the high barrier to entry to become a surgeon, yet you are people whine about the difficulty of ATS.
@@qx-jd9mh idk about ATS being difficult, but it sure is ugly.
Just a day after my interest in Zig got picked, you release the video I was looking for and didn't find. Nice.
piqued*
@@micha-ix1iy oui!
Zig is the future
The “post” refers to the position of the operator rather than operand.
So x++ is the POST variant.
The ++ is probably related to how it's technically a returned value and maybe something to do with rust mutability. Like you can do arr[i++]; but you can't do arr[i+=1]; for example in other langs.
I think a good example of good usage of unsafe rust is PyO3 project which provides bindings between python and rust. In benchmarks it consistently produces code that is just as fast as cpython's implementations of the same algorithms. And while it does naturally use unsafe wrappers at the API boundary, it exposes a perfectly safe API for production use. Given all this, one can draw 2 conclusions: 1. Unsafe is not for use all over your code. It is for making 2-3 line wrappers around the sketchy bits of your code. 2. Writing performant code in rust is just as feasible as in any other language, given that you understand what the compiler expects you to write. Every time you put an unsafe block in your code you clobber the optimizer, which is not great for perf. Zig compiler can, potentially, reason better about raw pointers than rustc can, which is where much of your performance gap could be.
You have no guarantee that this "safe" user space api is actually safe and has no bugs
@@32zim32 I'm pretty sure there is no way to achieve "no bugs" state in practice. But given its wide adoption across tens of projects, it is likely far safer than anything you'd make by hand for a particular project.
The undefined behaviour of having multiple references when one or more of them are mutable is that the compiler assumes it doesn't happen. It will optimise the code assuming it follows the rules and that will likely break something. The problem with UB is maybe nothing happens, maybe it crashes the app, maybe it causes results to be just slightly wrong and isn't noticed for a long time.
Regarding the ++ stuff, I don't have any issue with them no matter if it's before or after. I don't particularly care if it exists or not though.
26:00, I don't even remember when I had some serious issue, regarding to pointer indexing in C++. I wrote a class that inherits a container, and checks the index. I can turn that on/off anytime, for the entire project, by changing just 1 line!
It's also hard to get a trouble about pointer dereferencing, because everything is 'begin() + K, end() - N', valid range of containers. There's no space here for pointer issue. And when I send a nullable pointer to a f(), it uses to be null by default, which means I want to give the user the choice of sending it or not. In this context, it's obvious that I'll check the pointer soon. If it's a 'const char *' (for a string literal), and I want to earn some performance by not checking it, I set its default to "". So I don't have issues with pointer at all!
28:39, he meant that failing on those checks forced him to give up on pointers. These are much faster, because indexing always come all the way from the beginning. And failing to UB is not an option.
I can't believe so many people are opposed to the ++ operator. I don't really feel strongly enough about it to complain, but I prefer ++ for some reason, just looks neater to my special eyes.
Assuming that people are voting based on UX preference and not technical reasons that might negatively effect rust or performance. Though I really don't see how it would be possible that adding such a thing to a compiled language could negatively impact performance.
That said, I do kind of dislike having multiple different syntaxes(?) to do the exact same thing, that are different enough to throw you for a loop the first time you see it. Especially if one of them ends up being totally superior to the other. But ++ feels like its almost embedded in the programming zeitgeist now that I don't think it applies there.
I can't help but think the person was trying to "use rust as C" and that's why it "needed" that much unsafe rust
Tooling, UB and syntax... Yes if you want to do unsafe it currently makes it so that you "better just spread around that unsafe" or face possible UB if you want to provide a better api with references for the called instead of pointers. On the contrary for this kind of nasty work there are tools and UBs are also more researched in some langauge like c/c++ while likely zig avoids most of these issues.
This is very good take. I feel the issue is that its hard to do this "marshalling" kind of work. I mean marshalling between native and managed is also usually very big pain in the ass - I don't know if you ever tried, but basically the safest for those cases is to do the simplest - dumbest, c-like thing with handles as integers and try avoiding this marshalling. I think I would follow the same strategy for unsafe rust + rust boundary as this strategy of mine for managed / native boundaries. It would be totally not idiomatic, but likely work better than whatever I see here.
People in the stream comments saying things like "The reason I write rust is to avoid unsafe" and "The author of the article missed the point of rust" are the ones that missed the point of Rust. The point isn't to always write safe code. It's to create safe abstractions over unsafe operations and then use those generally instead of the unsafe all the time. That's why the std lib is full of unsafe.
But that is the point: All that unsafe code in the std lib is there so that you do not have to do it.
If your normal, not-base-of-ecosystem script is full of unsafe Rust, then you are doing it wrong.
It seems to me that the unsafe-dense packages are the "we put a lot of work into this, so that you do not have to do it" packages. If you are writting one of those, then why are you complaining that Rust is hard? You are literally going against the normal tenants of the language, of course it is hard.
If you are not doing it to create a layer of abstraction to easy the rest of your work, but instead that is your whole work, then use another language!
@@JackDespero The point is Rust is harder than it has to be. Not because of the rules, but because of the ergonomics. For example raw pointers have terrible ergonomics which pushes you towards converting them to references which means you bump into borrow checker rules.
Raw pointers have pointer arithmetic methods, but not operators. This is fine, but it makes your code more verbose.
Or when you're working with threads, pointers dont impl Send or Sync even though there is nothing technically wrong with that. So you may convert to int, pass, convert back, but that has pointer provenance issues. Or you have to wrap them in a new type and unsafe impl Send and Sync which works fine, but is a bunch of boiler plate.
Or another thing. UnsafeCell doesn't impl Copy which means you can't have a Copy type with interior mutability. You "can" do &a as *const _ as *mut _ to work around it, but that is UB so won't actually work.
These are the sorts of things that make people say unsafe Rust is hard. Also, there are lots of reasons to use unsafe outside of foundation layer crates. You almost always know things about your program that the compiler doesn't.
For example you might push something to a Vec, next line you do unsafe { .last().unwrap_unchecked() } because you know there is something there. A lot of the time you can rely on compiler optimisations to do these things, but that only works in a release build. This is why you see posts on Reddit all the time saying that Python, JS, etc are faster than Rust in debug.
Unsafe is part of the language. A part to use carefully, not something to avoid. You shouldn't be scared of it. You should strive to understand it because it's an incredibly useful and powerful tool.
"Carbon will be the true successor of C++". That's a bold prediction right there. My (equally bold) prediction is that Carbon will be the Google+ of programming languages.
Lol, I think cppfront has a better shot since it's modeling the C -> C++ and JS -> TS route. Being able to just start writing cpp2 anywhere in your cpp project is amazing for getting people to adopt your language.
lmao you know i think this every time and the debate rages like this "i bet its going to suck, Carbon is such a *lame* name, wait but they DID make GO.. Yea and G+" Only way to know is to wait and find out! Also gives me a chuckle, every government is trying to reduce carbon footprint even before its out!
i can see ++ being a issue with the fact that everything is a expression in rust,
i mean in C it is the the equivalent of doing a var = var + 1; in a line under the actual line. not on it
so you will end with ambigious va2 = var1++ type of issues issues every time you use it in a expression
"tooling and syntax make unsafe rust hard to understand" I think the problem is a bit deeper. The compiler assuming that borrow checker rules are being followed possibly causes some values to be overwritten without any context to why, debugging this type of problem is probably a HUGE pain.
(if this doesnt happen, then someone please correct me, I haven't actually messed with unsafe rust yet)
The compiler ensure some of the borrow-checker rules in unsafe Rust too, just not all of them or too strictly.
Also, the syntax and tooling are great IMHO.
Every time i see someone gripe about the rust mutable/immutable reference rules, I can't help but substitute Austin Powers saying "I too like to live dangerously". I mean the rust team didn't institute the many readers or one writer rule for clickbait... there's an actual reason for it and if you want to violate it (and you can) you had better REALLY know what you're doing and anyone saying "This is really easy to violate" doesn't fill me with confidence that they've done their due diligence. In the end I feel like is sort of missing the point of safety in rust. Alternatively, i'm just reading too much into it and i'm the asshole.
Regarding "I should play with some unsafe rust": there's a rust tutorial called "Learning rust the dangerous way" which (imo) is a really excellent read and it starts with converting a c package into unsafe rust and then converting it over to safe rust with some fairly small changes. Highly recommend.
@DanteNotAvailable you are right. Only those who know something about electronics understand that once the state has changed in electronic circuits you cannot query about it anywhere unless the hardware manufacturer has provided someway to do that. The unsafe is technically a wrapper around a point of imminent crash.
Write a kernel module in Rust or do some basic firmware with a well supported board!
It’ll be easy for Rust to add that pointer field dereference syntax, they’re already talked about doing that to make writing unsafe more ergonomic
that shouldn't be the only concern. there's also simplicity that is equally important
I was kind of left under the impression that making things hard in unsafe mode works as a sort of moral suasion. I feel like it is felt like that by the community (shame on libraries with unsafe code) and it is annoying to people who know what they are doing and simply want to get things done.
Rust is just not great for low level stuff like kernel programming, database system programming, or virtual machine programming because this field is all about "unsafe" memory manipulation and pointer arithmetics and Rust brings no tools that do it more safely. Basically Rust comes with idea that "yeah you shouldn't do pointer arthmetics" but this is stupid because when it comes to performance optimized algorithms almost always they come with pointer arithmetics. You typically don't need this in high level applications because someone wrote low level lib in C that you can load in Rust or because operating system had solved most difficult memory allocation and memory access issues for you or because someone wrote database system that you connect over TCP. Good tool here would be not the one that tells "oh you shouldn't be doing pointers" but a tool that can help prove that when I'm doing pointer arithmetics I'm not creating bugs for example running out of bounds.
Having to use Miri for unsafe Rust reminds me of using sanitizers for C and C++.
And there it is, an official sign that front end devs are infiltrating the system space. Reminds me of the new framework every week syndrome.
i think of it more as a competition for what makes a great systems language.
c is great, but there is definitely better solutions. Rust really is an amazing systems language and i think it has a huge potential to be the primary usage. Zig is just the other side of the c story. which will ultimately win? No idea, but i would put my money on Rust since it offers more
@@ThePrimeTimeagen Yeah, in the early 2000 we had the scripting language boom and now we have the systems language boom
@@ThePrimeTimeagen I like a lot of aspects about Rust, but I feel like C++ is still the "best" solution we have.
Pros of Rust:
- better/safer defaults
- better/more standard toolchain
- easier to maintain (biggest plus)
Pros of C++:
- more creative freedom to tackle a problem
- faster writing speed
- probably better performance if you go to the extremes (this is arguable tho, so treat this as an optional point)
- more mature libraries and a much bigger ecosystem
So why do I think C++ is still the best we have:
We can achieve the same level of safety in C++ that we have in Rust. It is just that Rust has more sane defaults, but this impacts the writing speed, also the borrow checker does.
And I think it is often more important to get a working something out and improve on that. Rust forces you to deal with a lot of things that you know won't be a problem and that can take you out of flow.
This also could be due to my lack of experience with Rust, so i might edit this in the future when i have more experience with the language.
also on the safety side: most systems have a ton of exploit mitigations now, so that memory bugs are mostly not exploitable or at least very hard to exploit. Also managememt doesn't care about security often too much. Except if it is a huge immediate risk.
But I'm really giving Rust a fair chance and I do like a lot about it. So as said I might come back and update this comment.
Zack has accumulated more experience with systems in his 21 years of life on this planet than most devs have at their peak. I think you're hallucinating stuff like how 'mericans hallucinate commies everywhere they go.
13:00 I thought not having ++ was silly... Until I spent an afternoon tracking down a bug by another developer who wasn't as smart as they thought. After not having it for a little, It just stopped bothering me, and now kinda like how it could avoid some minor bugs.
Your work is really awesome. Thanks sharing that much with us.
Comment for 16:00
In languages that define ++ you can use it as an expression like a = 1; b = a++. This would result in a == 2 but b == 1. I think this is just a bit of confusingness that is unneccesary. There would also a loose agreement in a custom Trait implementation that the previous value should be returned when incrementing
It's kinda funny how much his opinions change
Take the red pill:
Everything will finally be void*
A fan of Homotopy type theory, I see 😏
The point of Rust is so that I write safe code, and gives me the option to write unsafe in extreme edge cases.
If the majority of my code needs to be unsafe I would bother with C/C++
UnsafeCell
Whoever wrote this seems to have forgotten that this exists and works as a middle-ground beyond safe Rust and the C-in-Rust abomination. It and the types built around it allow you to mutate values from behind shared references without triggering undefined behavior since the compiler knows to relax the aliasing rules when UnsafeCell is involved. It's even more annoying to access the interior value with UnsafeCell than with a raw pointer, but since you still have access to references above it, it's much easier to use some of the ergonomics of safe Rust like slices and iterators. While not for UnsafeCell, Cell (which is built on UnsafeCell) has methods to convert between a slice of Cells and a slice inside a Cell.
Yeah I don't know. The article rightly pointed out the perils of unsafe Rust, but if you're application is mostly unsafe code then Rust is probably just not a good choice in the first place. But even then, one thing I like a lot about Rust is that I *can* write safe code. Outside of unsafe I know my Rust code is safe. Zig makes working with pointers safer, but it's exactly that: Safer. Not safe. And that's ALL of your zig code. In that regard I would much rather write a bit of yucky unsafe Rust and a lot of very nice and safe, safe Rust instead of writing the entire thing in non-safe Zig
While I also have not done enough unsafe Rust it seemed like they should have gone about it diffently.
Most likely they did not need two &mut's to the same data at the same time. That was just how they were storing the pointers.
They could have used unsafe_cell to help clean it up. It would not remove pointers entirely but it would rearrange how they used them.
I'll try to pull there code and see if it makes a difference.
He checked miri for runtime UB errors in case of Rust. How did he assert that Zig is safe without checking for UB? It says that Zig is safer, but I didn't find any instance where he explained how.
I believe it’s because the zig compiler checks aren’t turned off for unsafe zig code and zig also has runtime checks. He had to use Miri to check for UB because rusts compiler doesn’t check unsafe blocks.
In Rust no aliasing of mut references is not just a rule followed by the borrow checker, to prevent some errors.
the Rust compiler assumes that that can never ever happen and uses that to do wild optimizations.
But in unsafe Rust code, the borrow checker cannot help us, and the compiler will screw us if we break the assumptions of the compiler.
That is not the case is C. In C aliasing is totally legal. (No experience with Zig, but I would assume the same here)
So there is a whole class of UB that is common and easy to introduce in Rust, that just doesn't exist in C.
@@Ockerlord I always use black box when using unsafe rust to prevent those kinds of optimisations. Since I'm going bare metal, may as well optimize it manually.
I'm not so sure about Zig. Making concurrent apps would be a pain in the ass even if it can detect some errors at the runtime.
I use Rust for safety guarantees, not for speed.
@@emptydata-xf7ps that's not how unsafe works. Unsafe gives you (iirc) exactly 4 "superpowers":
* You can dereference pointers
* You can access static muts
* You can call unsafe fns
* You can use assembly.
Everything else about the language, borrow checker included, works exactly the same.
@@SimonBuchanNz I know how unsafe works. That’s not the argument here. He asked the difference in compilers. And I said zig doesn’t turn off compiler checks for unsafe code while rust does.
Great new course btw, well done, it's really good.
The Rust part of that article kinda feels like the person didn't understand the point of making safe interfaces to the parts that need unsafe. doing it all in unsafe is kinda distinctly against the point, no?
5:39 every class just defines a singleton. just live with it)
Ok well I guess I'll think about zig when I need to write unsafe code
I learned C, and while i didnt yet master C, i wanted to try out Rust, (or god forbid C**) but Cp+ is well spaghetti and the rust fundation did a major blunder, so Zig sounds like this angel coming for the rescue
Psst: here's a great secret. C DOES NOT NEED REPLACING. C with valgrind has fixed the bad code problem. All the power and speed of C is found in C. Learn to make peace with pointers and just don't do stupid things and you'll be fine.
what about UB ?
"I'm sorry, congradulations" is what you say to your soon to be father in-law.
Before I even watch this: WHAT? have I not reached the endgame yet?
there is no end game
Yeah, I was using my C library in Rust to feel like OOP style, I mean using methods on the object. But unsafe Rust wasn't really great. I don't know Rust compiler optimize or not, but wrapping my c functions in rust using unsafe made me think about performance. Do I really need to wrap unnecessary function calls every c functions? So i go back to C and it was so much better than unsafe rust.
05:19 Correction: Crafting interpreters in written by Robert Nystrom, not Thorsten Ball
Rust should add a ** operator which assigns one times the variable to itself
Have you tried the Oding lang? It seems to have a lot of options for custom allocators.
I'd be interested if prime's perspective on this article is different now, considering how immersed he has become in zig
This just falls back to the ole "using the right tool for the job". If you find yourself having to write unsafe Rust code everywhere (and being annoyed by said unsafe Rust), it's probably not the ideal language to be using for that project.
As a representative of the C "community", we don't care about Zig or Rust.
respect
Vouch
4 months ago: "I've tried Zig, and I don't like it. Carbon will be better."
Now: "I like Zig. Compile time is amazing. Carbon will be a flop."
oh is this before he swapped sides?
today he seems all for zig
Whst do you think of Pefect hash table programming language? It is faster than Zig and Bun? I wish to buy Zig programming language book.