The thing for me at least is that when I looked at Pascal, MODULA-2, Ada, if you had complex data structures which had to allocate and deallocate memory, then those language would not help at all. They would allow you to make pointer mistakes. Pascal and MODULA-2 were also very restrictive in various area (no generics). Ada is better in that respect, but Ada compilers were rare.
In my opinion it is only Rust that offers a language without runtime system requirement and fixes essentially all of the problems of C.
First of all C did not had any generics, so same playing field.
C has a runtime, even if tiny. That is what calls into main(), handles floating point arithmetic when none is available, functions that run before and after main(), nowadays also does threading.
Heap memory handling in Pascal, Modula-2, Ada, is much safer than C, first of all no need to do math to calculate the right size, arenas are available on the standard library, dinamic allocation can also be managed by the compiler if desired (Ada), pointers are safe as they by default must be used with existing data, however if one really wants to do pointer arithmetic it is available.
The only issue that they have in regards to C, is the use-after-free, but that apparently isn't an issue for folks moving away from C into Zig, wich is basically Modula-2 with some C syntax flavour.
C uses pointer casts all over the place to fake generics. If you don't have that (in Pascal or MODULA-2) then life becomes very unpleasant.
There is a quite a bit of C code that makes creative use of the size of allocations. For example linked lists with a variable sized payload. Again one of the things that would prevent a C programmer from switching to Pascal.
I don't expect the Zig user base to become larger than the Rust user base any time soon. But we have to wait and see, Zig is quite young.
> C uses pointer casts all over the place to fake generics.
by "C" do you mean users of C? because most of the C code I write I don't use those sorts of techniques; instead I just use the preprocessor to make scuffed generics.[1] Unless you mean in libc itself, where I don't recall any use of pointer casts like that? If I'm missing something, please enlighten me.
Same tricks are possible in Modula-2, Pascal, Ada, if fake generics count.
Creative use of the size of allocations are also possible in those languages, the BIG difference is that they aren't the default way everything gets done.
In Pascal (not the original Pascal standard, but, say, Turbo Pascal), could you allocate a variable-sized array of something, and still have index protection when using it?
(I know quite well that C couldn't. Even a C++ vector may or may not, depending on which access method you use.)
In my opinion it is only Rust that offers a language without runtime system requirement and fixes essentially all of the problems of C.