4 ms·
Try zig, it is C with a bit of polish.
by kuon 2y ago
Try zig, it is C with a bit of polish.
- sgt 2y agoWhy zig and not Rust? Just to throw the question out there :-)
- kelnos 2y agoZig is a much simpler language than Rust. I'm a big Rust fan, but Rust is not even close to a drop-in replacement for C. It has a steep learning curve, and often requires thinking about and architecting your program much differently from how you might if you were using C. For a C programmer, learning and becoming productive in Zig should be a much easier proposition than doing the same for Rust. You're not going to get the same safety guarantees you'd get with Rust, but the world is full of trade offs, and this is just one of them.
- nyrikki 2y agoFor me, where linked lists, graphs and other structures are a common need, zig gives me slices and deferred frees. Rust is double expensive in this case. You have to memorize the borrow checker and be responsible for all the potential undefined behavior with unsafe code. But I am not a super human systems programmer. Perhaps if I was the calculus would change. But personally when I have to drop down below a GC language, it is pretty close to the hardware. Zig simply solves more of my personal pain points... but if rust matures in ways that help those I'll consider it again.
- codedokode 2y ago> You have to memorize the borrow checker Correct me if I am wrong, but Rust at least has a borrow checker while in C (and Zig) one has to do the borrow checking in their head. If you read a documentation for C libraries, some of them mention things like "caller must free this memory" and others don't specify anything and you have to go to the source code to find out who is responsible for freeing the memory.
- nyrikki 2y agoRust gives two reasons for the borrow checker, iterator invalidation and use after free. As I have always bought into Dennis Ritchie's loop programming concepts, iterator invalidating hasn't been a problem. Zig has defer which makes it trivial to place next to allocation, and it is released when it goes out of scope. As building a linked list, dealing with bit fields, ARM peripherals, etc...; all require disabling the Rust borrow checker rules, you don't benefit at all from them in those cases IMHO. It is horses for courses, and the Rust project admits they chose a very specific horse. C is what it is, and people who did assembly on a PDP7 probably know where a lot of that is from. I personally prefer zig to c... but I will use c when it makes the task easier.
- int_19h 2y agoThe point is that any formal borrow checking will reject perfectly valid patterns because they are impossible to statically prove, and this comes up especially often with data structures like graphs. So you end up struggling against the compiler - either you just go unsafe (in which case you have to be even more careful than in C and Zig because Rust makes more optimization assumptions based on ownership which you're now responsible for), or else you use hacks like using indices instead of pointers to, basically, work around the borrow checker.
- codedokode 2y agoYou are describing the deficiencies of Rust implementation of a borrow checker and disregarding general benefits of it. Obviously there could be some way to mark self-referencing objects. C/Zig do not even allow to specify who is responsible for freeing the allocation, and every time you use a library you need to either search the docs or (more often) reverse-engineer the code. Probably this is why writing or checking C code is so slow. I end up adding annotations to function prototypes but nobody is going to validate them so they only serve as documentation.
- int_19h 2y agoWell, we are comparing real world languages, so of course I'm going to talk about the limitations of the actual checker that Rust has. That said, is there a better (as in fewer false positives without giving up safety) implementation of lifetime tracking out there? I mean, fundamentally, the problem is that the question ultimately boils down to telling what the code will do without running it. C and Zig have exactly the same facility to let you specify who's responsible for allocation - owning vs non-owning types for resources; it's just that you have to write them by hand, and for types that are owning, destructor calls must be done explicitly (but still, the pattern of "if I got an instance of OwnedFoo, I need to call destroy() on it" is much more straightforward then chasing the docs for each function).
- sramsay 2y ago> it is C with a bit of polish. I am fast becoming a Zig zealot. What I've discovered is that while it does regularize some of the syntax of C, the really noticeable thing about Zig is that it feels like C with all the stuff I (and everyone else) always end up building on my own built into the language: various allocators, error types, some basic safety guardrails, and so forth. You can get clever with it if you want -- comptime is very, very powerful -- but it doesn't have strong opinions about how clever you should be. And as with C, you end up using most of the language most of the time. I don't know if this is the actual criterion for feature inclusion and exclusion among the Zig devs, but it feels something like "Is this in C, or do C hackers regularly create this because C doesn't have it?" Allocators? Yes. Error unions? Yes. Pattern matching facilities? Not so much. ADTs? Uh, maybe really stupid ones? Generics, eh . . . sometimes people hack that together when it feels really necessary, but mostly they don't. Something like this, it seems to me, results in features Zig has, features Zig will never have, and features that are enabled by comptime. And it's keeping the language small, elegant, and practical. I'm a big time C fan, and I love it.
- __turbobrew__ 2y ago> and so forth forth, you say?
- codedokode 2y agoI saw mentions of Zig here often, so I decided to look at the docs to see what features it has. I had to scroll through all the docs only to find myself disappointed by the fact that Zig doesn't help with memory management in any way and advices to use comments and careful coding instead. And what adds to the disappointment is that its plus/minus operators do not catch overflow. If I wanted undefined behaviour, I could just use C/C++ as no language can compete with them in this regard.
- somethingor 2y ago> plus/minus operators do not catch overflow They do (in Debug and ReleaseSafe modes)
- codedokode 2y agoWhy not have the same behaviour everywhere? Because they are adapting the language to legacy CPUs not capable of detecting an overflow?