How can we support/encourage you? (in case you need it)
Defer is useful for code clarity in many situations IMHO, and it's easy enough for a project or code QA tool to ban its use for those that don't like it.
The argument against "Why dont they just fix X?" usualy commes down to: it would break millions of lines of code, make every C tutorial/book obsolete and force millions of C programmers to learn new things, not to mention that if we broke the ABI, we would break almost every other language since they depend on Cs stable ABI. Breaking C would literaly cost tens if not hundreds of billions of dollars for the industry.
Look at the move between Python 2 and 3. The cost of breaking bakwards compatibility have probably been astonomical, and then there is way less Pyton code being maintained then C code.
C operates on a scale that is almost unfathomable. A 1% perfomance degredation, in C will have ameasurable impact on the worlds energy use and co2 emissions, so the little things really matter.
C is "simple" in the same way DNA is "simple". There is a small set of very straightforward rules, but that set provides immense flexibility. But it in no way means that any resulting object will not be complicated. Perhaps a better word than "simple" would be "non-complex", making the distinction between "complex" vs "complicated" systems.
By contrast, the features you refer to would increase the "complexness" of the language (I won't even dare use the grammatically correct word "complexity" here, lest we deviate into yet another trap of conflating definitions).
Which, I would agree with OP is, for better or worse, probably far outside C's goals as a language.
You can get into pointer and memory errors in C++, Rust and Ada. All of them low-level system languages. Sure, those errors might be harder to produce, but not impossible, and definitely easy enough to still trip you up.
I programmed in all of those languages, except Rust (just don't like it). At least in C you pretty much now WHY (not necessarily where in the code) things went south, without consulting a thousand page specification or having to remember the myriad of language feature interactions that could have triggered those problems.
Moreover, C being small, it's a good on/off language. Try doing a code review for a C++/Rust/Ada code base which uses features heavily after not having touched the language for a year. I bet it is not as easy as C.
You know, some things in life are just hard. And low-level programming is one of those things. C is only honest about this.
It may be deceptive. Just look at how various compilers or even the same compiler with different options interpret the same C code.
> as explicit as possible
C is not assembler.
Umm, why is typing something like defer (and documenting what it does) different than typing something like goto (and documenting what it does)?
Frankly, not being comfortable with adding safe and efficient abstractions to a language will result in the death of the language (both for spoken languages and also for programming languages).
Because goto is explicitly declaring a control flow where defer causes implicit control flow in code that does not explicity declare it. That's a meaningful difference that the OP was trying to specifically avoid regardless of whether you care about it.
Why is this different than any loop in C? or function without a return? Wouldn’t it be more explicit and very minimal overhead to instead always use a goto at the end of a looping block?
Even tho C allows while loops (as a mistake - all control flow should be explicitly defined at the end of the block), why aren’t you - as a best practice - using an explicit goto and if block instead of while / for?
Because it's non-local control flow. Did you just ignore my whole comment where I pointed out where cases like exit() unwinds the stack, invoking deferred block in each caller up the call chain back to the root? Does for/while do that?
> invoking deferred block in each caller up the call chain back to the root
Yes if the caller writes N defers in the same function or across M functions then the code will run N defers.
Why is this any different than nesting N loops, in the same function or across M functions? It’ll still run N end of block control flow statements without them being “explicit”.
At the end of the day “explicit” typically is really just a replacement for saying “familiar with the previous documentation, don’t change things”.
Anyways, that’s all I can put into this conversation. Please just try to consider that you’re conflating familiarity with simplicity and leverage System 2 to really ask yourself if what you’re favoring is valuable to the group or just the NIMBY.