This is one the reasons I find it so silly when people disregard Zig «because it’s just another memory unsafe language»: There’s plenty of innovation within Zig, especially related to comptime and metaprogramming. I really hope other languages are paying attention and steals some of these ideas. «inline else» is also very powerful tool to easily abstract away code with no runtime cost.
If you make advancements but disregard the advancements that came before you, you have a research language, not a modern usable language.
Partially Matching Zig Enums
81–90 of 170 posts
Re: Partially Matching Zig Enums
#82It is great to see other languages getting the same compile-time meta programming features as C ;-) https://godbolt.org/z/P1r49nTWo
I think Zig gets some points here for legibility ;-).
Re: Partially Matching Zig Enums
#83Is there a reason the Zig compiler can't perform type-narrowing for `u` within the `U::A(_) | U::B(_)` "guard", rendering just the set of 2 cases entirely necessary and sufficient (obviating the need for any of the solutions in the blog post)? I'm not familiar with Zig, but also ready to find out I'm not as familiar with type systems as I thought.
I think the post would be more helpful if it had a concrete use case. let's say a contrived bytecode VM:
dispatch: switch (instruction) {
inline .load, .load0, .load1, .load2, .load3 => |_, tag| {
const slot = switch (tag) {
.load => self.read(u8),
else => @intFromEnum(tag) - @intFromEnum(.load0),
};
self.push(self.locals[slot]);
continue :dispatch self.read(Instruction);
},
// ...
}
"because comptime", this is effectively the same runtime performance as the common: dispatch: switch (instruction) {
.load => {
self.push(self.locals[self.read(u8)]);
continue :dispatch self.read(Instruction);
},
.load0 => {
self.push(self.locals[0]);
continue :dispatch self.read(Instruction);
},
.load1 => {
self.push(self.locals[1]);
continue :dispatch self.read(Instruction);
},
.load2 => {
self.push(self.locals[2]);
continue :dispatch self.read(Instruction);
},
.load3 => {
self.push(self.locals[3]);
continue :dispatch self.read(Instruction);
},
// ...
}
and this is in a situation where this level of performance optimization is actually valuable to spend time on. it's nice that Zig lets you achieve it while reusing the logic.Re: Partially Matching Zig Enums
#84Earlier quoted context omitted.
Right but I think people are disappointed because we finally got a language that has memory safety without GC, so Zig seems like a step backwards. Even if it is much much better than C (clearly), it's hard to get excited about a language that "unsolves" a longstanding problem. > not even Java, is truly "fully memory safe", as programs continue to employ components not written in memory safe languages. This is a silly…
> I think people are disappointed because we finally got a language that has memory safety without GC, so Zig seems like a step backwards Memory safety (like soundly ensuring any non-trivial property) must come at a cost (that's just complexity theory). You can pay for it with added footprint (Java) or with added effort (Rust). Some people are disappointed that Zig offer more safety than C++ but less than Rust in exc…
... or runtime errors (C, Zig presumably).
Ok Zig is clearly better than C in that regard but I think it remains to be seen if it is better enough.
> many Rust programs do use GC (that's what Rc/Arc are)
This is not what most people mean when they say GC.
> Why?
Because when we're talking about the memory safety of a language we're talking about the code you write in that language (and excluding explicit opt-in to memory unsafe behaviour, e.g. `unsafe` or Python's `ctypes`).
Saying "Java isn't memory safe because you can call C" is like saying "bicycles can fly because you can put them on a plane".
Re: Partially Matching Zig Enums
#85Earlier quoted context omitted.
> Zig is safer than C++ Maybe if someone bends over backwards to rationalize it, but not in any real sense. Zig doesn't have automatic memory management or move semantics. In C++ you can put bounds checking in your data structures and it is already in the standard data structures. You can't build RAII and moves into zig.
> Maybe if someone bends over backwards to rationalize it, but not in any real sense. In a simple, real sense. Zig prevents out-of-bounds access just as Rust does; C++ doesn't. Interestingly, almost all of Rust's complexity is invested in the less dangerous kind of memory unsafety ( https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html ). > You can't build RAII and moves into zig. So RAII is part of the defini…
Then why do my data structures detect if I go out of bounds?
Interestingly, almost all of Rust's complexity is invested in the less dangerous kind of memory unsafety
I didn't say anything about rust.
So RAII is part of the definition of memory safety now?
Yes. You can clean up memory allocations automatically with destructors and have value semantics for memory that is on the heap.
Why not just declare memory safety to be "whatever Rust does", say that anything that isn't exactly that is worthless, and be done with that, since that's the level of the arguments anyway.
Why are you talking about rust here? Focus on what I'm saying.
We could, of course, argue over which of Rust, Zig, and C++
if anything, it's become more, not less, mysterious over the decades
Says who?
I don't care about rust or zig, I'm saying that these are solved problems in C++ and I don't have to deal with them. Zig does not have destructors and move semantics.
Re: Partially Matching Zig Enums
#86Earlier quoted context omitted.
If you make advancements but disregard the advancements that came before you, you have a research language, not a modern usable language.
By this definition, every major programming language in use today (C, C++, Java, Python, ...) is merely a research language.
Re: Partially Matching Zig Enums
#87Earlier quoted context omitted.
I was trying to implement this trick in D using basic enum, but couldn't find a solution that works at compile-time, like in Zig. Could you show how to do that?
import std.meta: AliasSeq; enum E { a, b, c } void handle(E e) { // Need label to break out of 'static foreach' Lswitch: final switch (e) { static foreach (ab; AliasSeq!(E.a, E.b)) { case ab: handleAB(); // No comptime switch in D static if (ab == E.a) handleA(); else static if (ab == E.b) handleB(); else static assert(false, "unreachable"); break Lswitch; } case E.c: handleC(); break; } }
Re: Partially Matching Zig Enums
#88Earlier quoted context omitted.
> Maybe if someone bends over backwards to rationalize it, but not in any real sense. In a simple, real sense. Zig prevents out-of-bounds access just as Rust does; C++ doesn't. Interestingly, almost all of Rust's complexity is invested in the less dangerous kind of memory unsafety ( https://cwe.mitre.org/top25/archive/2024/2024_cwe_top25.html ). > You can't build RAII and moves into zig. So RAII is part of the defini…
C++ doesn't. Then why do my data structures detect if I go out of bounds? Interestingly, almost all of Rust's complexity is invested in the less dangerous kind of memory unsafety I didn't say anything about rust. So RAII is part of the definition of memory safety now? Yes. You can clean up memory allocations automatically with destructors and have value semantics for memory that is on the heap. Why not just declare m…
I didn't mean you can't write C++ code that enforces that, I said C++ itself doesn't enforce it.
> Yes. You can clean up memory allocations automatically with destructors and have value semantics for memory that is on the heap.
Surely there are other ways to do that. E.g. Zig has defer. You can say that you may forget to write defer, which is true, but the implicitness of RAII has cause (me, at least) many problems over the years. It's a pros-and-cons thing, and Zig chooses the side of explicitness.
> Why are you talking about rust here? Focus on what I'm saying.
You're right, sorry :)
> Says who?
Says most people in the field of software correctness (and me https://pron.github.io). In the seventies, the prevalent opinion was that proofs of correctness would be the only viable approach to correctness. Since then, we've learnt two things, both of which were surprising.
The first was new results in the computational complexity of model checking (not to be confused with the computational complexity of model checkers; we're talking about the intrinsic computation complexity of the model checking problem, i.e. the problem of knowing whether a program satisfies some correctness property, regardless of how we learn that). This included results (e.g. by Philippe Schnoebelen) showing that even though there would be the reasonable expectation that language abstractions could make the problem easier, even in the worst case - it doesn't.
The second was that unsound techniques, including engineering best practices, have proven far more effective than was thought possible in the seventies. This came as quite a shock to formal methods people (most famously, Tony Hoare, who wrote a famous paper about it).
As a result, the field of software correctness has shifted its main focus from proving program correct to finding interesting confidence/cost tradeoffs to reduce the number of bugs, realising that there's no single best path to more correctness (as far as we know today).
> I'm saying that these are solved problems in C++ and I don't have to deal with them. Zig does not have destructors and move semantics.
That's true, but these are not memory safety guarantees. These are mechanisms that could mitigate bugs (though perhaps cause others), and Zig has other, different mechanisms to mitigate bugs (though perhaps cause others). E.g. see how easy it is to write a type-safe printf in Zig compared to C++, or how Zig handles various numeric overflow issues compared to C++. So it's true that C++ has some features we may find helpful that Zig doesn't and vice-versa, we can't judge which of them leads to more correct programs. All I said was that Zig offers more safety guarantees than C++, which it does.
Re: Partially Matching Zig Enums
#89Earlier quoted context omitted.
C++ doesn't. Then why do my data structures detect if I go out of bounds? Interestingly, almost all of Rust's complexity is invested in the less dangerous kind of memory unsafety I didn't say anything about rust. So RAII is part of the definition of memory safety now? Yes. You can clean up memory allocations automatically with destructors and have value semantics for memory that is on the heap. Why not just declare m…
> Then why do my data structures detect if I go out of bounds? I didn't mean you can't write C++ code that enforces that, I said C++ itself doesn't enforce it. > Yes. You can clean up memory allocations automatically with destructors and have value semantics for memory that is on the heap. Surely there are other ways to do that. E.g. Zig has defer. You can say that you may forget to write defer, which is true, but th…
And C has free, but you have to remember to use it and use it correctly every single time instead of the memory working by default with no intervention.
Says most people in the field of software correctness
Not true, the last 30 years have had much safer languages than before java, scripting languages, modern C++ and rust.
That's true, but these are not memory safety guarantees.
Pragmatically they mean you don't have to worry about bounds checking or memory deallocation and it stops being a problem. Zig doesn't have this and it doesn't have safety guarantees either.
Re: Partially Matching Zig Enums
#90It is great to see other languages getting the same compile-time meta programming features as C ;-) https://godbolt.org/z/P1r49nTWo
I didn't know godbolt let you include URLs. Fascinating: https://raw.githubusercontent.com/uecker/noplate/main/src/co... I think Zig gets some points here for legibility ;-).