Personally, I have nothing against the emergence of new programming languages. This is cool:
- the industry does not stand still
- competition allows existing languages to develop and borrow features from new ones
- developers have the opportunity to learn new things while avoiding burnout
- there is a choice for beginners
- there is a choice for specific tasks
But why do most people dislike the C language so much? But it remains the fastest among high-level languages. Who benefits from C being suppressed and attempts being made to replace him? I think there is only one answer - companies. Not developers. Developers are already reproducing the opinion imposed on them by the market. Under the influence of hype and the opinions of others, they form the idea that C is a useless language. And most importantly, oh my god, he’s unsafe. Memory usage. But you as a programmer are (and must be) responsible for the code you write, not a language. And the one way not to do bugs - not doing them.
Personally, I also like the Nim language. Its performance is comparable to C, but its syntax and elegance are more modern.
And in general, I’m not against new languages, it’s a matter of taste. But when you learn a language, write in it for a while, and then realize that you are burning out 10 times faster than before, you realize the cost of memory safety.
This is that cost:
Firstly, I’m not sure where you got the impression that Rust is designed to replace C. It’s definitely targetted at the C++ crowd.
The string comparison with Rust actually points out one of my problems with C: All those Rust types exist for a reason - they should behave differently. That means that in C these differences are hidden, implicit and up to the programmer to remember. Guess who is responsible for every bug ever? The programmer. Let’s go through the list:
&str - a reference to a UTF-8 string on the stack, hence fixed size.
String - a handle to a UTF-8 string on the heap. As a result, it’s growable.
&[u8] - a reference to a dynamically sized slice of u8s. They’re not even ASCII characters, just u8s.
&[u8;N] - a reference to an array of u8s. Unlike above they have a fixed size.
Vec - a handle to a heap-allocated array of u8s.
&u8 - a reference to a u8. This isn’t a string type at all.
OsStr - a compatibility layer for stack-allocated operating system strings. No-one can agree on what these should look like - Windows is special, as usual.
OsString - a compatibility layer for heap-allocated OS strings. Same as above.
Path - a compatibility layer for file paths, on the stack. Again, Windows being the special child demands special treatment.
PathBuf - a heap-allocated version of Path.
CStr - null-terminated stack-allocated string.
CString - null-terminated heap-allocated string.
&'static str - a string stored in the data segment of the executable.
If you really think all of these things ahould be treated the same then I don’t know what to tell you. Half of these are compatibility layers that C doesn’t even distinguish between, others are for UTF-8 which C also doesn’t support, and the others also exist in C, but C’s weaker type system can’t distinguish between them, leaving it up to the programmer to remember. You know what I would do as a C dev if I had to deal with all these different use cases? I would make a bunch of typedefs, so the compiler could help me with types. Oh, wait…
I dislike C because it plays loosey-goosey with a lot of rules, and not in an opt-in ‘void*’ kind of way. You have to keep in your head that C is barely more than a user-friendly abstraction over assembly in a lot of cases. 90% of the bugs I see on a day to day basis are integer type mismatches that result in implicit casts that silently screw up logic. I see for loops that don’t loop over all the elements they should. I see sentinel values going unchecked. I see absolutely horrible preprocessor macros that have no type safety, often resulting in unexpected behaviour that can take hours or days to track down.
These are all problems that have been solved in other, newer languages. I have nothing personal against C, but we’ve had 40+ years to come up with great features that not only make the programmer’s life easier, but make for more robust programs too. And at this point the list is getting uncomfortably long: We have errors as types, iterators, type-safe macro systems, compile-time code, etc… C is falling behind, not just in safety, but in terms of ease of use as well.
Correction:
str
is not really stack-allocated, it rather is a fat pointer (i.e. pointer + length) to a string somewhere (on the heap or in the binary).Edith: replaced heap with stack
I never said str is heap-allocated. I’m presuming you meant stack when you said heap (or you meant String when you said str)?
You’re right, I meant stack.
str
is not like anu8
array, but a pointer.That’s fair. Because I explicitly mentioned &'static str later on, my explanation of &str implicitly assumes that it’s a non-static lifetime str, so it isn’t stored in the executable, which would only leave the stack. I didn’t want to get into lifetimes in what’s supposed to be a high-level description of types for non-Rust programmers, though. I mentioned ‘stack’ and ‘heap’ explicitly here because people understand that they mean ‘fast’ and ‘slow’, respectively. Otherwise the first question out of people’s mouths is ‘why have a non-growable string type at all??’.
Thank you for your answer. I am not a professional C developer. I am learning it just for myself and have no production products written in C. And I can imagine how difficult is to support something really huge and commercial. Now C is more for hobby developing and tooling. But I know guys who are making desktop apps in C just for performance.
C is in no way “more for hobby developing and tooling”. It’s still foundational to compilers, language runtimes, and operating systems (the Linux kernel was, famously, exclusively written in C up until extremely recently, and the non-C parts are still optional). It’s also the only supported language on many embedded devices.
My question when I see responses like this is: what genuinely useful new safety features have been added since Ada? It’s ancient and has distinct types, borrow checking (via limited types), range types, and even fixed point types. I’ve always wondered what niche Rust is targeting that Ada hasn’t occupied already. It feels like devs decided that safety was important, c/c++ are too unsafe, need a new language; without ever having looked to see if such a language exists?
I haven’t used Ada myself, but I have heard it brought up before. One of the huge advantages Rust has is it’s packaging, versioning and build system. I’d argue this is second to none.
Rust is GPL licensed. As I understand it, licensing was a major blocker for Ada and potentially hampered it’s uptake in the past.
Rust has modern sensibilities, like first-class iterator support, or built-in UTF-8 strings, etc… It also has a lot more of a functional style, rather than procedural.
More subjectively, Ada’s syntax looks very… unflattering to my eyes. I much prefer Rust in that regard. Looking at Ada reminds me of my time with VHDL, which is never a flattering comparison.
Ada actually found itself implementing Rust’s ownership and borrowing system, as pointers were not formally verifiable using SPARK before, so Rust must be doing something right!
Ada is still “new” compared to C, so I suspect the OP would have similar problems with it.
The question of what advantages Rust has over Ada is a good one, but I think it’s been pretty well discussed already. Just a quick google for “Rust vs Ada” turns up lots of discussions.
I don’t know Ada, and I love Rust, but it seems entirely plausible that the reasons for Rust’s greater popularity is primarily social rather than technical. Before I learned about Rust, my impression from talking to more experienced C++ programmers was that Ada was an interesting language with good ideas that was ruined by being “designed by committee.” Rust is at least the third major attempt to design a language specifically to draw some of C++'s user base, the other two being D and Ada (there are other examples that are more debatable; e.g. Erlang and Nim). But hey…at least one of them is finally gaining some ground!
yeah if there’s a popular “modern replacement for C” it’d be Go, similar procedural syntax with some functional features + great stdlib + static linking by default + easier concurrency + GC, but the new memory arenas feature looks like they’re open to change and it’s moving away from that dumbed down language for Google’s junior devs it used to be known as
I find Go a joy to maintain long term due to the high readability and stability of the language and standard libraries. In that respect I guess it isn’t that dissimilar to classic languages like C or Pascal which can be used to write systems that are maintainable for many years.
On the downside Go has some questionable design decisions. Null pointers and multi-value result, err returns are the result of an inadequate type system. It should not be impossible to dereference a null pointer or access the result if there is an error. With discipline problems don’t crop up that often but this is a solved problem in language design and pushes work onto the programmer that should be handled in the language.
Even with such serious deficiencies Go is still arguably one of the better alternatives to dynamic language like Python of Javascript and gets you most of the benefits of static languages without too much complexity. Having a runtime and garbage collection prevents Go use in libraries consumed by C and other languages and the overhead for calling into C is high. That disqualifies it as a modern C replacement.
The more I play with Zig, the more I like it. I don’t think I could use it for anything I had to support at the moment. Realistically you are forced to develop live at head. Active third party dependencies often won’t compile against stable versions. There aren’t a lot of native libs yet but it really feels like it inherits all of C. There is a lot of stuff to like but it will be a more compelling language when it stabilizes.
I hated the first nine words of this comment, but agree with everything else
Zig also seems interesting. I’m definitely a fan of what I’ve seen of their error handling. Intercompatibility with C (no FFI required) also sounds tempting, especially if I already had a legacy C codebase I wanted to migrate.
C is a nice language but performance is the least of the concerns for most development and prioritizing it above, for instance, readability is one of the biggest error you can make as a developper. C is not very strong at being readable. For instance as you said a
char*
can be anything in any format from binary media stream to text in random encoding. Also char* does not have the same meaning across various architecture. So good luck to be sure of what is happening. So I think it’s good to let C where it’s good at, low level softwares with performance as first requirement (forget about safety though) and with very senior people as developper.This is not a correct comparison as rust strings support UTF8. Try doing that with char*!
uint32_t* goes brrr
That’s not utf8 either…
max width of utf8 is 32 bits from my extensive research (1 minute of googling) so it should work, right?
UTF-8 is a variable encoding so none of the fixed sized type would work better for it.
But it would work
It would no longer be UTF-8; it would be UTF-32. UTF-8 is an encoding scheme, meaning that it is a specification for exactly how text is encoded as bits.
You can certainly use UTF-32 to represent all valid unicode, but you can only do that within the bounds of a single program; once you need to read or write data to or from an external source (say, the file system, or over a network), you’d need to use the same encoding that the other software uses, which is usually UTF-8 (and almost never UTF-32).
you are responsible for the code you write
https://9to5google.com/2022/12/01/android-memory-safety-rust/
Who benefits from C being suppressed and attempts being made to replace him? I think there is only one answer - companies. Not developers.
You’ve missed the group that is most affected by software quality: end-users. Almost everyone in the world relies on computers in some way now, and bugs, especially security vulnerabilities, affect people who have no say in what languages people use to develop software.
But you as a programmer are (and must be) responsible for the code you write, not a language. And the one way not to do bugs - not doing them.
Sounds good. How do I, the end-user of software, hold developers accountable for bugs? I guess I can switch from one buggy operating system to another, or from one buggy browser to another.
But also, do you honestly think that the choice of language does not impact software quality at all? Surely if you were forced to write software in a raw assembly, you’d find it more difficult to write a large and complex system correctly; right? But assembly is just another language; what makes C easier to use correctly? And if C is easier to write correctly than assembly, why would it be surprising that there are languages that are even easier to write correctly, especially after five decades of development in the extremely young field of computer science? Tools are important; your programming language (and compiler) is your first, most important, and most impactful tool as a developer.
[C] remains the fastest among high-level languages.
How are you determining that? C, C++, Rust, Fortran, Ada, and D all compile down to machine code, with no garbage collector (D’s is optional). So there’s not really any theoretical reason why they shouldn’t all perform roughly the same. And, in fact, this is largely supported by evidence:
- There’s a fair amount of competition among
grep
type tools.grep
itself is written in C and heavily optimized. I think it’s fairly well known by now thatripgrep
, written in Rust, is probably the fastest of these tools. - The TechEmpower web framework benchmarks maintains a ranking of the fastest web frameworks, updated each year. It doesn’t look like the current version of the site shows what language each framework is written in, but the top three (
may-minihttp
,xitca-web
, andntex
) are all Rust projects. The fourth (h2o
) is in C. - The Benchmarks Game lets people submit programs in a wide variety of languages to solve a variety of problems, and these submissions are benchmarked and compared. Rust and C are effectively neck-and-neck (note that Rust currently does actually beat C in several of the challenges). See the second graph here for an overall visual comparison among languages.
[Side-note: no one is “suppressing” C. I’m also not convinced anyone thinks C is “useless”.]
Thank you for answer. You helped me.
Why did you forgot Nim? Is it a player?
Oh, Nim is possibly even a better example because it is “transpiled” rather than compiled, meaning the compiler actually generates C or C++ code. You can then compile that with whatever compiler you want. However, I don’t know of any major projects in Nim to compare against ones in C, C++, Rust, etc.
Edit: and Zig should be extremely efficient as well.
- There’s a fair amount of competition among
another language that seems to get close to “C replacement” is Odin. Though it also does feel like departing a bit too much sometimes to be a true replacement.
And what every new language seems to be dead set on is no implicit type conversions which is mildly annoying (But I suppose that’s done specifically to protect from gremlins like me)
The creator of Odin has stated that it is not aiming to replace C. It’s its own thing. I suppose it has some degree of overlap, but I don’t know the language well enough to speak on the differences. One thing I have read is that it does not support embedded devices very well.
He said this in the comments of a youtube interview:
I think my idea of “C replacement” probably fits fairly closely with Odin’s creator’s idea of “C alternative”…
It’s of course impossible to truly replace C with anything since C is an extremely entrenched language what with it being widely used for about 50 years. (and odin probably won’t fit every niche where C is used)
I’m convinced the people who complain about C are actually C++ devs who never learned standalone C so they just think all the insanity in C++ must be 100x worse in C.
Either that or java devs who think pointers are nuclear bombs lol.
Oh, come on… all C++ devs know C well enough. Nobody assumes C is bad because it is more insane than C++.
C is just awfully repetitive as you have to spell out all the cleanup code all time – and you are likely to have a security issue when you forget it just once.