It has to do with porting code, generally. If I'm writing original Rust, I rarely miss it. It's not a huge deal, but you bump into it juuuust often enough to (probably unfairly) curse Rust out when you hit it yet again.
Here's code from CMSIS DAP debug probe firmware from ARM: https://github.com/ARMmbed/DAPLink/blob/main/source/daplink/...
Note the nested do { do { } while (); if (err) break;} while(); if (err) break;
Should that code be rewritten? Most certainly it should, and it should be given a proper Error type. However, when you are first porting it, you need to match semantics or you get a bunch of off-by-one, missed error, or missed end of stream bugs. And, as you point out, the Rust loop{} equivalents suck.
We've all written suboptimal code, and we all live in a suboptimal world. :)
do { ... } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort);
becomes something like loop {
...
if data & DAP_Data.transfer.match_mask) == match_value {
break;
}
match_retry -= 1;
if match_retry == 0 {
break;
}
if check_transfer_abort() { // Replaces DAP_TransferAbort
break;
}
}
I think that's actually more clear, and my mental focus is DAP_TransferAbort. I think it's just C programmers being C programmers, and we just want AtomicBool for this but I'm more comfortable wrapping it in this check_transfer_abort() function while I investigate whether anybody thinks this is a counter, or there's actually physical hardware backing it despite the way it looks like it's just a global variable.If we take comptime feature away, Zig is basically Modula-2 (1978) with friendlier syntax for folks with C background.
Everything else in terms of security Modula-2 did better (yes it did have null pointers, but supports null checking).
And the tagging mechanisms for use-after-free are anyway available for C and C++ compilers for at least 20 years (Insure++, PurifyPlus and VC++ 6.0 debug allocator being part of the first ones).
Oh, interesting, I was wondering if this (breaking with both a label and a value) existed (in a different context), and I concluded it didn't exist and so probably nobody had wanted it, but turns out it's in the next version and I didn't hear about it.
I don't understand a desire for do-while, I can't imagine what I might write where that looks reasonable and the loop equivalent in Rust is not very good.
If all you wanted was nicer C then yeah, Zig is that and Rust isn't -- I just don't think "nicer C" is a reasonable goal any more.