If you remove those checks, while Zig does not give you a sound guarantee there will be no undefined behaviour in production, it makes testing easier and faster, helping correctness across the board. After all, the goal is not to write your program in a language with some guarantees, but to produce a program with as few bugs -- undefined behaviour or others -- as cheaply as possible. Which approach results in safer, more correct programs, Rust's or Zig's? Only empirical study will tell.
For not-so-reliability-critical pieces of software, eg game related, zig might be easier to get it done. Some people are really passionate about rust and very talented, they aren't affected by rust's non-zero cognitive overhead. But us trivial 1x programmers are.
Rust's approach is based on one guess re correctness, Zig's on another. My personal guess is that Zig's approach is ultimately more effective at reaching correctness, but I could be wrong. There's no way to know which is better by thinking about it -- correctness is just too complex a subject.
How is that not the goal? The more bugs I can statically guarantee are absent the better!
The goal is to produce a program with as few serious bugs as possible, as cheaply as possible. It is never a goal to use a programming language with certain properties; that could just be a means to that end.
> The more bugs I can statically guarantee are absent the better!
Only provided that those guarantees don't come at a cost that could make finding the bugs you don't statically eliminate harder. How could it make it harder? By making the language overall harder to understand -- both by informal and formal analysis -- making safe evolution more tricky, and by slowing down compilation, which slows down the testing cycle and reducing the number of tests you write.
Correctness is a very complex subject, and that "the more sound guarantees the better" is not a consensus opinion on how to get there. For example, even in formal verification circles, a lot of current research focuses on reducing soundness (e.g. concolic testing vs. model-checking/deductive proofs). It's like the question of how to catch more fish: is a smaller net with small holes that guarantees no fish can get through it better, or is it better to cast a wider net with larger holes, that might let some fish slip through but covers a wider area?
Perhaps in the case of the net and the fish an answer could be given ahead of time if you know everything there is to know about the distribution of the fish size and their dispersion, but that's not the case with software bugs. We simply don't know enough, and the only way to answer the question is through empirical observation, over a wide range of applications and over a long time. It's also possible that both approaches are equally good at achieving correctness, and then it's just a matter of personal preference based on other aspects of the language.
Reasoning is pretty simple: a dynamic approach (Zig) will only catch the memory errors for the tested code paths. This is probably only marginally better than running your C++ code's test suite with address sanitizer.
Rust's static approach provides memory safety for all code paths.
Since your point doesn't really have to do with which languages are involved (only that they are different somehow), one could similarly say that C might produce more correct programs than Rust or Zig for the same amount of effort.
New languages like Zig need to have a better story around safety than "only empirical observation will tell," because Rust's safety story is pretty compelling.
You're assuming much more. The costs I mentioned are not about being harder to code. C++ is also easy to code in.
> one could similarly say that C might produce more correct programs than Rust or Zig for the same amount of effort.
True, and right now it might very well be. C has exceptional verification tools, which is why a lot of safety-critical software is not written in either C++ or Rust, but in C, Ada, and some domain-specific languages that compile to C like SCADE. But assuming "all external tools being equal" I would guess both Rust and Zig would be better, because they both have a very strong focus on correctness and do something about it, while C doesn't even try.
> because Rust's safety story is pretty compelling.
Zig has an exceptionally compelling safety story as well. It focuses on safety no less than Rust, but it does so in a different way. My personal guess would be that Zig's approach to correctness is at least as good as Rust if not more so, though I could be wrong, and I have no problem with people guessing the other way. After spending years with formal verification and following software correctness research, my only conclusion is that we don't have anywhere near a good model for software correctness that would allow us to make any reasonable projection about approaches.
The story, though, isn't just about correctness, and languages can be compelling in other ways, too. Language preference is largely based on personal aesthetics, and aesthetically Zig and Rust are very different. Rust's aesthetics are not to my liking but Zig's are, just as I'm sure the opposite is true for others. I see no reason why there should only be one aesthetic approach in low-level programming just as there isn't one approach in high-level programming.
So not expecting any resolution on the correctness approach any time yet, I think those two languages would appeal to different people.
Zig is way easier to verify than rust code (no hidden control flow, no hidden allocations that might fail, ...) which means a security expert can read a single function (without knowing more about the code) and can reason about that function.
This does not work in languages like C++ and Rust where RAII is a common pattern and code will be implicitly be executed when some objects go out of scope.
Yes, sure. Rust does a lot of verification work already, but so do tools like cppcheck and other verification tools and i'm sure those will emerge for Zig as well.
Zig (in contrast to C or Rust) has no warnings. Behaviours that might not be OK are compile errors and cannot be ignored. There are also plans (as in "not implemented yet") to forbid declaring unused variables and such so even this gets a compile error. This makes Zig also easy to reason about (seeing a variable declaration means that it's guaranteed to be used later)
That sounds very fraught with issues to me. Does that mean existing code will have to be updated in case other behavior turns out to be kinda iffy in practice? Isn't there a strong perverse incentive to just not add anything if that's the case?
What about the deprecation of existing code?
(Though, some people do use linters to get back the warnings. But the language itself doesn't have any.)
The main thing about having warnings isn't being silent in the face of possibly-shady constructs, it's about just making them errors, so you can be sure they don't occur. So e.g. in Go an unused import is an error.
Which is an incredibly annoying thing, because you can't easily just comment out some code and do a quick build to test something. You are forced to cleanup imports/unused variables every time you want to build something.
(Also, if you use something like goimports, it's pretty much automatic.)
It's true that a macro in Rust could introduce an early, invisible return. But this can only happen inside a macro. A reasonable option would be to disallow those in a project where such concerns are critical.
Otherwise Zigs "try" is similar to `?` in Rust, and "defer" comes pretty close to non-obvious control flow for me.
I'm particularly not a big fan of "defer" (and "errdefer"), which I already don't like in Go. Sprinkle multiple of those in a larger function, and following the logic can become quite tedious.