Safe Rust looks absolutely painful painful compared to other safe languages.
Correct C is not actually hard to write. It can be somewhat hard to convince oneself that it's right.
That's an important difference. Not all C has to be correct. If it's experimental or exploratory code that'll be thrown away. If that just works on one machine or on particular inputs that you care about, or it only certain specific environmental conditions, that can be fine.
Correctness is more than just memory safety and avoiding overflows. They are still bugs in programs and languages that avoid those problems.
When people talk about not needing to write much unsafe Rust, they mean that in any large-scale system, there are probably only a couple hotspots that are complicated enough to need the escape hatch from the Rust safety rules; you write the unsafe code, you give it an interface to the rest of the code, you carefully validate the unsafe code, and you're good to go.
They don't mean that you write unsafe Rust code for experimental or exploratory code that will be thrown away. You could do that, but it's not common.
More importantly: this approach of parsimoniously writing unsafe code in a larger-scale safe system does not work in C/C++. Memory safety issues can (and do) crop up all over your system, not just in the small "unsafe" parts you validate carefully.
Writing unsafe Rust is enough of a pain in the butt (partially thanks to some syntactic salt that comes from the early days that probably should be removed but isn't being dealt with any time soon as far as I know) that it would be harder to prototype in unsafe Rust than safe Rust, IMHO.
Needing explicit deref for raw pointers. (*ptr).bar() instead of ptr.bar() like if it ptr was a reference or adding something like ptr~bar() so at least you still know it’s a raw pointer deref but is at least nearly the same as a reference.
That's a valid strategy, but it's harder to write "unsafe-safe" code in C than people think it is. We just did a podcast episode about this with results from the Android team:
Even with careful rules and oversight and secure coding idioms and library exclusions and fuzzing, the rate of memory safety defects in C/C++ code is still pretty high.
I'm not sure I've met anyone with significant application security experience who would claim writing correct C is anything less than very challenging. It's not just memory safety, even basic features like iterable collections make code easier to write while at the same time avoiding potential bugs (vs C for loops in this case).
Security is tricky because correct programs (including in C) can have security problems, like side channel attacks and whatnot.
You can write code which you think erases some security-sensitive information to zero bits after a calcualtion, but the compiler throws it away. The program is perfectly safe in that it doesn't crash on any bad input or miscalculate on any good input, but doesn't meet a security requirement.
The crux is that what the language standard calls "observable behavior", and behavior that can actually be observed (with security implications) are two different things.
All C is unsafe, because it's a property of most language features. E.g. this is unsafe:
int main(void)
{
global_init();
service_loop();
global_cleanup();
}
Some of these functions, defined in another translation unit could require parameters, but their declarations be incorrect or missing from this translation unit. So the program will link, but the behavior is undefined.
"Unsafe" means that "no diagnostic is required when a rule is broken". When correctness depends on the programmer, such that the tooling silently accepts incorrectness, that is unsafe.
Almost all C is unsafe, but not all coding situations are equally risky of having a problem.
Under this valid strategy we minimize writing C. When we do right see it's easier than writing the unsafe Rust equivalent (if we are to believe the submitted article).
People working in non-Rust languages, I'm writing just small amounts of low level, unsafe parts in Rust, would be better off using C.
Safe Rust takes some time to learn, but once you do, is quite pleasant to write. It is true that it takes some time to get over that hump though. Google found that it was three to six months, but after that, there was no productivity penalty.
Rust offers tons of tools that are very useful for correctness outside of memory safety. I hope to never program in a language without sum types ever again, if possible.
You keep referencing Google's clearly flawed and asymmetric marketing about Rust. It is really unsightly. It has been thoroughly debunked nearly everywhere it was reported but here is a 10 minute recap of some of the clear flaws: https://www.youtube.com/watch?v=vB3ACXSesGo
The summary is that the research that you reference was not done in good faith.
I like prime but just because he says something doesn't mean it's true.
Repeating his claims in text form would be much more useful than linking to a video. I am not anti-video, but for example, I am out in public right now, and cannot watch it, and therefore can't meaningfully respond.
The video is worth a watch before responding. I'll try to summarize but it is unfair to the content. (I specifically opted for it over some others due to its brevity.) In all, the statement from Google lacks context and due diligence.
Some bullets:
* Experience levels in C++ and Rust are not equivalent. The experience gap between C++ and Rust developers can skew results, as C++ has been around much longer, affecting developer proficiency and code complexity.
* Comparison of codebases: legacy C++ vs. greenfield Rust. Comparing a mature C++ codebase with a new Rust project is like comparing apples to oranges; age and complexity can impact productivity metrics significantly.
* Measurement metrics can be misleading. The metrics used to determine productivity often lack depth, failing to account for feature complexity or development duration.
* Organizations have asymmetric composition of resources. The management style and communication within teams can heavily influence productivity, indicating that not all teams function under the same conditions.
* Experience gap between C++ and Rust should give edge to C++ as it has larger pool of candidates to pick from.
* Even in greenfield Rust vs greenfield C++ like Rust drivers in Android, Rust significantly reduced defect rate.
* Measurements in this study were done on teams with same size, rewriting existing service. Neither you or Primagen demonstrate how that would be misleading.
* See first point. While true how can you be sure C++ team isn't overall better than Rust? What if C++ is three senior engineers and Rust is three mediors?
Actual possible problems:
* There isn't yet enough data for language comparison. Too early to tell.
* Observer effect might have influenced the study.
Any other source that goes thoroughly over the video of keynote since it was thoroughly debunked nearly everywhere
I could not find it myself.
Also, I would not call it thoroughly.
Aha, so you're saying that asymmetric marketing is bad (I agree) and as proof you put up some other asymmetric marketing, namely an influencer`s video... Hard pass :)
Safe Rust takes some time to _unlearn._ By which I mean, there are (in my opinion) objectively bad practices that a linear language prevents you from doing - such as cyclic data graphs in memory. Rust is hard because you need to unlearn bad habits, and then learn how to solve those issues all over again.
I believe that's a good thing (in general, constructive constraints are good), but it is just an opinion.
"Cyclic datagraphs bad" is a perfect example of religious Rust brainwashing.
Cyclic structures in memory are not bad just because the one-memory-management-trick pony language you're currently infatuated with doesn't handle them within its safety paradigm.
Graph structures are entirely legitimate in computer science, and are handled nicely by garbage collection which is the gold standard in memory management.
Fully general lexical closures lead to cycles even when no variables are mutated. And even if no circular definitions are supported in the language.
We can use the Y combinator to create a cycle: a situation when a function's captured environment contains a binding whose value is that function itself.
I was talking to a friend last night, and programming languages came up, including Rust. I remarked to him that I felt that Rust's biggest weakness was its learning curve. But once you're past that, you're golden.
> Safe Rust looks absolutely painful painful compared to other safe languages.
It really isn't. It's quite nice to use. The big hangup is that Rust "wants" you to structure your programs according to a certain philosophy. Unfortunately the compiler can't teach you that approach directly, but can only complain when you write programs that don't abide by it.
In my experience, following this design philosophy benefits even outside of memory safety, and I now write code following these principles in every language.
> Correct C is not actually hard to write.
Quite literally all of the available evidence strongly disagrees with this conclusion.
> Correctness is more than just memory safety and avoiding overflows. They are still bugs in programs and languages that avoid those problems.
This is true, but C lack tools to help with any of them. Fixing memory safety and overflows is in and of itself an enormous win, but Rust also has other tools that assist in program correctness (sum types being a huge one).
> Quite literally all of the available evidence strongly disagrees with this conclusion.
Easy to write is not the same thing as easy to prove. It may be hard to show that some C program is correct, but when that is done, that doesn't change that it was easy to write (if that had been the case).
C is actually "unreasonably effective". You can't just look at the problems; the overall picture is that a lot of large and complicated, yet well-working systems have been achieved in C. They may not be correct, but are "correct enough".
The number of large C programs which have been repeatedly proven to be incorrect in practice is essentially 100%.
Still, C is unreasonably effective. A lot of large and complicated, yet mostly well-working (modulo regular CVEs) systems have been achieved in C. And that’s truly wonderful. I cut my teeth on C nearly 30 years ago and I still hold a soft spot in my heart for it.
But other languages these days are even more unreasonably effective. They need fewer lines of code to achieve the same results and they have fewer security vulnerabilities and logic bugs per line as well.
Many of the ways that C programs are incorrect are abstract portability problems, that don't have a repro test case on the machines and compilers that people care about.
Rule of thumb: almost never fix some alleged problem without a repro test case.
May I point you to Wikipedia pages on cognitive biases, like
Confirmation and Selection?
The CVE database lists only entries related to situations gone wrong. It doesn't list any information about working software that has no issues.
Also nothing will appear in the CVE database in relation to a language that nobody uses.
The database also has some garbage entries.
Overall the database is actually paltry in size in relation to the vast amounts of stuff out there written in C.
Also, correct C programs can have security issues, because some security issues depend on actual behaviors being observable which correspond to behavior that is not observable according to language standard. ISO C is mum about memory being observed, or side channel information being monitored, or timing of operations.
Ugh, not this again. Yes it is. It's hard. Veteran C programmers (I include myself in this category), even with compiler warnings, linters, and address sanitizers, still make mistakes all the time.
> Not all C has to be correct. If it's experimental or exploratory code that'll be thrown away. If that just works on one machine or on particular inputs that you care about, or it only certain specific environmental conditions, that can be fine.
So what? That's not the kind of code we're talking about.
> Correctness is more than just memory safety and avoiding overflows. They are still bugs in programs and languages that avoid those problems.
That's either whataboutism or a straw man. No one is claiming that languages that help avoid common C memory-related bugs like out-of-bounds access, use-after-free, memory leaks, etc. will also somehow magically make all your logic errors go away too.
Even veteran eaters bite their tongue or lip once in while. That doesn't mean eating is hard.
> No one is claiming
Only about 3 out of 4 Rust advocates.
> That's not the kind of code we're talking about.
We should talk about all code. Code that gets thrown away, rewritten, or improved from prototype to production. It is relevant to productivity. If I'm going to throw away some code to get to the code I want, it will be an extra waste of time if it is difficult to write.
> Even veteran eaters bite their tongue or lip once in while. That doesn't mean eating is hard.
Kinda. This would be more like if my mouth were stuffed with anti-tongue-bite technology and I'd trained for years using scientifically proven techniques to avoid biting my tongue, but inevitably I do anyway and then my identity and the identity of all of my friends get stolen.
I love C and actively dislike Rust, but to minimize the effort spent compensating for and consequences of C's shortcomings is very head in the sand.
I am not sure if Rust advocates tell that it will "magically" fix logic errors. What I hear they say is rather more precise terms: Stronger Type system, and memory safety, forcing more explicit design (e.g. no function overload). Whether this is true or not is another discussion to have.
In my experience, it helps to have stronger type system regardless of any language of comparison if you want to avoid logic errors.
Ok. There are some problematic people in any community (although I would require more scientific data instead of personal anecdotes to be convinced, e.g. comparing stats related to this behaviour across different PLs with meaningful statistical metrics). I think this is more of complex sociological question than some people make it out to be.
What I see is occasional people being aggressive rarely. The are disagreeing on a principled/reasonable manner. Those who are Rust fanboys (or whatever you implied) are suppressed/downvoted etc.
There are two big commandments of the modern programming religion:
- Type safety
- "Memory safety"
We have to understand it: it is religion. No science.
in 10 years maybe somebody start realising, that even with the 2 sw can still be very bad. And those 2 are not silver bullets... until then... patience.
I would advise to you not say such blatantly false things. You paint yourself either as a liar or as unqualified. C has been proven time and time again to be almost impossible to write correctly. Even top tier programmers like djb cannot write safe C.
Nobody can write "safe C" because C is inherently not safe. See my other comment about it. Safe means something like "if the program breaks some semantic rule, it will be caught and diagnosed". It's not a statement about the program being correct or not, but the consequences of if it were to be incorrect. Even tiny, trivial programs have the potential to be incorrect without diagnosis.
> C has been proven time and time again to be almost impossible to write correctly.
That is obviously untrue by the definition of unsafe that I've been explicitly using.
I've been sticking with the concept of unsafe language, whereas you're talking about an unsafe program.
The two are related. An unsafe program misbehaves when given bad inputs. It's behavior is undefined.
An unsafe language is an unsafe program with regard to bad inputs, which consist of certain kinds of incorrect programs. (Those which are not diagnosed).
It's easy to write unsafe programs in unsafe languages. If we only focus on the program's functional requirements and none of them speak about what to do with bad inputs or in bad situations, we can end up with a program which is perfectly correct but unsafe. It will behave as specified on the correct inputs.
If you happen to be advocating Rust due to misunderstanding this kind of material, you're in it for the wrong reasons.
Correct C is not actually hard to write. It can be somewhat hard to convince oneself that it's right.
That's an important difference. Not all C has to be correct. If it's experimental or exploratory code that'll be thrown away. If that just works on one machine or on particular inputs that you care about, or it only certain specific environmental conditions, that can be fine.
Correctness is more than just memory safety and avoiding overflows. They are still bugs in programs and languages that avoid those problems.