C also has a runtime, that is what takes care of calling main(), handling VLAs, floating point emulation, constructor/destructors (GCC C extensions), ...
Besides there are plenty of OSes written in type safe system languages to learn from, including surviving mainframe OSes.
The operative word here is managed runtime. Jvm wants to completely own your program, heart and soul. You can also write freestanding code in c (and rust, d, zig I assume although I don't know enough about it). I believe there is a dialect of c# that allows you to write freestanding code, but it's not really c# so much as c#-flavoured c with some extra features, so it's inferior to other c alternatives.
I feel much of the negativity that you like to express towards C is unwarranted. Fact is, it's both very easy and efficient to interface with "C" or more specifically, platforms' standard ABIs.
That Quora post is really only relevant when using Java applets. If you're running a local program, you're faced with similar vulnerabilities as with any other language with a managed runtime. Still doesn't make it relevant as a competitor to C or C++.
It has a sane subset which is basically C with a slightly saner syntax than C (the begin...end and lacking data initialization syntax are terrible though!), and with a proper module system and much better compile times.
On the other hand, it was crippled by missing a usable preprocessor and an ecosystem that has bought into each hype since the 90's, resulting in 23 incompatible kinds of strings, 101 different dynamic arrays, and about 5 (really) incompatible object models with different kinds of memory management. Programmers with many years in the language don't really understand all the ways memory is managed in this language.
Now try writing something on top of the broken RTTI for that. Even official guides basically concede the fact by writing quirky code that easily breaks.
Also you have to declare typealiases for every little thing like pointer-to-types, before you can use that type in a function signature. This alone renders it almost completely unusable for my purposes.
It has a culture of goto-considered-harmful where people like to indent 13 times instead of using return/continue/break, which would yield readable control flow. If you want to return something, you need to write two lines - assigning to the result and calling exit(). You can't call exit() though when the current class has a method called exit(), since that method is closer in scope (REALLY REALLY WEIRD).
I know what I'm talking about. I've been paid to work in it, and refactored a subsystem written in idiomatic Delphi to be halfway maintainable, achieving real speedups of 100-1000x by following a straightforward "data-oriented" approach, just like I would write it in C, writing complicated code only where the straightforward approach was not feasible in the language. Despite completing the project successfully (there hasn't been a single problem since the rewrite), in the end I was burnt out due to having to work with the original code. Didn't work for 5 months afterwards.
Except for when I write Assembly, the last time I used raw goto on an high level language, my MS-DOS 5.0 box was still relatively new.
System.exit was always a thing to avoid namespace clashes and since Delphi 2009, you could have used System.exit(value) instead. Next time better read the docs.
Regarding strings, you mean like 8 bit, 16 bit, wchar_t, DBCS, GString and many others used across C libraries?
Nominal typing is much safer for large scale engineering than type aliases, which don't provide a mechanism to prevent incorrect usage of types.
Do you suggest I should use System.exit everywhere (even though all the code you find on the net uses just "exit")? Just to be sure that Delphi will never ever choose the wrong function to call WHICH IT SHOULD NEVER HAVE DONE IN THE FIRST PLACE OMG IT'S TOO FRIGGING COMPLICATED PLEASE DELPHI APPLY SOME COMMON SENSE.
It's beyond me why I should write a function call and incur symbol resolution for such basic control flow in the first place.
> the last time I used raw goto
I was mainly speaking about return, break, continue, which don't seem to be popular in Delphi. Examples of Delphi code that isn't a messy nesting fest? As for goto, there are perfectly valid uses for it, in fact some where goto is the clearest and most maintainable choice when you simply skip downwards over a chunk of code without requiring an extra flag.
> Regarding strings
I'm talking about the culture. The culture around C is not one that makes anti-modular "abstractions" (at least if you stay away from MS). You will never see me using wchar_t, GString or any of that god-awful Microsoft string mess. I get along just fine with only char. In fact, the string handling I get by using C is the most painless, most modular I've ever gotten in any language. (No, I don't want to use split() or use any other high-level stuff that would do allocations when that isn't necessary).
In Delphi, different story. Everything you find in this culture is built around String and AnsiString and UnicodeString and WideString and what not. Try googling how to access command-line parameters. The stuff is pervasive. Entirely different story.
> Nominal typing is much safer for large scale engineering than type aliases, which don't provide a mechanism to prevent incorrect usage of types.
Exactly, typealiases are bad. And now explain to me why Delphi forces me to make a type alias (for use in function signatures) when that is worse than immediate Pointer syntax in every conceivable aspect? (Having written a compiler I know the answer: because it requires less code in the compiler to check for type equality).
So I guess I should just avoid pointers altogether and use only GC'ed boxed OOP NOMINAL types. And finally have some time for coffee again while my application takes 5-10 minutes to start up (as it did before I reworked the thing), instead of 1 sec.
Besides there are plenty of OSes written in type safe system languages to learn from, including surviving mainframe OSes.