> Zig is revolutionary in that its simple partial evaluation construct replaces generics/templates, typeclasses/concepts/traits, macros and conditional compilation.
This is what C++98 did, except they called their one true comptime evaluation construct "templates", and they did it by accident. There's a reason why Rust introduced generics and typeclasses separately: C++98 templates as bespoke comptime evaluation was a disaster, and this was clear already in the C++ community.
> This is what C++98 did, except they called their one true comptime evaluation construct "templates", and they did it by accident.
Right, except not at all, because templates' syntactic elements are distinct from the "object" part of the language, so it is not a partial evaluation construct for C++, but rather a separate (and rather complex) meta-language for C++. In Zig there is just Zig (with its superb error reporting mechanism), and comptime partially evaluates it. Zig distances itself from C++'s problematic design much more than Rust, which, when all is said and done, is pretty darn similar to C++.
But that's the problem with revolutionary design. Your ability to compare it to what came before it is limited because it isn't really similar to anything. Luckily, Zig can be fully learned in a day or two, so there's no need to rely on comparisons for long. You can quickly learn it and decide if it's your cup of tea or not; even if it isn't, you'd have learned something quite refreshing and inspirational, and without spending too much time.
I do agree that there is something more mysterious about Zig. Nobody knows how "good" Rust is yet, either, but it's probably no worse than C++ when we factor all elements that matter to C++/Rust developers, and we're willing to accept that it's also probably not drastically better, except maybe when it comes to undefined behaviour. Zig is more of an unknown because it is so different. It has the potential to be worse than C++, but it can also be much better. At the very least, it is very interesting in that it offers a completely new vision for how low-level programming could be done.
I really don't understand why someone would think Rust is "pretty darn similar to C++". I think about my code and data in Rust very differently to C++. C++ doesn't have tagged unions, Rust does. C++ does have inheritance, Rust doesn't. C++ templates are quite unlike Rust generics. Rust enforces safety and (mutable XOR shared), C++ doesn't. All of these lead to quite different design decisions for same-shaped problems.
You're looking at the details, while I look at the overall "feel" and find them almost indistinguishable. They're both low-level languages -- and so, like all low-level languages, suffer from low-abstraction, i.e. the difficulty to hide internal implementation details from consumers behind APIs -- that decided to invest their complexity budget to get the appearance of high-level code once you read it on the page (while the difficulty of changing it is the same as with all low-level languages), and don't hesitate to employ a fair bit of implicitness, grow a large set of features, and let compilation be slow. The details of how they do that are less important; what's most apparent is their shared design philosophy of low-level programming (although I think that Rust improves on C++ and certainly cleans it up). Zig offers a radically different approach, and one that is also radically different from C's philosophy.
I don't think your critiques are accurate, but anyway, the "similarity" here is that you have the same high-level critique of both languages. This does not make Rust "pretty darn similar to C++".
For me, memory and data-race safety and absence of undefined behavior are critical features, but it would be misleading if I were to go around saying "C, C++ and Zig are all pretty darn similar".
> the "similarity" here is that you have the same high-level critique of both languages.
The similarity is that they both espouse the very same design philosophy for low-level programming. It's a pretty big similarity.
> For me, memory and data-race safety and absence of undefined behavior are critical features, but it would be misleading if I were to go around saying "C, C++ and Zig are all pretty darn similar".
It would be misleading, because memory safety and undefined behaviour in Zig is much closer to Rust than to C++. Even where it's not the same as Rust, it's still very different from C/C++. Safety and correctness are as emphasised in Zig as in Rust; they just go about achieving them differently. It is not clear at all which of them achieves correctness better.
> Safety and correctness are as emphasised in Zig as in Rust
This is so far from true I cannot take you seriously.
Zig doesn't have any kind of lifetime analysis, so it's as vulnerable to use-after-free/dangling pointers as C and C++ are. That alone rules out Zig from ever being considered "memory safe" in any meaningful sense.
[Yes, I'm aware of GeneralPurposeAllocator, but that is not something you want to ship in production. "Never reuse any virtual address space" is a disaster for the OS (VMA fragmentation, TLB shootdown IPIs) and the hardware (TLBs, caches). That's why no-one ships such a thing in production for C/C++. GeneralPurposeAllocator will no doubt be useful for debugging (though less effective than ASAN or Valgrind) but safety in production is the game here; ASAN doesn't make C/C++ "memory safe".]
Zig also allows data races so Zig programs can have undefined behaviour via data races on non-atomic values. Again, this cannot be fixed.
Even smart pointers (e.g. reference counting) are nasty in Zig. Zig doesn't have destructors so cleaning up an owning pointer or a refcounting pointer requires developers to write manual "defer" statements. Worse, these only work at function scope so you also have to write manual cleanup code for every data structure containing a smart pointer. Without idiomatic smart pointers Zig will likely be more prone to UAF bugs (and leaks) than C++.
You've misunderstood. There is no doubt that Rust eliminates more undefined behaviour than Zig (though not completely), but it does it at the cost of harming other aspects of correctness. Zig does not try to eliminate UB as much as Rust, but it focuses more on reducing other types of bugs. At the end of the day, you don't care if your program fails due to UB or another bug, and it is unclear which approach results in more correct programs overall.
> you don't care if your program fails due to UB or another bug,
Actually you do, because memory safety bugs are more likely to be exploitable than some arbitrary correctness bug, because they can be weaponized to take full control of the program.
The reality is that UAF/dangling pointers are a major source of CVEs in mature software. Rust prevents those in practice, Zig doesn't. You think Zig is going to be much better than Rust at preventing other kinds of bugs. I see zero evidence of that.
I don't think Zig is going to be better than Rust at preventing other bugs. I don't know. No one knows. Software correctness is a very tricky thing about which we don't know much more than we know. UB are a cause of many bugs, and Zig eliminates many kinds of UB; Rust eliminates more. But Zig is also better at things we also know reduce bugs: simple semantics with simpler analysability, and shorter turnaround, which means more tests. In formal methods research we also have an analogous choice of approaches: more soundness at the cost of higher complexity and effort or vice-versa. There is no point hypothesising about which works better because even the experts have no idea, and it's certainly possible they are about even. The only thing that can settle this is empirical research.
Again, you misunderstand. Both Zig and Rust have much less UB than C. The delta between Rust and Zig comes at a cost to language simplicity and to more testing. You're guessing that that cost's negative impact on correctness is smaller than that positive delta. It's a reasonable guess, but so is the opposite one, and neither is more proven than the other, which would be my guess (while I don't write safety-critical code these days, I worked on safety-critical realtime software where a bug or even a later response could cost the lives of many people; in such correctness-critical domains C is preferred over C++ despite being less safe), although I would even more confidently bet that the real difference, whichever way, is small.
This is what C++98 did, except they called their one true comptime evaluation construct "templates", and they did it by accident. There's a reason why Rust introduced generics and typeclasses separately: C++98 templates as bespoke comptime evaluation was a disaster, and this was clear already in the C++ community.