299 comments

[ 3.2 ms ] story [ 297 ms ] thread
Or even better, Haskell!
If you rewrote only part of a large C++ project in Haskell, is there a way to link it back in again?
Call Haskell from C (not C++) seems pretty easy:

- [Calling Haskell from C - HaskellWiki](https://wiki.haskell.org/Calling_Haskell_from_C)

And the FAQ on the Haskell wiki directly addresses this too:

- https://wiki.haskell.org/Introduction#I_already_have_a_large....

So apparently it is doable!

It pulls in a huge runtime system, though (including stuff like garbage collection). This makes it much heavier than calling some Rust code.
True, where "huge" means something around 10MB.

For many projects that is a showstopper.

It definitely can, but if you're asking for an out-of-the box support, then it's probably not as easy to use as Rust. Then again, if you plan to rewrite your code base, then why not invest -- typed IO is a big thing.
the cool thing about rust is that you can use it for real-time programming, one example being DSP/audio. it often means no locks, nothing blocking, no dynamic allocation (malloc and most other allocators do not provide upper bounds of execution time), no recursion, and others.

haskell is not tailored for that.

of course there are other domains for which haskell is top-nocth and rust falls flat.

Minor nit: I believe that you can get memory allocators that provide upper bounds of execution time. But it won't be the default allocator in most languages. Also, you need an allocator that cannot ever fail to return a valid block. Even if you have all that, it still makes it much harder to prove that your worst-case timing is fast enough.

So, yeah, no allocations in situations like that. Allocate at start-up, and re-use your buffers (for that kind of code).

I think there are memory allocators that provide bounds, yes, but I never bothered finding one. Time-constrained code is so demanding already that handling the memory part is just one drop in an ocean of constraints. (and the whole thing is actually very interesting to do!)
C can be safe if you use Turing incomplete libraries that have been verified. It's the YOLO ad hock parsers that get you in trouble.
I am not sure if you are serious or not.

How does verification prevent buffer overflows? It can reduce their frequency, but you can never know you got them all. They find issues in libCURL and openSSL that have existed for years. Very few people are better than the people working on those libraries.

It is better to be safe by default then add risk only when you need it. I say this as a C++ developer, I think const should be the default state of all variables and one should have to opt out of that, and Rust did that right and C is so far from that I see no reasonable way to use plain old C safely. At least with C++ I can hide my stuff in classes and verify one thing at a time.

It was probably the "Turing-incomplete" part that prevents buffer overflows. Easier to reason about/verify.
Formal verification is not the same as a security audit. With formal verification you can prove that something is bug-free.

> They find issues in libCURL and openSSL that have existed for years

Neither of them are formally verified. https://github.com/seL4/seL4 however is formally verified.

Please, step away from "formal verification" and come back to world the rest of us devs work in. I have never seen a formally verified piece of software even once.

I don't know if its too hard to do to real software or if C doesn't allow for it, or if it is just too expensive. The simple matter is that is not an option for the vast majority of projects. Unless you can make it practical, I assert it has no place in a practical discussion about preventing software issues.

Worse: "It's amazing how many bugs there can be in a formally verified piece of software." I forget who said it, but it's been a long time. (Maybe in connection with formal verification of an OS? Does anyone remember?)

Formal verification only works if the formal verification was mistake-free. (And how are you going to prove that? With a formal verification? It's turtles all the way down...) Also, it only works for the aspects that were formally verified. Heartbleed, for example, could be regarded as a flaw in the specification; formally verifying that the code matches the spec won't save you from that.

If you are really worried about the security of old C code, then the safest, most portable thing to do is re-write in modern C++. This is sane and doable in a short period of time. Rust is not.
Why not Rust? Given that you aren't very familiar with niether C++ nor Rust, I'm not convinced that C++ is saner or faster.
Or just rewrite it in modern C. This is sane and doable in a short period of time. You just have to make sure it's modern C.

(no true Scotsman)

> Or just rewrite it in modern C. This is sane and doable in a short period of time.

What do you call modern C?

Well, anything that does not support the point I am making is not modern C.
I think his comment was facetious. I think the clue is "no true scotsman," which is a type of fallacy. I think the point is that it's assumed to be better because of the use of "modern," and that it's only valuable if it's rewritten in something modern. Perhaps it's a joke about how old code is actually fine, and that people who get excited about the cutting-edge technology could chill a little bit. Maybe it's just a mockery of the previous arguments.
No true Scotsman:

"We found a terrifying vulnerability in your codebase. You should rewrite it in modern C++."

"OK, done!"

<Time passes>

"We found a terrifying vulnerability in your codebase. It must not have been modern C++!"

same question applies to C++. every new version of C++ is the modern version for a while…
Isn't Go pretty much the modern C, with additions in concurrency?
It's garbage collected. So, no.
No, not really. Go left a lot of C behind (pointer arithmetic for example), while also being garbage collected and having modules instead of header files. Coincidentally, while being touted as replacement for C and as the "language of the server", most of its converts come from python, ruby, and node.js evironments.
Oh no, no, no! Some people may reasonably, with some extreme care and diligence, maybe try to claim they can write safe and UB-free C code. If stars align properly. (See maybe SQLite. Seen as one of the pinnacles of crazy pedantism in C. Also, see the article about errors found recently in SQLite with fuzzing!) But with C++, it's just impossible for a human. It's too big, too quirky, too big, too wide, too deep, too tricky, too big, too complicated, and also too huge. And purposefully (sic! for performance) sprinkled with UB, which means barbed fences, trip-wire mines (to boost your in-flight performance), and hidden pit traps. Writing C++ code longer than a few lines without UB is humanly impossible. Sorry. And that's just about UB, because it's the most unpredictable thing; but there's still exception safety, for example, which you also should be doing, which can "only" spoil your code's logic (and then, obviously, go on writing over random memory, but that's nothing uncommon for us C++ers). Is every line of your C++ codebase exception safe? Yeah, sure. Good luck. And "modern C++" only means more C++. Because backwards compatibility. Unless at some point some quest for a "safe subset of C++" finally gains traction, which may maybe bring back some sanity. I do really hope for that.

A personal opinion from a person who loved C++ for quite some time, before diving deep enough to realize how dark is the abyss.

> Oh no, no, no! Some people may reasonably, with some extreme care and diligence, maybe try to claim they can write safe and UB-free C code. If stars align properly.

Why the sarcasm?

I'm afraid I was not being sarcastic. Sorry. This is a totally honest and dead serious opinion from a long time C & C++ user. ("stars aligning" here means "you must also have luck". As I said: see SQLite.)
Then just delete your entire OS or at least your browser, don't force yourself to use C and C++ software. Seriously. I'll let you keep LLVM so you can play with Rust.

There's disliking language or the boilerplate it forces on the programmer which I can REALLY understand in case of these two and there's being a jerk and an idiot and saying any C++ program that isn't few lines is broken by the UB, you need stars aligning to write safe C, they are impossible to write anything substantial, safe and useful in, etc. and anyone who tells you otherwise is implicitly a very bad programmer who does their job wrong and endangers people.

I'm not sure I agree with the amount of hyperbole in the original post, but you must be joking if you want to claim that browsers or OSes are "safe" in the Rust sense of the word.

Use after frees and numerous other memory bugs are discovered all the time in C/C++ programs (including kernels and browsers). This isn't an imaginary problem. Then combine multithreading and you've got a whole extra level of possible issues. Rust does solve many of these problems, and you can prove it does so mathematically.

I understand why people don't like the use of the term "safe" because it feels like a value judgement. But I think people's egos really should be a bit less fragile when discussing language choices.

> Then just delete your entire OS or at least your browser, don't force yourself to use C and C++ software.

With RedoxOS you actually could do that in the near future once it supports some more hardware. The kernel and entire userland (with graphics) is written in Rust. And they did it in 2 years. If nothing else you have to admit that there are some very talented engineers using Rust.

Your point being exactly what? Don't put words in my mouth because I never claimed C and C++ are as safe as Rust, just that they are good enough for millions, including you, to rely on daily with their lives and that Rust itself relies on some C++ (LLVM). I'd even say that yes, C is the least friendly and most spartan language and C++ is the most complex and hard language that are in wide use nowdays but that wasn't the OP's claim. The OP's claim was ridiculous and on the level of opinion people have of Java applets ("totally unsafe", "useless", etc.). These people who have such opinions of them don't run them in their browsers so you should not run any C or C++ on your machine either or you are clearly overdramatizing.

Mathematical provability and technical excellence has sadly little to do with adoption - see where JavaScript, Erlang, Haskell, OCalm, Modula, etc. ended up and tell me every language got what it deserved based on its own merit.

Fanboying over Rust and RedoxOS (it being impressive or not is besides the point) won't fix all that "doable if stars align C" and "humanly impossible C++ that has UB even after few lines" code out there in the government, power plants (including nuclear), infrastructure, stores, embedded, banks, ...

Egos have nothing to do with it. I dislike JavaScript, Java and C# personally (not for any technical reasons but due to my tastes) but if I've seen someone saying the are useless and everything written in them is broken I'd call BS. I'm similarly fond of Free Pascal with LCL for personal GUI toys but if someone said it'll take over the world and destroy Qt and GTK+ behemoths I'd also call BS. Hell, I'd defend your precious little Rust if someone said something stupid about it.

There's factual critique (which I have lots of myself and I don't recommend C or C++ to new hobbyist programmers but Python3), there's personal taste (that you mustn't camouflage as technical opinions) and then there's pedal to the metal "I hate the language so it's totally useless and no human can use it" BS like the OP's comment.

Rust supposedly targets C and C++ programmers so it shouldn't be acceptable to shit all over their tools and by extension their work, telling them they are stupid for liking these languages and are doing everything wrong as an engineer. The fact that such BS is disallowed in official Rust spaces is really telling of how idiotic and ridiculous it is: https://news.ycombinator.com/item?id=14755394

Regarding my initial outburst, I'd like to clarify that it was specifically against a comment claiming that rewriting C code in ("modern" or not, whatever) C++ is the safest choice if someone is worried about security of a C codebase. I didn't actually even say a word about Rust. The C vs. C++ claim there was already enough to make me want to cry loud.
Ah, but I never called to delete any C/C++-based code! That's a strawman from you here. Also, especially I didn't say it's impossible to write anything substantial and/or useful in C++, oh, most certainly it is! But truly, I did and do claim it's humanly impossible to write anything safe in those. As to doing a programmer's job wrong, sorry if you got such impression. Wasn't my intention. C++ is powerful, and in many cases, the gains of using it overpower the risks. As to endangering people, now that's a different topic, and there are measures to protect people possible even in case of unreliable systems. But anyway that's really niche, your Windows/Linux/OSX laptop/PC won't really endanger people until you start hitting them with it, to first approximation. In the other case, like medical software, logic bugs can be I suppose orders of magnitude more dangerous to people than UB-related etc. bugs.

I'm not saying C++ kills people. But I am saying it is producing inherently buggy software, on some level. I'd say it this way: improvements that Rust, Idris, Haskell & many other new languages (and also some old ones, actually, like reportedly Modula, Ada, etc.) try to bring to the table, are similar to what procedural programming or type systems brought over assembly. Resisting those improvements is... strange to me.

[edit: I noticed I wasn't allowed to reply to some comments downstream a while before. I think this may be some kind of a signal for me to just STFU and drop the ball; even if not, I decide to just treat it so, I've said more than enough words already probably. Actually, biggest outburst of my posts on HN ever. I'm starting to think I might be having some kind of a PTSD w.r.t. C++. Anyone knows of some good therapy centers for recovering C++ veterans? :) ]

You can write large C++ programs that are quite safe, using only higher level abstractions (no pointers or explicit memory management). This doesn't require any fancy new C++; code written to C++98 (first ISO C++ standard) will do it just fine.

For exmaple, in C++, we can put two strings together to make a new string without worrying about whether we have a buffer large enough to hold the result, and whether null termination is ensured and so on, or whether or not the original source strings are damaged in the process (they are not), or whether that memory will disappear when we return to the caller. It's just str1 + str2.

I'm no C++ advocate, bu the fact is C++ code can look like a scripting language and be safe like one. C++ also has tools for isolating and managing the C-like semantics that a C++ program might contain.

So even to clump together C and C++ as "C/C++" is not well considered. There isn't a "C/C++" language. If you post a message about C/C++ in the comp.lang.c newsgroup, put on your flame-proof asbestos underwear first.

That's actually why I call BS on anyone who says "C/C++" while claiming to be a (former) C++ high level user (dabbling in it doesn't count, I dabbled Java, C# and PHP but it's not even on my CV because I don't consider myself anywhere near production level in them) and try to use "C and C++" myself. See: http://www.stroustrup.com/bs_faq.html#C-slash
Higher level constructs like iterators, references and smart pointers are all relatively easy to misuse. It is definitely possible to have safe abstractions like std::string's + and they're one reason why C++ is an improvement over C, but there's still many other dangerous edges that are nearly impossible for a human to keep track of at scale.
There are things in the C++ standard library that are not very well designed, yes.

For instance, erasing from some containers causes undefined behavior if iterators that were created before the deletion continue to be used.

Some of the various smart pointers for managing memory are not so smart; they have been redesigning new ones and deprecating old ones so many times now. It used to be "your code isn't exception safe: use auto_ptr, you dolt!". Then, "you idiot, don't use auto_ptr, use this instead" and so on.

You can avoid all that by defining your own classes that do just what you need, use only the safe stuff from the standard (like the aforementioned strings) and write yourself a perfectly memory-safe, leak-free C++ program.

Even the modernest pointers unique_ptr and shared_ptr are dangerous (use after free/move and, e.g., ease of data-racing in the data, respectively). The problems with them are relatively fundamental to C++ and its idioms. The classes you define will need to avoid using fundamental C++ features like references too: anything pointer-like can lead to problems (including `this`)

The "you (and the standard library, including the completely new parts) are holding it wrong" defence is tired, when it is so ridiculously easy to do so: it is okay and important to acknowledge that a tool is powerful but also has a pile of hard-to-avoid sharp edges.

I fully agree, but you cannot oblige everyone that touches the code to have the same care, and so the typical "C with C++ compiler" idioms sneak in, thus decreasing overall safety.

This is specially the case in the majority of enterprise software that doesn't use any kind of static validation tooling, or CI builds.

> you cannot oblige everyone that touches the code to have the same care

If you can't enforce that certain rules be enforced in a C++ program, you also can't enforce that someone won't sneak C++ modules into a code base written in another, safer language.

> doesn't use any kind of static validation tooling, or CI build

Or, also: a review tool for rejecting stuff that is against the project's explicit coding guidelines.

> you also can't enforce that someone won't sneak C++ modules into a code base written in another, safer language.

In Java and .NET projects you can easily ensure that, and that is a common scenario in some of our customers.

The machines are provided locked down by IT with the project sanctioned tools, including the configuration for in-house Maven and NuGET repositories.

No native code compiler gets installed, servers are configured to disallow unsafe code.

Any library not available requires a change request to the IT team.

With that environment and people, we could easily enforce C++ rules in the same way.

Stuff you don't want in C++ code can be rejected by a pre-commit hook which scans code. That header can't be #include-ed, that crazy operator can't be used, etc.

Also, with open source compilers, you can implement your own warnings. (Been there, done that; in the role of an embedded distro/kernel/toolchain person some years ago, I hacked g++ with custom warnings).

If there is something we don't want in C++, and it doesn't "grep" well, we may be able to diagnose its presence in the compiler and treat that as an error.

Not really, the part you are missing is that it is easier and cheaper not to have C or C++ compilers available at all.
No, what I mean that if those same people were running a C++ shop rather than a Java shop, they could be equally and just as effectively draconian in their enforcement.
Ah I get your point, but static analysers and sanitizers aren't able to find all unsafe issues, specially if binary dependencies are involved.

This is why on Solaris there is OS support via SPARC instructions to enforce bounds and valid pointer use, for example.

The call for removal of C++ is implicit or do you now say we keep extremely unsafe (in your eyes) software around and put our lives on the line? Lives and livelihoods do depend on C and C++ software in nuclear, medical, governmental, financial, etc. and somehow millions are not dying due to all this unsafe software. No software is 100% safe, even Erlang (another dear of HN but one that is enjoyed in a more civil environment than the "Go Rust, Fuck C++") is just "nine nines" reliable.

You made C++ sound as bad as Java applets or something similar. Obviously anyone saying Java applets are unsafe, bad, etc. is telling you between the verses to not run any, ever. The words you used were very strong and made it sound like everything is buggy as hell while the bugs are minor and few and far between (relatively speaking, there are lots in some places but your browser and OS is not crashing or leaking your data to hackers on a daily basis, the situation is nowhere near tragic).

Saying C and C++ are unsafe basically shitted on every programmer ever that picked them for anything important, kernel makers, browser makers, server makers, languages VM makers - all idiots, endangering people and property, writing unsafe software!

Basically exception safety is a solved problem in Modern C++. If you use RAIIike it was meant to be used, exception safety is not that big a deal.
True, I guess, for "business logic"-y classes. Not true at all for data structures, particularly those that are templates.
How is it not true for data structures? Even templated ones?
For serious exception safety, you have to be able to prove that all invariants all the code of your class relies on are kept between every 2 subsequent lines of your code in that class. Because exception can occur everywhere. And actually, I oversimplified, because often you must also know what happens in each and every operator you use, including implicit casting operators, and also in your destructors and constructors, including implicit ones. Each of those may or may not throw, and each of those may have some internal state, or modify your state in unexpected ways during an exception. RAII gives you primitives which you trust are written with exception safety w.r.t. their inner invariants. But you build some code on it, which has its own invariants. Do you prove them between every 2 lines of your code every time you change a line in your code? After I read enough about exception safety, I realized how hard it is to keep watertightly.
do you mind me providing a bit personal suggestion? When you've began resorting to play of words like 'barbed fences, trip-wire mines...' instead of providing concrete proof/examples in your post, you've already lost your argument.

> Writing C++ code longer than a few lines without UB is humanly impossible.

Do you want me to provide one for you? Because that will definitely change your definition of 'humanly impossible' tasks and might also bring you back from realms of using comically bad phrases..

Ok, please let me ask you a question: have you read all the fragments of The ISO C++ Standard regarding undefined behavior? I have not, but I've read enough fragments/quotes to raise hair on my back and show me how many assumptions I had and assumed safe were subtly wrong. If you have not read all the fragments, you by definition don't know enough about UB to protect against it! Sorry.
I struggle to imagine how you could be more wrong. C offers minimal if any possibilities for writing safe code, while C++ offers many.

Anybody who has the faintest clue about both languages should know that.

I actually feel that C++ memory management is less safe than that of C, because smart pointers provide the same opportunity for use-after-free while being much more opaque about when the destruction occurs. The rules about when destructors of temporaries are called in the evaluation of expressions are subtle.
I'd be happy to discuss an example, because right now the idea that smart pointers are opaque about destruction is unfortunately too abstract for me to give a helpful reply to.
Consider situations like this: https://stackoverflow.com/questions/17362673/temporary-lifet...

It's undefined behavior, despite not calling free anywhere. Replace with std::string and it could be use after free. In C, UAF wouldn't happen that silently for heap memory.

A similar example was posted by matthieu_m on Reddit a while back, but that's still not worse than C, even if it's an unfortunate gap in compiler diagnostics.

From my POV compilers should warn that this code is potentially dangerous. My rule is: never return a reference or pointer from a function to something whose lifetime you don't have control of.

It's worse than C because you can't have UAF in C without explicitly calling free (or a function that transitively calls free). In C++ freeing is implicit.
Do you even explicitly free() a RAII-managed pointer? If yes, why?
No, and that's the problem. Free can effectively be called invisibly, causing UAF.
C is kinda small enough, that I imagine one can maybe have some chance at trying to hold the whole of it, including all nuances/warts, in one's head. Like, maybe even actually write a compiler for it. (See e.g. Dennis Ritchie, Fabrice Bellard.)

With C++, good luck even reading and understanding The ISO C++ Standard. Not to say fully internalizing all possible interactions between all nuances. I presume not all of them may even be truly 100% fully fleshed out and explored in The Book. As to writing a compiler - even just writing a parser for C++ is famously super hard!

> C is kinda small enough, that I imagine one can maybe have some chance at trying to hold the whole of it, including all nuances/warts, in one's head.

Anyone that is able to keep in mind the documented 200 cases of UB is my hero.

To help protect you from these unsafe programs in obsolete languages I compiled a small list of software in C or C++ that you need to delete ASAP to ensure your safety: 1. Windows OS. 2. Windows kernel (mobile too). 3. Linux kernel (android too). 4. Bash, zsh, csh, fish, etc. 5. C#, Java, Ruby, Python, etc. 6. Parts of Rust backend, namely LLVM :(. 7. Apache, nginx, etc. 8. Filesystems. 9. Most drivers. 10. Router software. 11. Linux graphical environments (most/all are C or C++ and use GTK+ or Qt). 12. Any other kernels/OSes (any BSD, Haiku, iOS, etc.).

Be sure to not use rm, bash, zsh, windows explorer right click + delete, etc. to delete these as that'd be relying on definitely broken software written in obsolete languages too!

On a more serious note: IF you knew C++ at all you'd really know better than to say things like these and I have no idea where did you get the information about UB, overwriting random memory or using exceptions (Qt is famous for using none at all for a good reason) being common in C++. And what people use is the sane subset. When was the last time you've seen outside of some obscure specific place any of: virtual or non public inheritance, pointers to members, switching [] operator arguments for C arrays, placement new, manually calling destructors, using templates or macros to do compile time programming, etc? Considering your ignorance of the fact you use tons of rock solid C++ software daily I'd think you don't know what most or all of these even are.

Rust fanboys like you who speak of C and C++ programmers like of idiots who write unsafe programs that endanger people is exactly why I'm not using Rust (yet?). If a community seems that toxic at a distance I'm not even going to try to come closer. It's even worse than Java or C# fanboys who seem to forget what their VMs are in because they are at least fanboying over HUGE enterprise proven languages. Rust on the other hand does have a few big projects (but Servo is a toy and few lines around hundreds of thousands of C++ in Firefox doesn't make it a Rust project) and looks more promising than D ever did but fanboys are acting like it's the next C++, Java, Julia and C# combined and grasping at straws "one package in choco is in Rust!", "easy to call C code!", ...

[edit: ah, potentially my best argument regarding UB, that I thought of in another reply in this thread: so, please tell me now, have you read all the fragments of The ISO C++ Standard regarding UB? Because if not, you by definition don't know when you may be committing UB! :) And what I can tell you, is that I have not read all of them, but I have read enough of them to raise hair on my back and make me absolutely doubt all C++ code I've ever written, or would possibly ever write in future.]

Please note I didn't say a word about Rust here :) That's your overinterpretation. First of all, I never actually used Rust; from what I've seen, I feel it has some potential and good ideas; but OTOH, I also get the feeling that one is forced to use 'unsafe' blocks from time to time anyway, so there's still some area for self-inflicted danger. Even standard library has some errors found from time to time and reaching the news. Also the compiler is new so not very much battle proven yet. Also I'm somewhat uneasy about the fact, that Rust seems to be quite a big language already, and still growing in complexity. Not sure what's the solution. But C++, as it is now, in my opinion is most certainly not one.

I was employed in a big corporation and working on a moderately big C++ codebase. It totally had UB, overwriting random memory, exceptions, etc. It was common knowledge in the operations that the app crashes randomly lots of times a day and has to be restarted automatically, to the point of this being considered non-issue. Virtual inheritance was avoided; don't recall non-public. Pointers to members, suppose yes. Templates - oh, tons of them, and growing. The company actually has super smart C++ programmers (and I mean it!), submitting proposals to the C++ committee and having them accepted. Now, note the Brian Kernighan's quote about debugging clever code. I once debugged a somewhat more -often-than-normal crash. It ended up proving to be a data race. It was a fun experience, though at times totally depressing. UBs were so common during this debugging that I simply ignored them, or I'd go insane. But when I look at how easy it is to detect and debug races in Go, and how still I have to be careful to avoid races there, and still make them from time to time, I know there are tons of them sleeping undetected in any multithreaded C++ code. And we had valgrind etc (though it was rarely used, as it slowed the app to a crawl). Now, all the perfect "modern" or "subset" C++ you claim is so flawless (for whatever actual definition of "modern" you'd try to choose) is never fully enforceable, because it would be too strict or "not performant". Plain ugly non-modern C++ will spill, I don't believe you'll avoid it in any corporate environment. Maybe in an idealized open-source side project, in theory.

As to rm, bash, zsh, Windows Explorer's right click, etc - I'm sure they are broken! Those are the so called "bugs" you hear about so often. I didn't once say I won't use those tools. I only wish they weren't so buggy and unreliable... On the other hand, worth to note that there's always a random cosmic ray from time to time, or a bug in processor's microcode. So even Rust or Idris may not protect you at all time, I suppose plain old asserts may be more reliable as a last line of defence.

And back to your first point: again, "you have to delete ASAP" is a strawman from you here. But anyway, Windows totally has tons of security bugs, see all the NSA exploits, recent ransomware, Pwn2Own, etc. Though they seem to have gradually learned since the Win95 and XP days and stuff is slowly improving. Linux, absolutely has bugs and security holes! Linus is famously not treating security holes as serious bugs, isn't he. Filesystems are buggy as hell! SQL database engines have to go to great lengths to try guaranteeing atomicity and reliability of ...

I am not saying C++ and all the stuff listed is always safe, just that it's good enough for daily use, including professional use where lives are on the line. As I said before, you used extreme words and made C++ sound like Java applets - something no one ever should use nowdays outside of truly exceptional circumstances (a.k.a. not something as widely used as OSes, browser and the HotSpot JVM).

I'm sure you have seen BS codebases in Java, C#, PHP, Python, etc. as well, I've seen weird interactions with GC in WildFly (I can't comment more because I'm not a Java programmer), spooky action at a distance, globals, using one huge table in a DB to store everything thus missing the point of a relational DB, etc. all in non C nor C++ and it'd not help these things if they were in Rust.

Not all bugs come from the language itself either, some are just true programmer errors. I just google for PHP SQL tutorial (not an English one) and the result is of course pasting input together with SQL to form a query, 0 escaping... Sony had a leak like that. Many Windows issues are pure ignorance like having SMB (that turned out to be buggy, but still) running by default, similarly stuff like misconfiguration, default passwords, Apple's goto fail won't be solved if people are copy pasting code and formatting it badly (unless Rust enforces that, I'm not sure, I don't know Rust yet). Rust will not prevent these kinds of mistakes (maybe the last one if the compiler itself detect inaccessible code and maaybe the SQL one if it marks the variable from user input unsafe at first and cascades that through the function calls to see if it was pasted and passed to SQL) unless it has extremely deep understanding of what's going on.

Additionally, despite all the bugs in Windows there (sadly) wasn't a huge exodus to Linux (which too has tons of bugs and is in C and has lots of programs in C++), it just works "well enough" despite the flaws, there no disaster hanging over our heads.

> It totally had UB, overwriting random memory, exceptions, etc. It was common knowledge in the operations that the app crashes randomly lots of times a day and has to be restarted automatically, to the point of this being considered non-issue.

Most fundamentally, that's a corporate culture issue. That should not be regarded as normal in any sane environment. (And, yes, such environments do exist.)

> The company actually has super smart C++ programmers (and I mean it!), submitting proposals to the C++ committee and having them accepted.

But not thinking it's a problem when the app crashed multiple times a day? That sounds like architecture astronauts, not good programmers.

> I know there are tons of them [data races] sleeping undetected in any multithreaded C++ code.

No. I've worked on real-time multithreaded code that had no data races, thanks to judicious use of mutexes. (Now, I can't prove that, and you could argue that they're there, and I just don't know it.)

It's possible to do much better with C++ than what you experienced - to write solid stuff that doesn't crash every day, still less multiple times a day; to write multithreaded code that isn't riddle with race conditions; and so on. Mostly, what it takes is a team (or corporate) culture that insists on quality code, from start to finish - good design, good development, good testing and debugging.

Fastest to develop, yes. Portable, yes. Safest? Well, only in as much most of the errors will be blamed on the programmer for not doing the correct modern C++.

I mean, seriously, understanding the borrow checker is nowhere near as hard as understanding this: https://akrzemi1.wordpress.com/2013/10/10/too-perfect-forwar...

There's a No True Scotsman aspect to C++ advocacy. Anything that is obviously dumb either is because the programmer did it wrong, because it belongs to the ever-growing list of features you avoid or "doesn't come up that often".

As long as it possible to run the same old C code inside your "modern C++" rewrite, you might have ported the security holes to C++. The problem is, C++ is far to compatible to C here. The idea of all "safe" modern languages is, that unsafe constructs are simply not allowed by the compiler. Why not let the compiler do the checking work vs. hoping that the human programmer didn't miss a check?
You can also rewrite to C++, OCaml, Go... Each language has benefits and drawbacks, and there is good reason for each them to exist.

Would your project benefit a lot from algebric datatypes -> OCaml is a great fit!

You want to port as soon as you can: C++ is your friend.

You plan to write HTTPS service nodes: Go has the best standard library out there.

If you read the article you'll notice that he proposes that Rust is a better language because it allows incremental rewriting, rather than a complete one; Rust doesn't have a runtime, doesn't have GC, and can fairly seamlessly/painlessly integrate with C (you can both call and be called from C easily).

That changes the equation considerably, compared to something like Go where none of these benefits exists. For example, exporting code from Go not only requires the runtime and GC, there's also significant function call overhead because of the way Go maps goroutines to threads.

There are many other good languages, but few of them have these benefits. C++ is probably the option with the least amount of friction against C, but then you're also inheriting most of the unsafety of C.

Incremental rewriting introduces the potential for new issues, as foreign function interfaces are inherently unsafe.

Rust also has its own costs. Its biggest limitation when it comes to mixing in code with that written in another language is probably its poor support for shared ownership (i.e. multiple references of the same object), while in most languages, shared ownership is the norm.

Multi-language setups (which you invariably get with an incremental rewrite) also generally create other interfacing issues when they share objects. How are you going to represent `std::shared_ptr<T>` or `std::vector<T>` in Rust, for example? They are opaque types, after all. Can you guarantee that Rust properly observes C++ semantics with regard to assignment, move assignments, and destructors when dealing with instances declared entirely in C++ code once you start mixing and matching C++ and Rust?

+1 to everything said here.

It really is very straightforward to start inserting Rust into a C/C++ codebase. I did the Rust port of netcode.io[1] which started out by just calling C code for the portions that I didn't have working in Rust. Eventually the port was 100% Rust but I was really impressed with how seamless mixing C/Rust was.

Even now our unit tests run against the C code at a functional level so we know when the protocol diverges which lets us easily catch breaking changes from the reference C implementation.

Much like everything, don't apply an adage blindly and do a proper evaluation but I think if you're in the a space where memory or performance matters Rust is a very strong contender that plays well with existing ecosystems.

[1] - https://github.com/networkprotocol/netcode.io

Why Rust? Why not Idris? Why not Haskell?

Or you know, why rewrite it at all? You could instead try and use a safe C implementation (such as gcc/clang with the sanitisers or something like https://staff.aist.go.jp/y.oiwa/FailSafeC/index-en.html), but to be frank if I was to rewrite my programs I would use a truly modern language like the ones that I mentioned above.

All of your questions are addressed in the article.

> Why Rust? Why not Idris? Why not Haskell?

    it can easily call C code
    it can easily be called by C code (it can export C compatible functions and structures)
    it does not need a garbage collector
    if you want, it does not even need to handle allocations
    the Rust compiler can produce static and dynamic libraries, and even object files
    the Rust compiler avoids most of the memory vulnerabilities you get in C (yes, I had to mention it)
All of these except GC also hold true for the languages that I mentioned.

As for GC, I think that Mercury avoids its use https://lirias.kuleuven.be/bitstream/123456789/131304/1/Mazu...

Nope- C interop is higher on the list for a reason. Idris and Haskell do not produce straightforward, runtime-less binaries that can be easily loaded by e.g. CPython or Node, without any interference with their runtimes.
These parts are true of D, and C++.

IMO Rust's only true advantage over it's direct "competitors" is it's safety guarantees.

No GC, higher performance than either. Most other safe languages have more overhead than Rust.

As for why not use sanitizers and such: That's an ongoing cost of using the sanitizer. Rewriting in Rust is a one-time cost, and can be done incrementally.

How about Ada/SPARK then?
Please correct me if I'm wrong, but don't Ada/SPARK's memory safety guarantees only hold when all memory is pre-allocated? My memory is that dynamic allocations aren't visible to the proof system (this may be in plain Ada without SPARK, now that I think of it).
That is correct. Ada and SPARK do not provide memory safety in the case of dynamic memory allocation without garbage collection.
Not as much as rust, but still. I'm not sure whether it qualifies as memory safety for you but using Controlled types alleviates a large part of the problems of dynamic memory allocation. http://www.adacore.com/knowledge/technical-papers/the-gnat-i... might be of interest for the underlying implementation.

I also find that 'not null' access types, typed pointers and in general the in/out/in-out parameter passing mode help making ownership clearer... And there's also the limited types in the toolbox, to 'hide' ugly pointers/resource ids, etc.

Spark2014 still excludes pointers and aliasing, but I think some work is in progress. Previous HN thread : https://news.ycombinator.com/item?id=14346032

Or better, why not pascal?

The HONEST question is because developers hate progress. We could have left in the past C/C++ by now, but not, is better to move forward with the same problems as DECADES ago.

Rust is a potential contender because is not that far from C/C++, and have {}, and the last point is not even a joke.

-----

Is weird to me why a clean fork of C/C++ was not made, if the prospect to move to something else was too much progress for the minds of the industry, the slow progress is a good alternative. You could have C.1, C.2, C.3, etc...

Think how much is about "modern C, modern C++, coding well" and then why not commit all that wisdom as the language?

The creator of Pascal made a point that a new version of a language must remove and correct the mistakes of the precious version, not accumulate problems.

That is fight AGAINST entropy.

Many clean forks of "C/C++" were made and they're all dead because apparently it's not so easy to do as you think.
Is not about being easy to do. Is that developers not accept them if not recreate all the same things that C/C++ have with the same good & bad, defeating the whole purpose.

Plus, this need a serious marketing push, and more than the work a few on them. Is each year harder and harder, similar to Cobol (where each year on drugs make you less likely to quit).

Now, the best hope is a painfully and too long gradual switch to rust or something else...

The title ought to have been, "Why you should rewrite some of it in Rust." That's what the article is actually about. Then we could have a productive discussion about which parts, rather than yes or no.
Good idea. We've added that bit above.
Sigh. This again.

Not all security vulnerabilities are due to pointer arithmetic or out of bounds execution or pick-your-rust-is-better-idiom.

Heartbleed is a great example. It wasn't caused by an error with how C handles memory or strings or anything else. It was caused by failing to validate untrusted input. Rust isn't going to help you with that.

Could the affected parts be re-written in a way where the boundary checks would have worked? Yes. As they could have in C, C++, D, Fortran, or any number of other languages.

If memory safety and correctness was so truly valued above everything else, we'd be seeing a lot more Ada than we do today.

And this doesn't even cover the fact that not everything can be re-written in Rust, mainly due to compilation target restrictions.

Exasperated Edit: No, I'm not saying code should never be re-written. I'm not even saying that Rust is a bad tool if the decision to re-write is made. What I am saying is that Rust is not a silver bullet. Rust is not going to solve every problem ever. Rust is one of many choices for writing memory safe, C ABI compatible code.

The reasons provided by this article are insufficient to solely justify a re-write in Rust; the exact same arguments could be used as justification for rewriting everything in Ada. Or Haskell. Perhaps some thought will be put in the next "re-write everything in Rust" article that takes that into account.

Then again, none of the past articles have.

?? Surely Rust would have helped against heartbleed? I mean, some servers were leaking private keys because they sent random segments of memory back to clients.
The problem is they implementing their own memory management on top of the standard primitives; they never sent unallocated memory to the client.
rust can also help you make custom memory management safer, e.g. there are several arena crates which hand out allocations with lifetimes, which means the arenas won't be freed before all references went out of scope. And there also is no pointer arithmetic into the arena, you only interact with individual allocations. I don't know if it would have prevented heartbleed, but it enables 3rd-party allocators to provide the same safety guarantees as the rust standard lib does. Something that cannot be said about C because there are no safety guarantees in C in the first place.
There are some safety guarantees in C, it's just that Rust has more. Rust doesn't guarantee total safety, just like C doesn't mean no safety.
It's ... debatable.

Heartbleed implemented their own memory management system (and had a bug in their use of it). This is pretty unusual even in C. It's extremely unusual in Rust, but who's to say that a similar implementation in Rust would come across the same challenges and implement their own memory management too? And write the same bug? Ultimately this kind of system would be unsafe code anyway, so Rust won't help you there. The question is if a Rust programmer would design such a thing (it's very non-Rust-y). The answer is probably "no". However, the same can be said about C programmers and the heartbleed code, so you have a bit of a no-true-scotsman vibe happening here.

So, yes, heartbleed could have happened in Rust too. I do feel it's less likely (Rust more strongly forces you to compartmentalize unsafe abstractions), but all of that is really debatable.

Yeah, the openssl codebase was pretty crazy due to cross platform support over multiple decades...I guess it grew organically and turned into a enough of a mess that the OpenBSD team started the libressl project. There are some pretty good youtube videos about the work that they did.
Thank you for the clarification.
> Rust isn't going to help you with that.

As I noted elsewhere in this thread ( https://news.ycombinator.com/item?id=14753692 ), I've actually been working on a low-level media decoder in Rust. Compared to my earlier work in C (the xmlrpc-c library, for example), my Rust code has stood up very well to heavy fuzzing. My xmlrpc-c code, on the other hand, was written with ridiculous levels of paranoia, and it has been the subject of multiple CVEs thanks to a third-party XML parser I used.

So in terms of practical engineering reality, Rust seems to make a big difference. And even more importantly, it means I can trust other people's libraries a bit more.

Rust's practical advantages seem to be:

1. Runtime bounds checks! I wouldn't have thought that this was the most important thing, but when fuzzing, it's the last line of defense against quite a few potential exploits.

2. Debug-mode checks for integer overflow. Rust defines integer overflow as an error, and debug builds will actually check for it. This turns out to work really well with fuzzers.

3. The borrow checker. In my experience, this is actually less useful than (1) and (2) above in terms of preventing security bugs. But it does help.

So as somebody who's written parsers for untrusted data in both C and Rust, I definitely found that Rust helped me a lot. Of course, Rust can't help with some forms of stupidity, such as writing a bad custom memory allocator and using it to handle key material. OpenSSL's problems go well beyond the ordinary hazards of C.

> 1. Runtime bounds checks! I wouldn't have thought that this was the most important thing, but when fuzzing, it's the last line of defense against quite a few potential exploits.

C.A.R Hoare talking in 1981 about how their Algol compiler customers reacted to the proposal of turning off bounds checking.

"Many years later we asked our customers whether they wished us to provide an option to switch off these checks in the interests of efficiency on production runs. Unanimously, they urged us not to--they already knew how frequently subscript errors occur on production runs where failure to detect them could be disastrous. I note with fear and horror that even in 1980, language designers and users have not learned this lesson. In any respectable branch of engineering, failure to observe such elementary precautions would have long been against the law."

The mainstream adoption of UNIX and with it, C, made many without the knowledge of how computing outside AT&T walls since the dawn of computing looked it, to cargo cult ideas that were proven wrong elsewhere.

But given that victorious get to re-write history and UNIX got adopted by the enterprise, those OSes written in safer systems programming languages get forgotten.

The recent example was to learn about PL/8 and how IBM used it, in a compiler framework similar to LLVM, to do the research that lead to RISC.

http://rsim.cs.illinois.edu/arch/qual_papers/compilers/ausla...

Imagine that! The RISC computer was designed using an OS written in a system programming language using Algol safety checks, including bounds checking, in the 70's.

EDIT: Added a link to the PL/8 research paper.

So your argument is that because rust doesn't solve all problems people shouldn't strongly consider replacing C code with it, even though rust avoids entire classes of critical bug types in C?

I happen to like rust, though I would not suggest that it is the only solution to the classes of problems it avoids. I would, however, suggest that people very strongly consider using languages that avoid the problems that rust avoids whenever possible. Like, literally any time you're considering writing C or C++, at least strongly consider rust or another much safer option.

I agree that there are technical limitations, but I think those should be sought to be overcome. I disagree with your implicit assertion that all languages are equal (or close enough). If it is possible to make a class of error completely disappear then it should be done when not cost prohibitive, and languages can be designed such that there is no cost to avoid certain errors.

Sure one boundary error could have been detected in any language, but there will always be fewer in a language that simply disallows them. Consider how infrequently Gotos are used now there are no longer errors with setting state before a jmp/goto, because modern constrol flow tools function, case, inheritance, generics and others tools have strong semantics with good implementations that work well and reduce complexity.

Unfortunately language adoption is not a pure meritocratic affair. Bad languages can stick around for far too long because of external factors. Consider that Ada never had real use outside the DoD when it was shiny and new. That group isn't exactly known for evangelizing. The Rust community has better marketing strategy and has chosen a highly meritocratic approach to language design.

> It was caused by failing to validate untrusted input. Rust isn't going to help you with that.

Really?

Validation and sanitization are the last, not the first line of defense. It is not about erecting barriers, it is about failure modes. All your software components, from core to border, should fail fast, safe and in a predictable way -- the exact opposite of what happens in C.

In any sane programming language (e.g. Java -- not particularly sane, but boring enough) Heartbleed would have resulted, at worst, in OutOfBoundsException or similar, and the only damage would have been the denial of service. And to do bounds checking, you don't need to have garbage collector -- it is the most basic thing the runtime can do, and performance penalty is minimal. Why it is customary to skip this in C/C++, I don't know.

Lack of bounds checking, not pointer arithmetic or allocation lifecycle, is the major source of security issues with existing software.

Bounds checking is not customary because it is more work. It is more work because arrays in C degrade to pointers, which do not know their length. This is because C was designed on a PDP-7 with 8k RAM. Original Pascal had only fixed size arrays/strings and it was a problem.

http://cm.bell-labs.com/who/dmr/chist.html

> Lack of bounds checking, not pointer arithmetic or allocation lifecycle, is the major source of security issues with existing software.

No, this is not true. Use after free is more pernicious nowadays.

Sometimes I wonder why developers are so masochist with his tools, and so MUCH AGAINST AUTOMATION.

If a language, for example, don't have NULLs and you need to use Sum Types (like ML or Swift) you have solved FOREVER and FOR ALL THE DEVELOPERS that problem.

But say that just because this is one problem among dozens, then is better FOREVER AND ALL THE DEVELOPERS to stay with the problem?

Instead, why not put as our goals to eliminate all the problems that are possible?

Sigh. This again.

The Rust language is more than just memory safety. Memory safety is certainly the most prominent and unique feature of Rust, but the language also includes a lot of features that make writing good, bug-free code easier.

For example:

`Result`, when returned, forces all callees to check for errors. It's all too easy to throw away error codes in C/C++. This is probably one of the most important features in Rust, besides memory safety.

To easily consume an `Enum`, you have to use `match`, which forces you to handle all members of the enum. In C/C++ it's easy to build a switch for an enum, and then later when a new member is added to the enum and you forget to update all your switches.

Support for multiple return values (through tuples) means being able to avoid the nightmare of output pointer arguments to functions.

No NULL pointers.

Unit testing built into the canonical tooling.

Documentation testing built into the canonical tooling.

The `Option` type, which lets you return "nothing". In C/C++ you'd have to return a bool, and again use a nightmarish output pointer argument.

`OsRng` in the rand crate (go ahead, try to write a function that safely reads urandom in C).

No undefined behavior.

The list goes on. The flavor of it, is that Rust makes it easier to write defensive code. Defensive code is code that is hard to use wrong. For example, for a backup solution I built using Rust, I made all the cryptographic types their own unique, opaque types. EncryptionKey, HmacKey, Salt, etc. For someone new to the codebase, these types make it obvious what each function is asking for, and make it really difficult to use the functions or the types the wrong way. And they are super easy to build and use in Rust, see my code: https://github.com/fpgaminer/preserve/blob/master/src/keysto...

C++ would require a whole set of classes, and require instantiating a new class every time I want to add a new cryptographic type. Rust only requires 3 lines per type.

TL;DR: The real magic is that it's easier to do the right thing in Rust.

> `OsRng` in the rand crate (go ahead, try to write a function that safely reads urandom in C).

Nowadays, you should just call getentropy (http://man7.org/linux/man-pages/man3/getentropy.3.html) instead of trying to read from /dev/urandom, unless you have special requirements.

Great example! OsRng will use that system call, if it is available.
> It's all too easy to throw away error codes in C/C++.

Warning is produced by nearly every good compiler. They aren't forced because sometimes I don't really want to check for return values.

> In C/C++ it's easy to build a switch for an enum, and then later when a new member is added to the enum and you forget to update all your switches.

why would you update all other enum values in accordance to addition to a new one? I understand you could possibly be skipping one switch case because you just added it in enum definition but didn't update switch case, but why would you update rest? Is this a forced requirement in Rust? This is bad if it is.

> Support for multiple return values (through tuples) means being able to avoid the nightmare of output pointer arguments to functions.

std::tuple?

> No NULL pointers.

but what if you need them? Lets say a type safe, non-zero nullptr? I understand some people want to bring up whole NULL is bad mistake argument but remember some of us work with maintaining large code where such changes are non-trivial.

> Unit testing built into the canonical tooling. Documentation testing built into the canonical tooling.

This is good argument :)

> The `Option` type, which lets you return "nothing". In C/C++ you'd have to return a bool, and again use a nightmarish output pointer argument.

std::optional? Or many other implementations of optional type? I've been using them since ages(before rust was even born) and writing them is no NP problem. Don't credit rust as if it brought the `Option` type.

> `OsRng` in the rand crate (go ahead, try to write a function that safely reads urandom in C).

Is this intended to be sarcasm? try <random> header and see if it fulfills your requirement, otherwise there are tons of libraries. But wait, what? This is another already solved problem unless I'm missing something.

> No undefined behavior.

Lol do you even unsafe bro?

> C++ would require a whole set of classes, and require instantiating a new class every time I want to add a new cryptographic type. Rust only requires 3 lines per type.

Depends on your cpp skills and judging by this post, they're certainly less than expected from a beginner. I hope you learn about certain languages (even the ones you are defending) before writing things on internet, since 90% of what you wrote won't even come near acceptable so I suggest doing your research properly.

Your comment indicates that you don't really understand the value of ADTs as the switch, option type and NULL pointer comments overlap: in your new code(and it would be be new code since it's rewritten in Rust) you define it to have Some(pointer) or None. Then to access the value you have to switch on and evaluate the None case at any dereference site. NULL cannot happen but you can still pass around a None type.

Regarding safely reading urandom, you don't seem to be aware that concurrency issues occur when accessing it from multiple processes. This is something that the borrow system can aid with by formalizing access to a resource like urandom and not allowing contention for it to occur at runtime.

Also, nobody appreciates aggro kid language.

Some corrections:

* option and result are also available in C++, the former is even standardised.

* random numbers support is quite good.

* C++ compilers will warn if not all members of an enum have been handled in a switch. It's also easy to assert/throw in the default case as a safety measure.

* tuples are likewise supported

* I believe something like your opaque types could be done with templates and tag classes in a similar amount of LOC.

But yes, in Rust it's generally easier to do the right thing. This is the big benefit of learning from others' mistakes and not having to maintain backwards compatibility with ancient decisions.

std::optional don't enforce exhaustiveness; you can get away with accidentally unwrapping it. In Rust this requires an explicit check or explicit call to unwrap()/expect().

To me, this is super important. But yeah, it's still a good thing to have!

IIRC there are TMP-implemented versions of this that are safer (though a bit ugly to use) though.

I mainly agree that Rust is more than about safety. I just wish these other features had a tenth of the vocal support as Safety.

It's even worse here on HN, where the a certain group seem to thrive on blasting not-Rust, especially if that not-Rust is C or C++. I've seen comments to the effect that anyone writing in C or C++ today is literally acting with reckless indifference to life and safety. It's terrible.

It's actually harming Rust. And not just a little bit.
The official Rust community isn't helping itself, either, here. If they were even a little bit as eager to step on lazy "C is bad" comments as to point out how safe Rust is it might help. Lazy reasoning about competitor languages isn't helpful because it inhibits the ability to effectively tout Rust's benefits.

But I've basically stopped commenting in Rust threads. There's too much "not even wrong" as regards C and C++ to be bothered with.

Criticism is just so much easier than constructive arguments. That's why it's rampant in communities, even HN. And controversial subjects (Bitcoin, health, food, Javascript) will magnify the problem.

It's easy to find fault in C/C++. It's easy to parrot the Rust marketing. It's not so easy to actually have spent the time to learn and use Rust, let alone articulate the subtle ways that its design, taken as a whole, is better than alternatives.

Building those constructive arguments is _hard_. I remember reading an article about error handling. It had to have been at least 10 pages worth of content, covering the history of error handling throughout all the old and modern languages, and using examples for where each fails or succeeds. It culminates, more or less, in explaining exactly why the error handling of languages like Rust outperforms in the field of systems programming.

(NOTE: The author of that article was actually arguing for the error system used in the language they developed for their OS, IIRC. But Rust was pretty darn close to the ideal the author was going for, and they pointed out as much.)

My point is that it took 10+ pages to make a solid argument for _just_ error handling. Not many people have the experience, wisdom, time, and willingness to write even a fraction of such insightful content in a comment on HN.

That said, well written, balanced comments still generally float to the top in even controversial HN threads.

EDIT: I would also like to point out something specifically in response to "I've seen comments to the effect that anyone writing in C or C++ today is literally acting with reckless indifference to life and safety."

There is a tremendous amount of pent up anger in the programming community against C/C++. The language should have been put our to pasture a _long_ time ago. Rust is the first language which has a real chance to displace it. So it's no wonder that a lot of us are willing to just burn C/C++ to the ground and jump ship.

Not to mention that as programmers we may be quickly approaching a time when security bugs become a governmental issue, and the _last_ thing we want is the government mandating how we write code. So it is in everyone's interest if we self regulate. Again, that would explain why everyone is kinda jumpy about C and security bugs.

The interesting bit is that it was already happening on the PC world, with C only being used for OS APIs on Windows and OS/2, but most people were actually using C++ (OWL, VCL, MFC), Turbo Pascal for Windows followed by Delphi, VB, Eiffel, Ada, Oberon, Component Pascal...

Then the UNIX FOSS, written mostly in C took over, and set us almost 20 years back in security and safety.

Heartbleed included memory safety violation. A hand crafted Malloc replacement was used to manage buffers. Uninitialized memory of new buffers was able to be read which allowed the extraction of secrets.

Now the reason why some people claim that Rust would not have stopped it, is that a similar leaky buffer system is possible to be written in Rust. This however is just applicable if you just use byte buffers for everything. At that point you become close to emulation. Also if the system malloc is shit, you just use jemalloc which is the standard for Rust. So there is no need to roll your own malloc replacement in Rust

Isn't this just the nirvana fallacy? You're basically arguing that because Rust can't solve all security problems, it's not worth using it to solve some security problems, and the better option is the status quo of using languages that expose all problems.
> Heartbleed is a great example. It wasn't caused by an error with how C handles memory or strings or anything else. It was caused by failing to validate untrusted input. Rust isn't going to help you with that.

Yes, it would. In Rust, the server would have crashed when it overran the buffer instead of sending that potentially-secret memory back to the client. Heartbleed is a great example of why rewriting in Rust is good.

> If memory safety and correctness was so truly valued above everything else, we'd be seeing a lot more Ada than we do today.

The problem was that many companies had certain problems paying for Ada compilers and rather used the free C compiler delivered with their OS SDK.

Actually, Rust would just have panicked in the Heartbleed case: you wouldn't have been able to perform an out of bounds memory access without causing a runtime panic.
Heartbleed came from allowing reads of uninitialized/out of bounds memory. Rust doesn't absolutely prohibit that, but it is an out of bounds memory access error. Python, Javascript, etc. catch that.
Haskell (and any other GC language) has big runtime requirements that rust does not. It's not just about the ABI.

Your argument does apply to Ada, but freeing from the heap in Ada is unsafe, which has made it difficult to use in a safe way for a lot of cases.

Rust really does make an advance in this regard: safety, and no significant runtime requirements.

D and modern C++ might work for disciplined teams, but seem a few steps behind rust safety-wise.

> The reasons provided by this article are insufficient to solely justify a re-write in Rust;

You didn't read the article. He acknowledged that the hyperbolic calls to "IMMEDIATELY REWRITE EVERYTHING IN RUST!!1!!1one" are silly. In bold, the author states:

> What I’m advocating for is much simpler: surgically replace weaker parts but keep most of the project intact.

Which, by the way, is exactly how Mozilla is applying Rust-written rewrites to Firefox (dogfooding their own programming language).

The author focuses on rewriting low-level media decoders in Rust. I have bit of experience in this area. I've been slowly working on an MPEG2 binary subtitle decoder in Rust: https://github.com/emk/subtitles-rs

A while back, I ran my subtitle decoder through "cargo fuzz", and I was pleasantly surprised at the results: Close to half a billion fuzz runs found 5 runtime panics, all of which were detected by Rust before they could compromise security. If I'd written this code in C, several of those errors would have been exploitable. I like to think I'm a lot more paranoid than the average programmer. But the MPEG2 format is gnarly and, sooner or later, I'll miss a potential overflow when bit shifting, or get confused following internal "pointers" in a subtitle packet.

Rust has a few advantages for this work:

1. Rust does not require a garbage collector or other specialized runtime. This makes it far easier to pretend to be boring C code. This is a significant advantage over some other excellent languages like Haskell, etc., which require non-trivial runtimes.

2. Rust is very fast by default. For low-level programming, this matters.

3. The Rust infrastructure for testing and fuzzing is surprisingly good and easy to use, which makes it easier to produce bullet-proof libraries.

The downside is that even if you're already familiar with C++, it's probably going to take a couple of weeks to become comfortable with Rust. And if you don't really understand stacks, heaps, memory layout and references, it may take even longer.

I do agree with the underlying thesis: In 15 years, I'll be heartbroken if we're still facing an endless stream of security updates and remote root compromises. But it's going to require literally billions of dollars of programmer time to put a dent in this problem.

> Close to half a billion fuzz runs found 5 runtime panics, all of which were detected by Rust before they could compromise security. If I'd written this code in C, several of those errors would have been exploitable.

Wouldn't the apples-apples comparison be fuzzing a C program? If AFL would catch the same bugs, Rust isn't better than C in this case.

The difference is not in what was caught by AFL, but what wasn't (and also, what would have happened in C had AFL not been run).
> If AFL would catch the same bugs, Rust isn't better than C in this case.

You can find a list of my vobsub bugs in the Rust Fuzz Trophy Case: https://github.com/rust-fuzz/trophy-case They are:

1. The shift overflow: This was harmless in both C and Rust, I believe.

2. The arithmetic overflow: This was a runtime panic in Rust, resulting in a clean crash. In C, this might have been exploitable with a complex enough attack.

3. The three "invalid slice" errors. All of these were clean runtime panics in Rust, and I'm pretty sure that at least two of them would have been exploitable in C with enough work.

So Rust has a couple of advantages here. Out of 5 errors found by the fuzzer, the worst thing that could happen in Rust would have been crashing the program in a controlled fashion. In C, we would have been looking at memory corruption and quite possibly escalation.

Secondly, Rust's runtime checks actually make fuzzers work better. Even simple checks like "is the end index of this slice great >= to the beginning index?" tend to catch problems almost as soon as they occur.

I think you aren't understanding what parent comment is trying to say. No one is saying rust isn't better than C in some respects, instead, you were comparing Rust + Fuzzing with C and he implied that you should at least use C + AFL if you want to compare properly otherwise it's just BS.
It's a pointless comparison. Fuzzers don't catch everything. What's important is the type of issue that the fuzzers do reveal, because that gives a hint as to how severe the uncaught issues may be.
One implication is that C would have had more errors, but that's a hard judgement to make. It's probably true.

The thing that really matters is that these errors which the fuzzer found aren't exploitable -- memory errors in rust are guaranteed to panic (unsafe aside) instead of susceptible to overflows, etc. Since fuzzing is very much more of an art than a science, this guarantee is important.

The point here is that a runtime panic is not an exploitable event - at the very worst, it's a DoS as it usually results in the program exiting.

AFL isn't even nearly guaranteed to catch everything, but what it's shown here is that the program contained bugs which would've resulted in an exploitable event in C. The program probably contains more bugs, but following this pattern, it's more likely that they result in panics in most of the worst cases, not exploitable events.

With Rust, a panic occurs right away when the fuzzer develops input that performs e.g. out of bounds access. With C, it's possible to go wrong a little but not enough to segfault or to go wrong enough that by accident the access looks valid (for an unintended valid memory address) to a sanitizer.

In that sense, fuzzing Rust is more certain to make the bad things actually be caught than with C where there's a chance that the fuzzer developed input that caused UB but the UB didn't happen to be caught by the mechanisms that are supposed to discover bad events during fuzzing.

(comment deleted)
I don't agree with the underlying thesis: In 15 years, I'll be heartbroken if we're still facing an endless stream of security updates and remote root compromises when all these projects were rewritten in a popular but unsafe language: Rust.

There do exist fast and SAFE language out there. With guaranteed memory safety, null pointer safety, concurrency safety, dead-lock freedom, race freedom, and even with normal syntax. Rust is not one of them. When will all these rust fanboys finally see the light?

Can you be specific about which languages you include in the category of "fast and SAFE"?
D? GC is optional so don't even :D
How much of the standard library works without GC enabled? How many community libraries do?

D has a lot of great things (I am incredibly jealous of their metaprogramming facilities sometimes), but it doesn't seem like many people are successfully using it in the "fast and SAFE" sense as GP defined it.

> How much of the standard library works without GC enabled? How many community libraries do?

Enough to be usable on virtually all platforms that rust is going to target in next 2 years. I hope I'll get proven wrong but that's it for now. And maybe along the time we'll see some decoupling of stdlib from GC too.

OTOH some people like GC too :)

Ada. Algol-60. The much maligned Pascal.
Rather than answering this question directly, let me perhaps explain why Rust is getting so much pushback.

With the exception of dynamic memory, virtually all high-level languages that aren't called C/C++ are memory-safe. Memory-safety is not a new feature. Inherent memory-unsafety was a "feature" introduced by C and its immediate ancestors (and later perpetuated by C++) in order to deal with the performance limitations of 8/16-bit architectures and optimizers that were far more limited than they are now.

For many of the older of us – before C/C++ took over much of the world – safe languages were the norm (with the exception of dynamic memory for languages without automatic memory management).

So, in our experience, Rust doesn't really offer us much except an alternative to automatic memory management that imposes a significant cognitive burden. That tradeoff is not always attractive. It presupposes that any and all forms of automatic memory management are not an option. Not a modern incremental, generational garbage collector, not Swift-style ARC (where unnecessary RC updates are optimized away), not some of the various and sundry automatic memory management techniques that researchers have come with over the years (such as MLKit's regions).

If you have this kind of programming background, the tradeoffs that Rust offers are not at all attractive. Not only are the use cases where you need exactly Rust's value proposition relatively rare, the ongoing and often aggressive evangelism sucks up oxygen in the open source commons, so to speak, that could go towards alternative efforts.

That dynamic memory exception is big enough to drive a truck through. Dynamic memory is so pervasive in today's programs that (I would argue) a language that's "memory-safe except for dynamic memory" has no business advertising itself as memory-safe at all. Maybe it was different in the past.

That said, plenty of applications can easily afford to pay the runtime cost of a tracing garbage collector and don't need to be using Rust. (You might want to anyway, if you're writing such an application—the language is designed pervasively to eliminate as many sources of program incorrectness as is practical, and this comes through in more areas than just memory safety—but it's not the same kind of critical advantage that memory safety is.) In general I tend to think of Rust as a better replacement for C++, and useful for approximately the same use cases.

I'm not sure how I feel about Swift's ARC; it seems like a bit of a hack compared to Rust's lifetimes and I worry that it makes memory leaks too easy, but I haven't worked with it. I don't think I count techniques that aren't available in any language less obscure than Cyclone.

> That dynamic memory exception is big enough to drive a truck through. Dynamic memory is so pervasive in today's programs that (I would argue) a language that's "memory-safe except for dynamic memory" has no business advertising itself as memory-safe at all. Maybe it was different in the past.

1. Many embedded applications do not use dynamic memory at all.

2. The runtime cost of a tracing garbage collector is largely a red herring. In a well-designed imperative program, all the cost involved with GC should not typically exceed 10% or so and manual memory management can only avoid part of that. On top of that, Rust's fallback option for shared ownership (Rc<T> and Arc<T>) are very expensive and can be worse than tracing GC. As I noted elsewhere, Rust is a very poor option when you have to deal with shared ownership (such as with persistent data structures).

3. Tracing GC does raise genuine issues in other situations (stack scanning in a multi-language environment, for example), but it's not the only established automatic memory management technique. There's no reason why you can't have a compiler switch to change to a different implementation.

4. Conversely, tracing GC can also have advantages, such as avoiding fragmentation for long-running processes (assuming the GC supports compaction).

> I'm not sure how I feel about Swift's ARC; it seems like a bit of a hack compared to Rust's lifetimes and I worry that it makes memory leaks too easy, but I haven't worked with it.

There's nothing hackish about Swift's ARC. It's basically bog-standard reference counting, which has very well understood semantics, and then the compiler optimizes away reference count updates that aren't needed. The primary downside of the approach is that it can't handle cycles automatically, but then, neither can Rust. Other than that, it ticks off pretty much all the boxes that Rust does.

> I don't think I count techniques that aren't available in any language less obscure than Cyclone.

I'm not sure why, nor why you would tie it to languages. After all, MLKit is Standard ML, hardly a language more obscure than Cyclone; deferred reference counting was first implemented for Java (lots of memory management techniques have actually used Java as a testbed).

> You might want to anyway, if you're writing such an application—the language is designed pervasively to eliminate as many sources of program incorrectness as is practical, and this comes through in more areas than just memory safety—but it's not the same kind of critical advantage that memory safety is.

If you want to go into a more detailed discussion of Rust with respect to software engineering, then we'll also have to discuss the software engineering costs that Rust creates, and that becomes a fairly large topic.

> So, in our experience, Rust doesn't really offer us much except an alternative to automatic memory management that imposes a significant cognitive burden.

And zero runtime overhead.

> If you have this kind of programming background, the tradeoffs that Rust offers are not at all attractive.

I think you underestimate the attractiveness of zero overhead abstractions.

> And zero runtime overhead.

Please show me an implementation of binary decision diagrams [1] (ideally multi-threaded) where Rust has zero runtime overhead.

Rust has zero runtime overhead only in some cases.

[1] https://en.wikipedia.org/wiki/Binary_decision_diagram

I made a claim of zero runtime overhead after directly quoting the context of automatic memory management.

So are you suggesting that claim in such a context is false, citing BDDs as some example, or are you taking my claim to be more broad than the context warrants, and so are arguing a strawman?

> I made a claim of zero runtime overhead after directly quoting the context of automatic memory management.

And that's what I was referring to. BDDs inherently require Rc<T>/Arc<T> (as long as you want to be memory-safe, at least) and therefore incur significant overhead (reference counting is one of the most expensive forms of automatic memory management). I use BDDs as an example, because there's no way to work around the structural sharing, as it's a requirement for an implementation.

In addition, aiming for zero-cost abstractions is hardly a Rust-only thing. That's more of a Java problem because it only has polymorphic methods and no value types. Outside functional languages, lack of zero-cost abstractions is not a particularly common issue.

Even if your claim is correct, the existence of some programs that cannot be expressed with memory-safe zero overhead abstractions still doesn't entail your original claim. As you just said, you can use Rust's unsafe escape hatch to preserve your desired performance where it's critical and you haven't lost anything from C/C++, but you can still enjoy the safety benefits where unsafety is not needed.

And BDDs expose a safe API behind which you can hide the unsafety, so only a fragment of your system would dependent on unsafe Rust.

So we come full circle to your claim that Rust is not "at all attractive", despite being able to express programs more compactly, more elegantly, and more safely than in C/C++, without losing the performance. So I still don't see the case for this claim.

> Outside functional languages, lack of zero-cost abstractions is not a particularly common issue.

Pretty much only Ada and C++ can provide the zero cost abstractions, and they do so only with heavy syntactic and semantic costs (templates for C++, packages and wordy instantiation for Ada). The Rust language does this as part of polymorphic elaboration, which is a natural and compositional language feature, not some ad-hoc secondary language or restricted module system.

I'm frankly finding it hard to believe you think there are serious alternatives. Certainly MLTon if you want the same specialization done, but you then have the unavoidable GC cost, so you're still back to non-zero runtime overhead.

> Even if your claim is correct, the existence of some programs that cannot be expressed with memory-safe zero overhead abstractions still doesn't entail your original claim. As you just said, you can use Rust's unsafe escape hatch to preserve your desired performance where it's critical and you haven't lost anything from C/C++, but you can still enjoy the safety benefits where unsafety is not needed.

I'm not comparing to C/C++. I'm comparing to other memory-safe languages.

The more general problem is that Rust cannot offer zero-cost abstractions for shared ownership as a result of how it is designed. This is the really killer issue. It's a problem for pretty much any persistent data structure, for example.

> And BDDs expose a safe API behind which you can hide the unsafety, so only a fragment of your system would dependent on unsafe Rust.

The unsafe approach would be to do use an array representation, use indices instead of pointers, and roll your own garbage collector. Or manually remove unnecessary reference count updates whenever you can prove that they are unnecessary. Both of which cannot be easily hidden behind a safe zero-cost API.

> Pretty much only Ada and C++ can provide the zero cost abstractions, and they do so only with heavy syntactic and semantic costs (templates for C++, packages and wordy instantiation for Ada). The Rust language does this as part of polymorphica elaboration, which is a natural and compositional language feature, not some ad-hoc secondary language or restricted module system.

The entire Wirth family of languages qualifies, too. Or Eiffel. Or Fortran. Or Modula-3. As do more recent languages such as Nim and D. Honestly, off the top of my head I can't think of an imperative language with native compilation that doesn't and isn't totally obscure, other than Swift and Go (and even they only some of the time). Note that zero-cost abstractions need to only exist, not that they have to be the only option. Languages can and do provide both expressive constructs that come with overhead and less expressive constructs that are overhead-free. 90:10 rule, premature optimization, and all that.

In addition, parametric polymorphism cannot ever have a zero-cost abstraction (or rather, the term has no meaningful definition in this context), because you pay for it either in runtime overhead (shared generics) or code size (specialization).

I also wouldn't bring up syntactic and semantic costs; that's throwing stones while sitting inside a glass house. Rust is probably one of the worst offenders in this regard.

> The unsafe approach would be to do use an array representation, use indices instead of pointers, and roll your own garbage collector. Or manually remove unnecessary reference count updates whenever you can prove that they are unnecessary. Both of which cannot be easily hidden behind a safe zero-cost API.

There are potentially many unsafe approaches, and possibly even some safe ones.

> The entire Wirth family of languages qualifies, too. Or Eiffel [1]. Or Fortran [2]. Or Modula-3 [3]. As do more recent languages such as Nim [4] and D [5].

[1] Doesn't support expressing stack allocation patterns, which are essentially to achieving true zero-cost abstractions.

[2] Oh yeah, that'll be easy and maintainable to program.

[3] Doesn't support 64-bit Windows. Verbose like Ada. Abstraction is weak compared to Rust. Also doesn't support expressing stack allocation.

[4] Nim requires a GC, so not zero cost. It also has surprising runtime semantics. For instance, fields that are are guarded by a clause raise runtime exceptions. These would require different cases which are checked for exhaustiveness statically in Rust.

[5] D is not memory safe for non-trivial programs if you're not using the GC.

Clearly you and I have a different understanding of zero-cost abstraction.

> In addition, parametric polymorphism cannot ever have a zero-cost abstraction (or rather, the term has no meaningful definition in this context), because you pay for it either in runtime overhead (shared generics) or code size (specialization).

Code size is not a problem when discussing zero-cost abstractions. Honestly, it just seems like you're grasping for something to nitpick on.

> I also wouldn't bring up syntactic and semantic costs; that's throwing stones while sitting inside a glass house. Rust is probably one of the worst offenders in this regard.

I have no idea what you're talking about. Once they removed all the special syntax for pointer types years back, Rust is very readable to anyone from a brace-based language tradition.

> Doesn't support expressing stack allocation patterns, which are essentially to achieving true zero-cost abstractions.

Says someone that never wrote a single line of Eiffel.

That is what local variables defined as expanded classes are for.

    local
       array: expanded ARRAY[INTEGER];
    do
       array := <<1,3,2>>
       sorter.sort(array)
       ....
    end
> Doesn't support 64-bit Windows. Verbose like Ada. Abstraction is weak compared to Rust. Also doesn't support expressing stack allocation.

Says someone that never wrote a single line of Modula-3.

    TYPE
       Time = RECORD
          seconds: INTEGER;
          milliseconds: [0..999]
       END; 

    PROCEDURE MyProc =
    VAR
       t: Time; (* Stack Allocated *)
    BEGIN
       t.seconds := 0;
       t.milliseconds := 0   
    END MyProc;

Being verbose is a virtue in large scale software development.
> BDDs inherently require Rc<T>/Arc<T>

"Zero-cost abstraction" means "You couldn't have coded it any better yourself." If the problem requires a certain amount of overhead, than an implementation of that solution is considered zero-cost. Rust can't change the laws of math.

Maybe Bjarne should have called it the "Zero additional-cost abstraction" instead; I think it'd clear the principle up a lot.

> If the problem requires a certain amount of overhead, than an implementation of that solution is considered zero-cost. Rust can't change the laws of math.

His contention is that languages with GC don't require reference count updates, and so manipulating the BDD graph is much cheaper in these languages since the resource accounting overhead is deferred by some non-deterministic time.

You can still write a GC in Rust and use it for those types.
First, "you can write a GC" in Rust is not seriously an answer. You can't do it without unsafe code, it would be a lot of effort to just purposely avoid using a GCed language. And the existing efforts to do a GC in Rust are very simple mark-sweep designs that (unsurprisingly) don't even support generational collection.

Second, the reason why I use the BDD example (or, more generally, persistent data structures) is that it's the simplest way for online discussions, because (unlike simpler examples), it's not amenable to pseudo-solutions that don't resolve the underlying problem and that you don't have the space and time for.

The underlying problem is that Rust doesn't really do safe zero-cost abstractions for multiple ownership, and multiple ownership crops up more often in actual Rust code than people like to admit (global caches and memoization often end up with using cloning). You have to deal with it either through Rc<T>, Arc<T>, or cloning, of which cloning is the most common solution, because you don't have the footprints of shared ownership all over your code.

Have you seen crossbeam? That's not mark and sweep.

As I said elsewhere, your definition of "zero cost abstractions" differs from what the term means.

I know about crossbeam vaguely (mostly because the non-blocking concurrency is of interest to my research), but due to lack of documentation, haven't really dug into it and am not even sure what it has to do with GC?

> As I said elsewhere, your definition of "zero cost abstractions" differs from what the term means.

I'm going by Stroustrup's definition [1]? If your argument is – I'm not sure here – that "Rust gets zero-cost abstractions by limiting what you can do to beat its normal mechanisms", then that's not terribly convincing. What it boils down to is that multiple ownership is a weak spot of Rust, as for other languages that attempt the compile-time memory management thing, such as ParaSail. TANSTAAFL, "There ain't no such thing as a free lunch." No compile-time mechanism can solve the reachability problem for arbitrary runtime graphs without adding some overhead somewhere. Rust does zero overhead for certain kinds of graphs, but still needs overhead for others.

[1] http://www.stroustrup.com/ETAPS-corrected-draft.pdf

Crossbeam's epoch based collection is basically a form of GC, for certain kinds of data structures.

Yeah Bjane's definition doesn't say "no overhead", it says "no extra overhead." If your data structure requires a GC, then writing a GC for it is a zero-overhead abstraction. What I'm saying is "gotcha, you need some runtime support for this" is not contradictory to zero-cost abstractions.

> If your data structure requires a GC, then writing a GC for it is a zero-overhead abstraction. What I'm saying is "gotcha, you need some runtime support for this" is not contradictory to zero-cost abstractions.

There are two points to be made here.

1. The problem is not that a data structure needs GC; it's that reference counting (or worse, atomic reference counting) is about the highest-overhead garbage collection in existence. It's popular because it's easy to implement, has mostly predictable performance, and can be implemented as a library without compiler support, but performance is not one of its virtues. The cost really becomes absurd in the `Arc<T>` case, where you have an atomic operation for each reference count update. Nobody actually implements performance-sensitive data structures using naive atomic reference counting outside of C++ and Rust.

2. Persistent data structures (or anything with structural sharing) are, as I mentioned, just the simplest example. They are suitable for illustrating the problems Rust has with shared ownership, but shared ownership is not limited to those. Rust also has problems with shared ownership in a number of other scenarios (such as global caching or any scenario where object lifetime depends on the semantic state of a program).

The underlying problem is that whenever you approximate an undecidable predicate (pointer safety in this case) with a decidable subpredicate, then any zero-cost abstraction claim usually falls flat, because there are typically other decidable subpredicates (not even counting throwing a full theorem prover at the problem) that can handle cases without overhead that your approach can't. In the case of pointer safety, model-checking approaches would be an obvious and well-known example.

Obviously, these alternative approaches may carry different software engineering overhead, but a claim about an abstraction being zero-cost is independent of software engineering costs (not to mention that this is an area where Rust is hardly without its own issues).

> His contention is that languages with GC don't require reference count updates, and so manipulating the BDD graph is much cheaper in these languages since the resource accounting overhead is deferred by some non-deterministic time.

To be clear, the "contention" is the well-known problem that reference counting (especially atomic reference counting) is one of the most expensive automatic memory management techniques in existence, and it takes pretty significant efforts to get it on par with a modern tracing collector. That's because reference counting has high overhead and poor cache locality (as it comes with a built-in pointer chasing requirement even when you assign a reference).

That the cost is deferred has nothing to do with it.

> It presupposes that any and all forms of automatic memory management are not an option.

You might not want to make that strong assertion without spending some time with the language. Rc/Arc exist or if you want to build a GC into Rust nothing is stopping that. You can break out unsafe and start hacking away, in fact that's what the arena allocator crates do today.

The space where memory and performance matter has very few options, which is why you see those of us who spend time in that area excited about Rust.

> You might not want to make that strong assertion without spending some time with the language. Rc/Arc exist or if you want to build a GC into Rust nothing is stopping that. You can break out unsafe and start hacking away, in fact that's what the arena allocator crates do today.

You're misreading what I said. I didn't say that Rust doesn't have Rc<T>/Arc<T> (given that I explicitly mentioned it in other comments). My point was that in order for Rust's approach to memory management to be worthwhile, automatic memory management cannot be viable (or you get a much simpler way of ensuring memory safety). Rust also offering a limited form of automatic memory management does not change that.

> The space where memory and performance matter has very few options, which is why you see those of us who spend time in that area excited about Rust.

I did not deny that Rust is an interesting option if automatic memory management is not a viable approach.

> I did not deny that Rust is an interesting option if automatic memory management is not a viable approach.

I think this is the main niche in which Rust can compete, while of course rust community want to attract people with different backgrounds (eg pythonists, webdevelopers etc).

It's like you say, if I don't need the performance or I am not memory constrained then I will just use GC'd language.

There are so many:

Pony, ATS, Sing#, Spec#, Felix, Gordon, Æminium, DPJ (Deterministic Parallel Java), Kilim, Haller and Odersky. A lot of more linear type languages, like PRFJ or OIGJ. See e.g. http://www.doc.ic.ac.uk/~scd/fast-cheap.pdf

I'm not sure about Factor yet, but it looks good and beats Rust in performance and features also.

So which of those don't depend on an unsafe runtime?
(comment deleted)
So what's your language of choice that is not eventually built on unsafe code?
> with normal syntax

what does this mean?

(foo a b c)

You made me. :-)

Is there any way to lessen the burden by automating conversion of straightforward portions of a C codebase to Rust? They seem similar enough conceptually and semantically, if not syntactically, that a lot of boring C code might be fairly easy to translate?
That doesn't convert C to Rust. It compiles C into Rust as a target language, bugs and all. Raw pointers in C become raw pointers in Rust.
Yeah, I suppose the larger challenge is how to convert unsafe C to safe Rust.
Most of the problems revolve around "how big is it". (The three big problems in C are "how big is it", "who owns it", and "who locks it". C has no language constructs for any of those, while Rust does.)

If a C program works at all, there has to be some computable expression for the length of a C array. Code that uses an array passed as a pointer has to know how big the array is, even though C lacks a language construct for this. The problem is finding that expression. For many cases, it can be automatically inferred, especially if you have cross-module analysis and can see where the original array came from.

I once proposed an extension to C to allow expressing array size information.[1] Discussions indicated it was technically sound but politically too much trouble. It gives a hint, though, of how to approach size information in C. Instead of

    int read(int fd, char buf[], size_t len);
one would write

    int read(int fd, char& buf[len], size_t len); 
Same generated code for the call, but now the source code contains size information, which could be used for subscript checking by the caller and callee. A serious C to Rust converter needs to be able to detect relationships like that.

It doesn't have to be 100% automatic. If the converter could knock off most of the easy cases (especially those involving strings), and accept hints on the hard ones, it could be usable.

[1] http://www.animats.com/papers/languages/safearraysforc43.pdf

It doesn't provide any additional safety by itself, but it does provide a good starting point. Once you've Corroded your existing C code, you can then replace the unsafe Rust abstractions (like raw pointers) with equivalent safe ones (like references), one at a time. This way the manual part of the conversion doesn't have to be done all at once.
Is there anything that prevents this conversion of raw pointers to references from being automatable as well?
If C was able to encode Rust's semantics around references, you wouldn't need Rust in the first place.

You might be able to get it to work sometimes for a very simple subset. I'd be extremely skeptical that it'd be very useful, though.

I agree with "sometimes, for a very simple subset" but I think there's a good chance that can still be very useful. A lot of uses just are super simple, and that may be obvious to the computer in cases that aren't obvious to the human. If we can remove the need for the human to reason about those, that can be a big help.
Rice's theorem.

That's an overly glib answer. The fully general form of this problem is undecidable, but it would be theoretically possible to build a "reverse borrow checker" that analyzes a Rust program, detects raw pointers that are provably used exclusively in ways compatible with Rust's lifetime semantics, and converts them to references. But it would probably be a fairly major project requiring lots of specialized knowledge, because lifetime semantics are complicated. Nobody has attempted it yet as far as I know, although the author of Corrode has expressed interest.

Yeah I mean, compilers don't fix bugs. I don't know what you want. This is taking the "sufficiently smart compiler" idea to absurdity.

As part of an incremental re-write or port, this is still useful. It is extremely close to being able to straight-up cross compile CVS, for example.

Has anyone done any in depth explorations of the safety and security of rust code vs well written C or C++?
it's all in the "well written" part. of course well written C/C++ is good. the very point of Rust (and others, like Ada) is to admit that we, programmers, cannot do good work all the time.

anyone thinking "I'll just write these 50k SLOC very well so it'll be ok" should not consider a career in programming.

Well written the hard part there. I am riding on on the idiomatic C++11/14/17 train right now.

Life over here is great, but I can the warts of the language looking backwards. The promised land in the future doesn't look quite as bright as the promises Rust offers. The only thing keeping me from trying it is the giant codebases in my current projects.

> I am riding on on the idiomatic C++11/14/17 train right now.

How do you see it?

Nowadays I only use C++ on hobby projects or when Java/.NET need some kind of integration work.

To me it seems that as code bases grow organically, it will become very hard to get which code is in which ANSI version, specially problematic given some of the changes that took place between standard revisions.

At both of my jobs, I am working way too much, I am working in pre-C++11 codebases which now allow C++11. Both are working to for -Werror everywhere and that helps a huge amount, and we can try to get more warning listed and make broad but subtle changes to the codebases.

At one place we are in a race before a tight deadline and at the other we are breaking a large monolith into smaller packages. At one place we implement a new practice for all our code, and at the other we implement all our best practices as we chop code out of the monolith. Both places are seeing a reduction in bugs. The place with the packages is probably reaping a larger benefit because they are aggressively re-working old code and have better test coverage and can do so with confidence.

Code bases do grow organically, but like places they can be tended and pruned to make impressive orchards or topiaries or left to the wild to become impassible jungles. Tools like RAII, exceptions, classes, etc... are just tools for managing this.

I think the tools in C++11/14 are at least as powerful as in any language except perhaps Rust. Every time I hear a C developer say "C can be just as safe..." I am imagine a person with nothing but a pocket-knife trying to manage a whole forest.

Thanks for the overview.
Am waiting for Coq developers to start showing up and asking for Rust projects to be rewritten using Coq / Compcert.
Sadly Compcert is not foss, meaning that they will have a huge problem if they try to push it everywhere. I think that the age of non-free languages and implementations meant for the general public is over, even MS has made their C# and F# implementations free.
Compcert is guaranteed to compile correct C code to correct assembly (given its TCB assumptions). It doesn't say anything about incorrect C code. So in order to benefit from CompCert, first you have to prove that you have valid C in the first place, which is no easy feat. You'd probably be better off using a language that's designed with verification in mind, like Cogent or ADA/Spark, or waiting for lambda-Rust to become production ready, since in those cases you won't have to prove tedious bureaucratic memory safety invariants for the vast majority of your code, and can focus on functional correctness (or, if you just care about memory safety, you can stop there).
Is this article "Use Rust" or "Stop using C"?

I mean both are reasonable arguments that get made often on here, but the one doesn't necessarily follow from the other.

I think its a little bit of both. Primarily it is aimed at legacy software. IMO not a lot of new code is written in legacy C, so we have a problem with having a ton of dependencies written in a way that may not be the safest or most reliable (from recent experiences). The authors suggestion is to rewrite parts of those applications that tend to be buggy (mostly I/O parts) in Rust.

I really hate to see the naysayers comment on this article without even having read it. I think the author made a very good point.

In my opinion, there are more reasons to rewrite Rust code in C.
such as?
E.g. ABI compatibility, multi-platform support, tools, open source code base, community, etc.
ABI compatibility: Not really solved in C++ - see MSVC versus Mingw. If you're coming from the standpoint of using a Linux distro or BSD you enjoy a sanitized environment from the start.

Multi-platform support: Pray that your project's build system makes it straightforward to get all the dependencies going on every platform. Pray that your dependencies are easy to access and of the correct version. Pray that the manufacturer's fork of an ancient gcc isn't too buggy to use. C made it possible, not easy.

Tools: Both languages are too impoverished to have tooling as comprehensive as the stuff available in, for example, Java, although VS pushes very hard on this front. rustc already gives better error messages than any C++ compiler.

Code base: See the build system problem. Maintaining open source projects in C and C++ is an exercise in endurance. Single header file libraries have come into vogue as a result - and they're a hack. There is a lot of decent code in both languages not being used because it's hard to get running.

Community: Rust is in a better position here in part because it's smaller. If I encounter a C++ hacker in an online space it's just as likely to be an aggro kid as a seasoned pro.

My point was explicitly about C, not C++. All these points are solved in C, decades ago.
Or write in Haskell in the first place.

Good Haskell code is rather fast, but that's beside the point. For many projects, the only measure of goodness should be how nimbly one can then use and experiment with one's code. In Haskell, like Lisp before it, one ends up with a language to use one's code. Like writing a Mathematica package and getting all of Mathematica for free, only better.

Well Rust seems like a nice enough language if blog posts are anything to go by. But I really cannot unless we something like RustPython and Rython to replace CPython and Cython. (If anybody does write a new Python distribution on rust I named if first)
Someone has already done the honors:

    https://github.com/shinglyu/RustPython
Should have seen it coming. Though it seems to be a one man show for now.
We need Rust to have great support for ARM microcontrollers before the IoT industry really takes off.
The relatively low portability of rust programs is definitely one of its largest shortcomings.
Can you elaborate? Although haven't tried it myself, I was under the impression that it's quite possible to write low level code for at least for x86 and ARM (and AVR?).
What aspects of support are you missing today?
Is it really the time, yet, to start advocating for rewrites in Rust? Worth considering for new projects, definitely. Using to write new components of existing projects, maybe. But rewriting existing work?

I'm concerned if we start pushing that too much too early, the initial friction will burn people. You only get one first impression.

For anyone who thinks "yes, now is the time" I have questions for you:

Have you released and distributed software written in Rust? What's the install story like for end-users? Is it in a repository for a major OS (e.g. can I yum install it, or apt-get it) and if so which?

As far as I can tell there's no major package manager accepting or even ready to accept programs written in Rust yet. Am I misinformed?

I believe Firefox as of recent versions requires a Rust compiler to be available, and that's a pretty bread-and-butter application to have in your distro's package repository.
You should only need a rust compiler to compile Firefox.
Most distributions require that packages in the repositories are built with tools from the distribution.
> As far as I can tell there's no major package manager accepting or even ready to accept programs written in Rust yet. Am I misinformed?

At least Debian, Fedora, Arch, and Gentoo have rustc and cargo in their repositories. Oh and Alpine, recently. FreeBSD (IIRC) has it in ports.

In the not-too-distant future, there's a pretty important package that will require Rust: Firefox. HEAD already does today.

For Debian at least, cargo isn't even in stable yet AFAIK.

And even then, having the compiler and package manager available is a step along the way, but insufficient. Anything non-trivial depends on libraries, which with C programs are typically also packages... which for my project means I need to create 73 Debian packages to distribute my software. That's a big hurdle.

I thought it made the cutoff. I could be wrong. I was more worried about 1.15, which did get missed, ugh.

Debian has made a tool, "debcargo", to automatically turn crates from crates.io into Debian packages, so it should be "just run this tool." I have not used it myself though.

I think it's fair to say that anyone releasing software written in Rust on Debian right now has extra work to do, and is likely to be treading new ground.
Totally! That's far different than "no major package manager accepting or even ready to accept programs written in Rust yet", though.

Oh, I thought of something better than just the compiler: https://github.com/burntsushi/ripgrep#installation

* homebrew

* chocolatey

* arch

* gentoo

* fedora

* RHEL/CentOS

* Nix

All have at least one Rust program packaged :)

For RHEL/Centos/Fedora (the only ones there I would call "major") you have to enable a separate repo, which isn't really the same as being in the official repos.
Also openSUSE and SLES. Yes, we're still around and doing interesting stuff.
Is it really harder than making autotools work?

Anyone releasing software in C, Python, Haskell, Ruby, Lisp, or whatever language has extra work to do. I don't think there's any sizeable difference between any of them.

The biggest problem is that distributions have their own build systems and cargo just doesn't fit in a variety of different ways (not to mention projects that pin nightly compilers).

Distributions such as Fedora and openSUSE need to have a package for everything installed on the system (and everything required to build said packages). Now take into account the you can have multiple versions of the same library in a single rust project. While you could handle all of this on paper, automating it and putting it all into every distributon's build system is a very big task.

Ruby has similar problems, NodeJS is even worse than Ruby in this respect but I believe that Rust might make this the hardest for distributions. Personally I've never liked cargo that much as a user either, but as someone who works on openSUSE and was thinking about packaging rust packages I decided against it. It's just far too difficult and I'm not convinced it's worth the effort, since it feels like people have forgotten the reason why distributions exist in the first place (to provide a cohesive experience and provide you seamless management of your software). Having a shiny new package manager for every language just makes life difficult for everyone involved.

(comment deleted)
But you do realise that pressuring distributions in that way (when there are still issues with integrating cargo and crates into our existing build systems) won't result in Rust being properly supported right? There will be some hack to get Rust to work "well enough" to build Firefox, and if someone wants to start packaging more Rust stuff then all of the work would either need to be redone or started from scratch.

I'm saying this as someone who has started writing their projects in Rust and has plans to ship said projects as part of openSUSE and eventually SLES. If you cannot satisfactorily maintain a Rust package inside OBS then it's a non-starter. I imagine that many other distributions feel this way. We were burned with Ruby (and continue to be burned by it) and I doubt that anyone is going to jump on the "just auto-generate an RPM for every version of every crate we need" solution.

It's great that Firefox will have Rust code, but I'm not convinced that will make the situation better for distributions. It'll just make the packagers more stressed out.

All I can really say is, we're interested, willing, and actively working with distro maintainers on fixing their issues. It's something we care about.

It is just one of many things on our plate, though.

While I am avid supporter of Rust, I can't help but feel this post is not right. If Rust is so much better, why not prove it by writing software in Rust, instead of words. After all, if Rust is so much better, the result will speak for itself.
In this case it seems the author is writing about the concrete results they've already obtained, not about something abstract.
"Rewrite it in Rust" is the new "Stallman was right" thread.

Its an echo chamber of fandom. Over time I've come to despise "evangelism" or any kind. I'm sure Rust is great. I just don't think it's news every time a Rust fan says that its great.

YouTube lectures of people actually using it? That would be interesting. Interviews of people actively porting a large C project to Rust. That would be interesting.

Rehashing its feature sheet? Not so much.

The author is actually using it, to actually rewrite portions of C projects in it, and writing about their experience doing this in practice. For example, the linked paper is about using Rust at the I/O boundary in an existing, complex system.
Except that the article is actually just the feature sheet of Rust. I would rather the article had been a link to that paper.
uhhhhhh, multiple links in this block on the post:

"That’s because I have been working on this subject for a long time now:

* I did multiple talks on it * I even co-wrote a paper * I did it both as client and personal work"

Yes, I saw those links. The article that op linked to though was another Rust feature sheet blog post, though.

This was days ago, why do you care?

One of the reasons why I'm super hesitant of learning Rust is the attitude and emotional based opinions of the community. I picked up Python due to my work and I love it and I'd never think I would before trying it. But I also never in my travels seen Python people advertise it negative with "<somelang> SUCKS! FUCKING IMPOSSIBLE! GIT GUD AND USE PYTHONN!" about ANY widespread or niche language but instead they just keep positively gushing over Python: "how clear", "how succinct", "formatted by significant whitespace", "readable", "simple", "pythonic", "wide array of modules available", etc.

When someone in one message both recommends Rust and says that it's absolutely impossible to ever write correct programs in C or C++ that are more than few lines long what am I supposed to take away from that? Rust itself uses C++ written LLVM, is it unreliable too then? Seriously... And implicitly, anyone liking C or C++ is an idiot and a bad programmer.

I've been programming in C for 17 years. Now I'm writing (and rewriting) image processing and encoders in Rust and I love it.

It's not just memory safety. Rust has sweet error handling — the syntax is almost as noise-free as exceptions, but code flow is as predictable as error codes. In Rust I handle rare error cases that I wouldn't have bothered with in C (and thus my Rust programs fail in orderly fashion instead of running with garbage values).

Runtime arithmetic overflow checks have saved me many times. Knowing I have this safety net I can be cavalier about using smaller integer types.

I don't have to free memory explicitly, and yet peak mem usage is as minimal as it can be, and I did not have a leak yet.

And the whole ecosystem is fantastic compared to C. There's a culture of having unit tests. Ease of using dependencies via Cargo, and the zero-cost abstractions, help having dependencies broken down into small and focused libraries.

> Rust has sweet error handling

I feel like a lot of the cool things in Rust get obscured in the never ending safety dance. There is some rad stuff in Rust compared to its closest competitors (C and C++) -- cleaner error handling, a standard package manager, no aliasing -- I want to hear about what else Rust can do for me! More safety guarantees, ehhh, I'll take them but they aren't a huge win in our work.

A huge win compared to C is fearless refactoring. Making changes to an existing codebase in C is a minefield. Refactoring in Rust is a breeze.
> the syntax is almost as noise-free as exceptions

No.

const USAGE: &'static str = "usage string";

I did rewrite it in Rust. I rewrote a small low level command line app in Rust. I really wanted to like Rust going in but I freaking hated it going out. They had a few good ideas but they never knew how to say no. The part I hated the most was the Rust macro language. And for real low level to the metal systems programming, everything is unsafe; so you may as well be writing in C.

Go is pretty minimal. They knew how to say no. I like modern C (C99 and C11). It has most of the good ideas from C++.

As of the most recent release, that's now

    const USAGE: &str = "usage string";
and there's talk of maybe making it

    const USAGE = "usage string";
> The part I hated the most was the Rust macro language.

We don't like it either; there's a replacement coming. We reserved the "macro" keyword before 1.0 and made the current one use the less-good "macro_rules" to help ease the eventual transition.

> We don't like it either

But.. but.. Scheme macros are so nice!

Totally! It's not about the fundamentals, it's about things like "macros are global" and "almost entirely hygienic but sometimes not", stuff like that. Stuff that would be backwards incompatible to just fix.
The comment was about error handling syntax, not constant declaration syntax. The comparison being made is between `result = foo(); if (!result) { ... }`, `foo();`, and `foo()?;`.

> And for real low level to the metal systems programming, everything is unsafe; so you may as well be writing in C.

Sounds wrong to me. People have done things like booting up x86 with all of the hardware bit-twiddling behind safe interfaces (for example: https://os.phil-opp.com/).

setjmp wasn't even supported. I had to use an LLVM intrinsic. This only barely worked if I put the setjmp and the longjmp in separate files.
Why is setjmp such a major issue for you? It's a C language feature, not a "real low level to the metal systems programming" requirement.
If you are calling C or assembly and there is any sort of processor exception, you need to establish a signal() handler and you will need setjmp/longjmp to re-establish a safe stack frame.

Yes, this is a C/assembly thing. But it is also a Linux/BSD/Unix thing. You really cannot call Rust a systems programming language if signal/setjmp/longjmp are not fully supported. It just goes with the territory.

Linux/BSD/Unix are hardly the only systems programming environments. I'd hesitate even to call them the majority.

And for now, there are definitely ways to handle signals using libraries.

> Linux/BSD/Unix are hardly the only systems programming environments. I'd hesitate even to call them the majority.

Do you have any source that can confirm that? Because what you wrote seems really wrong. I see linuxes/bsd/unix EVERYWHERE (Android/iOS/OSX/almost all backend servers etc.)

I'm thinking of embedded systems and desktop machines- the first tends not to use an OS nearly that big (if any at all), and the second tends to use Windows.
> Runtime arithmetic overflow checks have saved me many times. Knowing I have this safety net I can be cavalier about using smaller integer types.

As a note to others, arithmetic checks doesn't happen in release builds unless you used something like checked_add, add "debug-assertions = true" to [profile.release], or use -C overflow-checks flag with the compiler.

https://github.com/nox/rust-rfcs/blob/master/text/1535-stabl...

As someone who really likes C and C++ I feel like the biggest reason for me not even thinking of Rust as a viable language right now is the community attitude. It seems so damn hostile to C and C++. Anyone who thinks C and C++ is viable is a misguided idiot, bad programmer, writing unsafe software, etc. to these people.

Some badass below even just said that "writing C++ code longer than a few lines without UB is humanly impossible". Apparently all these FUBAR C/C++ systems (Linux and Windows kernels, all? web browsers, LLVM that the dear rust uses, device drivers, web servers, router software, VMs of Lua, Python, C#, Java, ..., etc.) work well enough to transfer that kind of garbage to me.

It's a bit like the decades old vim vs. emacs, C vs. C++, C++ vs. C# vs. Java, etc. feuds.

I think you see some of that since quite a few people have spent decades in C/C++(myself included) and have had exposure to experiencing these exact problems.

I'm still a huge fan of C++ but Rust gets me to where I want to go with C++ with much less fuss and a lot more confidence.

I'm a big fan of Python lately but neither I nor Python community at large goes "you fucking scrub, use Python, fuck you, wtf are you doing, stop making broken progs for ppl and wasting your time, omg, obsolete shit you use" and instead highlight upsides of it like readability, plentiful modules, widespread use of it, etc. Meanwhile Rust community seems full of negative advertising in the tone of "fuck C, fuck C++, Rust is safer and better, always, for everything". I see this every time Rust is brought up, without exception. Like WTF? I can understand people disliking C, C++, Lua, whatever, but not going batshit insane over them and saying you need stars to align to write a C program that isn't broken and that to write an unbroken C++ program is impossible...
I think what you're seeing is less the Rust community and more the community of computer users that have been forced to use C/C++ software for decades now. Up until Rust, there were many easy reasons why developers could justify their choice to use C/C++. And so users had to live with the frustrations of running code written in those languages because there really were few well-known alternatives.

Now Rust comes along with its safety claims (which are mostly true) and suddenly these computer users have what they believe is a legitimate complaint. They now see the frustrations with running C/C++ software as no longer facts of life but, instead, development externalities that users are forced to pay based on the decisions of the developers.

And so you have a bunch of people who've likely never written much in either C/C++ or Rust who are trumpeting Rust because they're sick of dealing with CVEs, segfaults and all the other 1970s baggage that the C-cosystem imposes. And it doesn't help that C/C++ developers tend to react defensively and take the advocacy as an impugnment of their developer honor. Saying "It's only inept C/C++ developers that write code with UB or memory safety issues. Disciplined developers can write safe C code!" just infuriates people even more since the weight of evidence suggests that any non-trivial C program will eventually have a bug or vulnerability of this kind. Humans make mistakes. That's an immutable fact that we need to take into account when relying on humans to do anything. Programming is a thing that is part of that anything. To err is human, to catch as many of those mistakes as possible is the compiler's job.

But I think both the Rust community and the Rust-resistant community should be wary of those trumpeting Rust who are part of neither of those groups. There are many good reasons to use Rust and some good reasons not to. Often times a hybrid Rust/C solution would be the best. We should be careful to try to take ego out of the decision making process as much as possible. And we should remember that when users are asking for Rust, what they're really asking for is an end to the pain that they've had to deal with. If it can be accomplished in some other way, then that works too.

For what it's worth, while I agree that there is a vocal minority within the Rust community that can be militant this way, it's not an official position, and it's explicitly not endorsed by the Rust core dev team.

Personally, I'm considering C++ for a new software project despite my extensive background in security. I think Rust is a great language, I just don't have much interest in it.

In official Rust spaces, attacks like that are not allowed. We don't directly reference other languages in any official docs and such, to not promote this kind of attitude.

It is true that we built Rust to address shortcomings of C and C++, some some form of crtitique has to happen. But many Rust programmers, and especially Rust leadership, will gladly say there's still some good reasons to write C and/or C++ today. Many of those reasons will still be around for a very long time.

There's critique (and I have lots towards both C and C++ but nothing fits my hobby better and all libs I like are in it and I know them the best so..) and there's just being downright stupid and insulting("stars aligning to write C", "humanly impossible to write C++", etc.).

In any case Rust is still solidly on my list of things to learn to become a T-shaped person with lots of insight from different angles but it's annoying to even be unable to skim through comments without seeing garbage, this doesn't happen that often, even the Java, C#, C, C++ quartet stopped going at each other's throats online a long long time ago and it's just skirmishes now and not a constant onslaught.

I absolutely agree. Being stupid and insulting is not good, both in general and for the language. Not acknowledging other languages' successes means that we have blind spots for improvements, not to mention things like you've commented all over this thread.

As others have said, I think this is more of an HN issue than anything else; you won't see this kind of discourse in Rust-centric spaces. I know that's not super helpful, but I'm not a HN moderator, so...

Show me the programming language community that's a fan of the language it's intending to supplant and we'll talk. :)
D has a much better attitude towards it.
I've never seen Python or Lua community do that so far. But Python is its own animal (which IMO is only highlighting how good it is), it's not supplanting anything. Rust meanwhile both hates C and piggybacks on it (using LLVM, similar syntax, cited compatibility and coexistence with C). Lua is similar, no hate, its own animal, custom syntax, good in its niche (Python's niche seems to be literally everything not super performance critical BTW). Same for Erlang and Elixir, custom, different languages that are masters of their niche (and go see people gushing over these two on HN, they don't shit on other languages but say how good these are, no "Pfsshh, it's 2017, only idiot would write a reliable service in C, you can't program C ever, it's broken").
I've never seen Python or Lua community do that so far.

Back then, wasn't it readable Python versus unreadable Perl?

You have a point. Python was definitely pitched as a perl replacement. We forget because it pretty much won.

Lua has it's own problems, of course, but I don't see it as a language developed as a consequence of frustrations with another.

Lua was developed for legal reasons: huge tariffs on foreign software meant that Brazilian companies often found it cheaper to develop custom toolchains, which is what gave us Lua.
I see attitude like that a lot on hacker news, but never see it on the rust user forums or IRC and rarely in rust related twitter. I can only speak for what I've seen personally but it seems to have more to say about hacker news comment sections than the rust community itself.
> Some badass below even just said that "writing C++ code longer than a few lines without UB is humanly impossible". Apparently all these FUBAR C/C++ systems (Linux and Windows kernels, all? web browsers, LLVM that the dear rust uses, device drivers, web servers, router software, VMs of Lua, Python, C#, Java, ..., etc.) work well enough to transfer that kind of garbage to me.

Yes, they work well enough, until they don't, because realistically, they are rife with dependencies on undefined behaviour. Linux can only be compiled with gcc last I checked.

> I feel like the biggest reason for me not even thinking of Rust as a viable language right now is the community attitude

Kinda reminds me of the "coal vs. renewable energy" feud. The first tier arguments are formed around {economics, externalized costs, existing infrastructure, base load vs intermittent load} and then second-tier arguments align around {culture, history, identity, momentum, geography, political party}. You are making a second-tier argument against Rust when the article is making a first-tier argument for Rust.

I would argue that you are attributing to "the Rust community" the more outrageous attitudes which are a minority of the Rust community and ignoring the majority which have much more rational and banal attitude. And likely you are attributing the inverse to the existing C/C++ attitudes towards Rust (conveniently ignoring lots of the best arguments for Rust). It's exactly what happens in those feuds you described and in modern US politics (Democrats vs. Republicans, liberals/progressives vs. conservatives, secular vs. religious, etc). By focusing on the strawman arguments, you are missing the potential benefits of using a newer generation language.

I'm an outsider and there is a war every damn time the word Rust comes up on HN. I've yet to see bashing any language to that degree in Erlang threads, Python threads, etc. Something has to be up with that.

I'm not using C and C++ professionally at all so the only place Rust has to fit in is fun or potential long term professional opportunity (assuming Rust is a fair bit more widespread than now by then, otherwise C and C++ win in the native field for employment opportunities), I'll not have fun (and I won't learn anything I don't immediately need that won't bring me fun) in a sea of vitriol against anyone who doesn't hate C and C++ so I'm happy Rust community guidelines forbid such idiocy in official spaces and documentation.

Rust is apparently targeting C and C++ devs but at the same time the ones that like it are going crazy and saying stuff about C and C++ being impossible languages (I agree they are by far the most spartan and hardest in the mainstream right now but not impossible as evidenced by lots of quite reliable software written in it, some that lives depend on).

Up until about six months ago, I saw it a lot from Haskell proponents here on HN. But with them, it was pretty much against everybody (except maybe users of F#).

Either the most obnoxious ones left, or they learned that this was not a productive approach. It's been refreshingly quiet lately...

But I disagree that there's a war every time Rust comes up, as a general thing. Many of the Rust proponents here are quite reasonable, willing to listen, willing to explain gently. (The conversation on the current article has gotten a bit out of hand, I'll admit.)

I've never seen Haskell people (I'm relatively fresh here, 2 weeks, as evident in my lack of fitting into echo chambers) and Haskell is entirely different beast so that's different, especially if they were okay with F#. Rust is pretty much claiming to be doing same stuff in same niche (efficient native code) as C and C++ except better, it's like reverse of Haskell vs. the world except F#, it's Rust vs. C and C++.

I wasted an hour and a half or even two here today as well, I at least got a reply from a Rust core team member who responded to me (yay), was nice enough and told me the community rules disallow wars, that's something I'd not get otherwise, but still, this feels very very unproductive in the end...

> all these FUBAR C/C++ systems (...) work well enough to transfer that kind of garbage to me

I don't think you read the article. The author specifically cites lots of different types of hyperbolic "rewrite everything in Rust!" arguments and explains how this article is not that and he doesn't advocate for that. The author of the article advocates "surgically replace weaker parts but keep most of the project intact." This is exactly how Mozilla is dogfooding Rust in Firefox.

And no one is arguing that all of those C/C++ systems you mention are "FUBAR" -- that's a strawman. Rust advocates, as well as advocates of many of the newer-generation, lesser-used languages advocate for advancing programming beyond the languages designed in the 1970s. We've had an explosion in programming language diversity over the past 30 years and we've developed some great research on how to prevent certain classes of defects. The longer those C/C++-written systems exist without a rewrite in a safer language (or thorough audits including massive amounts of fuzzing), the larger the impact of inevitable non-zero-probability of those vulnerabilities which Rust prevents.

The article's author completely admits that at their best, C/C++ developers can avoid all of the problems that Rust solves. But not everyone is a rockstar and not everyone performs at 100% all of the time. Rust is written for humans and the compiler is a strict nanny, preventing you from getting yourself into danger, the same ways you can with C/C++ memory issues. It also has tooling for unit tests, benchmarking, fuzzing, and standardizing code formatting conventions in the language. You can bolt these things onto C/C++, but that means that you have to go find them (which new developers won't do unless sufficiently motivated to).

The garbage I was referring to was in the comments "below". Namely: "Some people may reasonably, with some extreme care and diligence, maybe try to claim they can write safe and UB-free C code. If stars align properly" and "writing C++ code longer than a few lines without UB is humanly impossible", not the article, I quoted the latter shorter one in my original message.

I consider Java browser applets unsafe trash and I'd never run one I don't absolutely trust. This person has similar (or even worse) opinion of C and C++ languages but runs tons of software in them with seemingly no problems since his idiotic comment made it in here and arrived to me intact despite all the C and C++ software on the way from him to HN to me.

Did you read the linked article about UB? The odds that a random C++ program trips up some of that UB are actually pretty high, and all of the programs you've mentioned do have UB (Linus has infamously gotten angry about GCC starting to exploit it). It's just a question of whether a compiler (or hacker) is bothering to exploit it yet.
I came across this comment before your others. Initially, I thought you were an innocent bystander, and maybe you were, but man did that change quickly. You criticized Rust / C++ bare knuckle boxing but then immediately afterwards jumped into the ring.
The trouble with mixing Rust and C/C++ is that you tend to get Rust with C/C++ unsafe pointers. Most of the examples of this pass C raw pointers into rust, Rather than passing a Rust Vec into C. Or even passing STL strings and vectors into Rust. So, instead of passing Rust's array size information into C, they propagate C's lack of size information into Rust. Typical example: [1]

    pub extern "C" fn count_substrings(value: *const c_char, substr: *const c_char) -> i32 
If you incrementally convert from C/C++ to Rust, you end up with those constructs in the final Rust program. Not good.

[1] http://siciarz.net/24-days-of-rust-calling-rust-from-other-l...

You only end up with them in the final program with a naive translation that makes life hard for yourself. Using the native types is much nicer (even ignoring any safety benefits), and so people are naturally encouraged to do so. For instance,

- the C interface can easily be thin wrappers around pure "nice" Rust functions, that just do the necessary unsafe conversions

- and, whether or not that is used, when a function is no longer being called from C (that is, everything that calls it has been converted to Rust) the arguments can be switched to something more natural and strong static typing will point out all the places that need to be updated.

I cannot believe that a pure Rust codebase would want to be passing raw pointers around. And the alternatives don't seem at all better: only ground-up complete-rewrite migrations (hard to justify so often won't even start) or not migrating at all (meaning one has a C codebase that is still full of unsafe pointers).

I would love to learn Rust, but the learning curve seems a bit too steep for me. The whole struggle with lifetimes is what has kept me from diving in. It seems impossible to me to figure out how to use them correctly. Plus the redundant syntax, I guess. If those things weren't an issue for me, I would gladly try to learn Rust.
Lowering the learning curve is a huge objective of this year!

> The whole struggle with lifetimes

How did you try to learn them? I'm interested in trying to make this easier!

> the redundant syntax

Which bits are redundant?

I am a fan of rust, but this article overstates the simplicity of C/rust integration.

A few examples:

* You may need to use PhantomData in your struct definitions to properly track lifetimes. Not sure I fully understand.

* C functions don't always return. Sometimes they longjmp (c.f. PostgreSQL). Calls into C code need to prepare for this and it's not trivial nor does it generalize to all projects.

* Integrating with the memory management scheme is probably possible but not trivial. For instance, Postgres memory contexts (regions/arenas) can hold any kind of object, and code can switch between them and create/destroy them at will. You could rely on rust to manage it's own memory, with circular references an Rc that might leak.

* Postgres has its own calling convention for SQL-callable functions and conventions for loadable modules. Integrating with this is a pain because macros are hygenic and can't make up new symbols. Maybe procedural macros will help when they arrive.

* Rich APIs that rust supports don't always translate well to C. When integrating with a large application that pushes you toward the lowest-common-denominator APIs.

* A lot of C macros don't translate well to rust and just including a C header in rust is a lot of work. Hoping procedural macros will help here too.

Btw, are you planning to work on a thin integration layer between rust and postgresql? Sufficient to be able to write UDFs in rust? That's imo the most realistic start to get some experience w/ rust in the postgres community, and it provides value on its own.
I've made some progress. Not quite as thin as I had hoped ;-)

I really need procedural macros to stabilize, otherwise it just puts too much pain on the UDF author.

> I really need procedural macros to stabilize, otherwise it just puts too much pain on the UDF author.

Why exactly is that? I'd have expected a C wrapper to take care of most of that? Are you concerned about the Datum<->native type C macros?

Are you planning/hoping for this to be all safe, or is there going to be unsafety in the wrapper?

Creating a new module or UDF requires exporting new special symbols for V1 calling convention.

Rust's hygenic macros don't let you do that. So defining a UDF has a bunch of boilerplate, unless I am missing something.

Procedural macros should alleviate this, but it will be a while. I might just release and document the boilerplate needed.

EDIT: Yes, I am trying to be mostly safe. I will see how close I can get for at least the basic stuff.

> Creating a new module or UDF requires exporting new special symbols for V1 calling convention.

Right - but I don't think you need to do so. That'd only be required if you'd use language 'C' - why not instead use language 'rust'. That'll force a simple wrapper function which looks up and calls the real function, but that's fairly harmless, no? Might actually be good, because you can do some extra checks and conversions there.

There are some extension APIs that demand C. But perhaps I dismissed the idea of plrust too quickly and there is room for both?
I'd say it'd be better to let PL handlers decide whether they can be used in those cases. IIRC those cases largely exist because you need to be able to deal with pointers which existing pls weren't able to...
Writing manually-vectorized SIMD code is the only way to approach advertised performance on any modern CPU.

While there’s _some_ SIMD support in Rust nightly builds (but not in Rust stable), it’s just not good enough. For one thing, Intel only supports their intrinsics for C (C++ also gets that ‘coz compatibility) and Fortran. Another thing, Rust strong type-safety concept complicates SIMD code, especially when the code does integer math. These __m128i / __m256i / __m512i registers are often treated as different data types by even consecutive instructions.

While Rust might be good enough for some areas, performance critical CPU bound code is not one of them.

Yeah, SIMD is being very actively worked on; until then, you can link in an external assembly file, but that's not exactly the best UX.
Yep, assembly’s not the best UX.

When you’re coding assembly, you have to code everything in it, including code running on the scalar parts of CPU cores. With intrinsics you can code these parts the usual way, e.g. for( size_t i=0; … )

With intrinsics you can even compose your vectorized code the usual way, VC and Clang have __vectorcall calling convention for that, Intel has very similar __attribute__((regcall)).

Yup, absolutely. My understanding is that an RFC is currently being written, so it's gonna be a little while to get into stable, but not forever. We'd have liked to have had it sooner, but some stuff happened, that's just how it goes sometimes.