I guess that there is some small truth to your allusion to the static-vs-dynamic debate, but Zig does give you errors at compile-time, and elaborate things it can check at runtime are much easier to express than in Rust. But I would say that Rust is a language in a well-known tradition, and is clearly a "cleaned up C++", while Zig is something that we haven't seen before. It is not dynamic in the same sense as dynamic languages -- you get the checks done at compile-time -- but it is not part of the familiar tradition of typed languages or even any low-level language.
I'm not a devout minimalist, but when it comes to low-level programming in particular, language simplicity is a very important feature, and before Zig it wasn't clear it was achievable at all in low-level languages without significantly compromising on expressivity and safety.
I agree that comptime is not the same thing as Rust macros, I mostly mentioned Rust macros because I felt it was a gotcha to my argument since my criticisms of Zig's comptime could be levied at Rust's macros.
To be a little more specific in my criticism, the fact that Zig implements generics with comptime is a bit of a red flag for me. I worry, perhaps unreasonably, that it's going to lead to fragmentation in the way generics are handled in various libraries, leading to headaches and incompatibilities. It is a smart solution, but I wonder if it's a pragmatical solution.
It's definitely an interesting approach at any rate, it's great to see all this creativity in systems language. I don't want to sound too critical of Zig, it's a cool language.
> my criticisms of Zig's comptime could be levied at Rust's macros.
Except that comptime is nothing at all like macros, even though, as it turns out, it can replace enough of their use to make them unnecessary in low-level languages.
> I worry, perhaps unreasonably, that it's going to lead to fragmentation in the way generics are handled in various libraries, leading to headaches and incompatibilities.
But generics in Zig are just functions, and so the problem should be no better but no worse than any API. comptime is drastically less "crazy" or "weird" or hard to make compatible than macros, which Zig doesn't have at all.
Where they differ: memory safety, sum types (don't tell me std::variant is a valid replacement), move semantics, having pointers, classes, GC vs RAII, statement vs expressions... That's a lot of differences.
What do you mean 'beyond'? It's not like there are many other languages that have compile-time polymorphism. (Java, Go, C, etc., don't.)
> memory safety, sum types (don't tell me std::variant is a valid replacement), move semantics, having pointers, classes, GC vs RAII, statement vs expressions... That's a lot of differences.
ML ignores the real performance and architecture considerations, so yeah, of course it is a simpler and more 'elegant' language. As a teaching aid, yeah, I think all C++ programmers should be forced to program something in an ML-derived language.
But once you start handling the real-world edge cases and requirements you'd end up in a place very similar to C++.
Java does, it's called generics. Also D, rust, Ada, free pascal, nim, and most statically typed languages from the last 3 decades (even Go is finally getting them ). Still can't see why C++ is closer to ML than C, since it's literally an almost compatible superset of C.
No, Java is still pointers to Object and dynamic dispatch under the hood. Generics didn't change this at all.
> Still can't see why C++ is closer to ML than C, since it's literally an almost compatible superset of C.
ATS is also 'literally an almost compatible superset of C'.
I think the idea that zig is a very sharp knife is true, but the overlap of footguns and comptime is not as big as one would think (@fieldParentPtr mistakes comes to mind, but that's sort of about it)
TANSTAAFL. Compile-time evaluation cannot truly "permeate" a language because most practical languages preserve a phase distinction between compile time and runtime. (This phase distinction is somewhat softened, e.g. in interpreted languages as well as in advanced PL's which include such features as dependent types). For a system programming language like Rust which relies on this clear-cut phase separation, macros and proc macros (as well as `const`-marked expressions and functions) are ultimately more elegant.
constexpr is basically making more of C++ available at compile time -- e.g. lots of C++11, 14, 17, and 20 are just allowing more of the language at compile time. Including STL, allocators, etc.
Zig simplifies everything by designing in comptime up front, rather than gradually opening it up with ad hoc rules over 10+ years.
My understanding is that Rust is going down the same path as C++. So you're going to have 2 kinds of macros AND comptime-like/constexpr-like compile time execution.
> Zig simplifies everything by designing in comptime up front, rather than gradually opening it up with ad hoc rules over 10+ years.
I am not 100% sure that I agree with these characterizations, personally, but they're both valid strategies for sure.
Could you give some concrete examples of this?
Unlike C, zig's comptime doesn't have grammar altering abilities
Yes, it makes the language more approachable, yes it makes it easier for people who aren't familiar with the language to understand what's going on. That's nice, but that's not critically important IMO. It's nice if you want to impress people on HN, but if you use the language day-to-day you'll get over that stuff pretty quickly.
On the other hand this type of extreme customization means that even for somebody very familiar with the language you still have to be on your toes because innocuous looking code could behave surprisingly due to comptime shenanigans. On the other hand languages with a more rigid structure may end up being more verbose but that leads to code that a proficient coder can unambiguously understand without having to mentally expand comptime blocks or macros.
This is effectively the metaprogramming equivalent of the statically vs dynamically typed debate. Yes, dynamic code is easier to write but it can be harder to maintain and leads to worse compiler diagnostics and generally requires more unit tests to validate that it's doing the right thing. I think macros/comptime behave similarly when compared to stricter, more limited metaprograming like Rust's generics system.
Rust has macros too of course, but they're a pain to write in my experience, and I'd almost argue that it's a feature. You only use them if you really have to, and after careful consideration, or at least that's how I use them.