This is a good article but it only scratches the surface, as is always the case when it comes to C++.
When I made a meme about C++ [1] I was purposeful in choosing the iceberg format. To me it's not quite satisfying to say that C++ is merely complex or vast. A more fitting word would be "arcane", "monumental" or "titanic" (get it?). There's a specific feeling you get when you're trying to understand what the hell is an xvalue, why std::move doesn't move or why std::remove doesn't remove.
The Forest Gump C++ is another meme that captures this feeling very well (not by me) [2].
What it comes down to is developer experience (DX), and C++ has a terrible one. Down to syntax and all the way up to package management a C++ developper feels stuck to a time before they were born. At least we have a lot of time to think about all that while our code compiles. But that might just be the price for all the power it gives you.
- Use a build system like make, you can't just `c++ build`
- Understand that C++ compilers by default have no idea where most things are, you have to tell them exactly where to search
- Use an external tool that's not your build system or compiler to actually inform the compiler what those search paths are
- Oh also understand the compiler doesn't actually output what you want, you also need a linker
- That linker also doesn't know where to find things, so you need the external tool to use it
- Oh and you still have to use a package manager to install those dependencies to work with pkg-config, and it will install them globally. If you want to use it in different projects you better hope you're ok with them all sharing the same version.
Now you can see why things like IDEs became default tools for teaching students how to write C and C++, because there's no "open a text editor and then `c++ build file.cpp` to get output" for anything except hello world examples.
loeg · 1h ago
> in C++, you can write perfectly fine code without ever needing to worry about the more complex features of the language. You can write simple, readable, and maintainable code in C++ without ever needing to use templates, operator overloading, or any of the other more advanced features of the language.
This... doesn't really hold water. You have to learn about what the insane move semantics are (and the syntax for move ctors/operators) to do fairly basic things with the language. Overloaded operators like operator*() and operator<<() are widely used in the standard library so you're forced to understand what craziness they're doing under the hood. Basic standard library datatypes like std::vector use templates, so you're debugging template instantiation issues whether you write your own templated code or not.
AaronAPU · 32m ago
I’ve been programming C++ on a daily basis for more than 20 years and literally never use the >> operator. Never. Not rarely, never.
butterisgood · 54m ago
Overloaded operators were a terrible mistake in every programming language I've encountered them in. (Yes, sorry Haskell, you too!)
I don't think move semantics are really that bad personally, and some languages move by default (isn't that Rust's whole thing?).
What I don't like is the implicit ambiguous nature of "What does this line of code mean out of context" in C++. Good luck!
(oh and I think you can write a whole book on the different ways to initialize variables in C++).
The result is you might be able to use C++ to write something new, and stick to a style that's readable... to you! But it might not make everyone else who "knows C++" instantly able to work on your code.
wvenable · 25m ago
Overloaded operators are great. But overloaded operators that do something entirely different than their intended purpose is bad. So a + operator that does an add in your custom numeric data type is good. But using << for output is bad.
jandrewrogers · 35m ago
A benefit of operator overloads is that you can design drop-in replacements for primitive types to which those operators apply but with stronger safety guarantees e.g. fully defining their behavior instead of leaving it up to the compiler.
This wasn't possible when they were added to the language and wasn't really transparent until C++17 or so but it has grown to be a useful safety feature.
loeg · 46m ago
> I don't think move semantics are really that bad personally, and some languages move by default (isn't that Rust's whole thing?).
Rust's move semantics are good! C++'s have a lot of non-obvious footguns.
> (oh and I think you can write a whole book on the different ways to initialize variables in C++).
Yeah. Default init vs value init, etc. Lots of footguns.
ot · 53m ago
Reminds me of the old quote
> everyone only uses 20% of C++, the problem is that everyone uses a different 20%
scj · 1h ago
"you can write perfectly fine code without ever needing to worry about the more complex features of the language. You can write simple, readable, and maintainable code in C++ without ever needing to use templates, operator overloading, or any of the other more advanced features of the language."
You could also inherit a massive codebase old enough to need a prostate exam that was written by many people who wanted to prove just how much of the language spec they could use.
If selecting a job mostly under the Veil of Ignorance, I'll take a large legacy C project over C++ any day.
gmueckl · 1h ago
C++ will always stay relevant. Software has eaten the world. That transition is almost complete now. The languages that were around when it happened will stay deeply embedded in our fundamental tech stacks for another couple decades at least, if not centuries. And C and C++ are the lion's share of that.
COBOL sticks around 66 years after its first release. Fortran is 68 years old and is still enormously relevant. Much, much more software was written in newer languages and has become so complex that replacements have become practically impossible (Fuchsia hasn't replaces Linux in Google products, wayland isn't ready to replace X11 etc)
ktpsns · 1h ago
As long as people write software (no pun intended), software will follow trends. For instance, in many scientific ecosystems, Matlab was successfully replaced by Scipy. Which happens to get replaced by Julia. Things don't neccessarily have to stay the same. Interestingly, such a generational trend currently happens with Rust, despite there has been numerous other popular languages such as D or Zig which didn't have the same traction.
Sure, there are still Fortran codes. But I can hardly imagine that Fortran still plays a big role in another 68 years from now on.
gmueckl · 45m ago
I am not saying that these languages will stay around forever, mind you. But we have solidified the tech stacks involving these languages by making them ridiculously complex. Replacement of a programming language in one of the core components can only come through gradual and glacially slow evolution at this point. "Rewrite it in XYZ" as a clean slate approach on a big scale is simply a pipe dream.
Re Matlab: I still see it thriving in the industry, for better or worse. Many engineers just seem to love it. I haven't seen many users of Julia yet. Where do you see those? I think that Julia deserves a fair chance, but it just doesn't have a presence in the fields I work in.
lordleft · 2h ago
Great article. Modern C++ has come a really long way. I think lots of people have no idea about the newer features of the standard library and how much they minimize footguns.
sunshowers · 1h ago
Lambdas, a modern C++ feature, can borrow from the stack and escape the stack. (This led to one of the more memorable bugs I've been part of debugging.) It's hard to take any claims about modern C++ seriously when the WG thought this was an acceptable feature to ship.
Of course, the article doesn't mention lambdas.
TuxSH · 1h ago
Capturing lambdas are no different from handwritten structures with operator() ("functors"), therefore it makes no sense castrating them.
Borrowing from stack is super useful when your lambda also lives in the stack; stack escaping is a problem, but it can be made harder by having templates take Fn& instead of const Fn& or Fn&&; that or just a plain function pointer.
loeg · 1h ago
Convenience is a difference in kind.
Like, I'm not god's gift to programming or anything, but I'm decently good at it, and I wrote a use-after-return bug due to a lambda reference last week.
bluGill · 1h ago
They can, but I find in practice that I never do this so it doesn't matter.
sunshowers · 22m ago
I'm glad, but my problem is with the claim that modern C++ is safer. They added new features that are very easy to misuse.
Meanwhile in Rust you can freely borrow from the stack in closures, and the borrow checker ensures that you'll not screw up. That's what (psychological) safety feels like.
im3w1l · 1h ago
Why wouldn't it be acceptable to ship? This is how everything works in C++. You always have to mind your references.
BeetleB · 32m ago
This is like writing an article entitled "In Defense of Guns", and then belittling the fact it can kill by saying "You always have to track your bullets".[1]
[1] Not me making this up - I started getting into guns and this is what people say.
sunshowers · 1h ago
Exactly! This is my problem with the C++ community's culture. At no point is safety put first.
StillBored · 46m ago
Its worse. The day I discovered that std::array is explicitly not range/bounds checked by default I really wanted to write some angry letters to the committee members.
Why go through all the trouble to make a better array, and require the user to call a special .at() function to get range checking rather than the other way around? I promptly went into my standard library and reversed that decision because if i'm going to the trouble to use a C++ array class, it better damn well give me a tiny bit of additional protection. The .at() call should have been the version that reverted to C array behavior without the bounds checking.
And its these kinds of decisions repeated over and over. I get its a committee. Some of the decisions won't be the best, but by 2011 everyone had already been complaining about memory safety issues for 15+ years and there wasn't enough politics on the comittee to recognize that a big reason for using C++ over C was the ability of the language to protect some of the sharper edges of C?
Yoric · 1h ago
Yeah, it's great that the C++ community starts to take safety in consideration, but one has to admit that safety always comes as the last priority, behind compatibility, convenience, performance and expressiveness.
Symmetry · 58m ago
I eagerly await the day when they do away with the distinction between ".cpp" and ".hpp" files and the textual substitution nature of "#include" and replace them all with a proper module system.
Night_Thastus · 1h ago
When it comes to programming, I generally decide my thoughts based on pain-in-my-ass levels. If I constantly have to fiddle with something to get it working, if it's fragile, if it frequently becomes a pain point - then it's not great.
And out of all the tools and architecture I work with, C++ has been some of the least problematic. The STL is well-formed and easy to work with, creating user-defined types is easy, it's fast, and generally it has few issues when deploying. If there's something I need, there's a very high chance a C or C++ library exists to do what I need. Even crossing multiple major compiler versions doesn't seem to break anything, with rare exceptions.
The biggest problem I have with C++ is how easy it is to get very long compile times, and how hard it feels like it is to analyze and fix that on a 'macro' (whole project) level. I waste ungodly amounts of time compiling. I swear I'm going to be on deaths door and see GCC running as my life flashes by.
Some others that have been not-so-nice:
* Python - Slow enough to be a bottleneck semi-frequently, hard to debug especially in a cross-language environment, frequently has library/deployment/initialization problems, and I find it generally hard to read because of the lack of types, significant whitespace, and that I can't easily jump with an IDE to see who owns what data. Also pip is demon spawn. I never want to see another Wheel error until the day I die.
* VSC's IntelliSense - My god IntelliSense is picky. Having to manually specify every goddamn macro, one at a time in two different locations just to get it to stop breaking down is a nightmare. I wish it were more tolerant of having incomplete information, instead of just shutting down completely.
* Fortran - It could just be me, but IDEs struggle with it. If you have any global data it may as well not exist as far as the IDE is concerned, which makes dealing with such projects very hard.
* CMake - I'm amazed it works at all. It looks great for simple toy projects and has the power to handle larger projects, but it seems to quickly become an ungodly mess of strange comments and rules that aren't spelled out - and you have no way of stepping into it and seeing what it's doing. I try to touch it as infrequently as possible. It feels like C macros, in a bad way.
zahlman · 1h ago
> I never want to see another Wheel error until the day I die.
What exactly do you mean by a "Wheel error"? Show me a reproducer and a proper error message and I'll be happy to help to the best of my ability.
By and large, the reason pip fails to install a package is because doing so requires building non-Python code locally, following instructions included in the package. Only in rare cases are there problems due to dependency conflicts, and these are usually resolved by creating a separate environment for the thing you're trying to install — which you should generally be doing anyway. In the remaining cases where two packages simply can't co-exist, this is fundamentally Python's fault, not the installer's: module imports are cached, and quite a lot of code depends on the singleton nature of modules for correctness, so you really can't safely load up two versions of a dependency in the same process, even if you hacked around the import system (which is absolutely doable!) to enable it.
As for finding significant whitespace (meaning indentation used to indicate code structure; it's not significant in other places) hard to read, I'm genuinely at a loss to understand how. Python has types; what it lacks is manifest typing, and there are many languages like this (including Haskell, whose advocates are famous for explaining how much more "typed" their language is than everyone else's). And Python has a REPL, the -i switch, and a built-in debugger in the standard library, on top of not requiring the user to do the kinds of things that most often need debugging (i.e. memory management). How can it be called hard to debug?
Night_Thastus · 30m ago
Unfortunately that Wheel situation was far enough back now that I don't have details on hand. I just know it was awful at the time.
As for significant whitespace, the problem is that I'm often dealing with files with several thousand lines of code and heavily nested functions. It's very easy to lose track of scope in that situation. Am I in the inner loop, or this outer loop? Scrolling up and down, up and down to figure out where I am. Feels easier to make mistakes as well.
It works well if everything fits on one screen, it gets harder otherwise, at least for me.
As for types, I'm not claiming it's unique to Python. Just that it makes working with Python harder for me. Being able to see the type of data at a glance tells me a LOT about what the code is doing and how it's doing it - and Python doesn't let me see this information.
As for debugging, it's great if you have pure Python. Mix other languages in and suddenly it becomes pain. There's no way to step from another language into Python (or vice-versa), at least not cleanly and consistently. This isn't always true for compiled->compiled. I can step from C++ into Fortran just fine.
zahlman · 18m ago
Pip has changed a lot in the last few years, and there are many new ecosystem standards, along with greater adoption of existing ones.
> I'm often dealing with files with several thousand lines of code and heavily nested functions.
This is the problem. Also, a proper editor can "fold" blocks for you.
> Being able to see the type of data at a glance tells me a LOT about what the code is doing and how it's doing it - and Python doesn't let me see this information.
If you want to use annotations, you can, and have been able to since 3.0. Since 3.5 (see https://peps.python.org/pep-0484/; it's been over a decade now), there's been a standard for understanding annotations as type information, which is recognized by multiple different third-party tools and has been iteratively refined ever since. It just isn't enforced by the language itself.
> Mix other languages in and suddenly it becomes pain.... This isn't always true for compiled->compiled.
Sure, but then you have to understand the assembly that you've stepped into.
Night_Thastus · 16m ago
>This is the problem. Also, a proper editor can "fold" blocks for you.
I can't fix that. I just work here. I've got to deal with the code I've got to deal with. And for old legacy code that's sprawling, I find braces help a LOT with keeping track of scope.
>Sure, but then you have to understand the assembly that you've stepped into.
Assembly? I haven't touched raw assembly since college.
zahlman · 4m ago
> And for old legacy code that's sprawling, I find braces help a LOT with keeping track of scope.
How exactly are they more helpful than following the line of the indentation that you're supposed to have as a matter of good style anyway? Do you not have formatting tools? How do you not have a tool that can find the top of a level of indentation, but do have one that can find a paired brace?
>Assembly? I haven't touched raw assembly since college.
How exactly does your debugger know whether the compiled code it stepped into came from C++ or Fortran source?
bluGill · 1h ago
CMake is not a great language, but great effort has been put into cleaning up how things should be done. However you can't just upgrade, someone needs to go through the effort of using all that new stuff. In almost all projects the build system is an after thought that developers touch as little as possible to make things work and so it builds cruft constantly.
You can do much better in CMake if you put some effort into cleaning it up - I have little hope anyone will do this though. We have a hard time getting developers to clean up messes in production code and that gets a lot more care and love.
butterisgood · 59m ago
A pet peeve of mine is when people claim C++ is a superset of C. It really isn't. There's a lot of little nuanced differences that can bite you.
Ignore the fact that having more keywords in C++ precludes the legality of some C code being C++. (`int class;`)
void * implicit casting in C just works, but in C++ it must be an explicit cast (which is kind of funny considering all the confusing implicit behavior in C++).
C++20 does have C11's designated initialization now, which helps in some cases, but that was a pain for a long time.
enums and conversion between integers is very strict in C++.
`char * message = "Hello"` is valid C but not C++ (since you cannot mutate the pointed to string, it must be `const` in C++)
C99 introduced variadic macros that didn't become standard C++ until 2011.
C doesn't allow for empty structs. You can do it in C++, but sizeof(EmptyStruct) is 1. And if C lets you get away with it in some compilers, I'll bet it's 0.
Anyway, all of these things and likely more can ruin your party if you think you're going to compile C code with a C++ compiler.
Also don't forget if you want code to be C callable in C++ you have to use `extern "C"` wrappers.
jandrewrogers · 31m ago
> You can do it in C++, but sizeof(EmptyStruct) is 1.
Unless you use the C++20 [[no_unique_address]] attribute, in which case it is 0 (if used correctly).
whobre · 1h ago
> C++ is very old, in fact, it came out in 1985, to put it into perspective, that’s 4 years before the first version of Windows was released
Nitpick, I guess, but Windows 1.0 was released in November 1985:
Funny how silly Windows 1 looks compared to Mac OS 1. I wonder if it was the color support taking resources.
BeetleB · 58m ago
> Here’s a rule of thumb I like to follow for C++: make it look as much like C as you possibly can, and avoid using too many advanced features of the language unless you really need to.
Also, avoid using C++ classes while you're at it.
I recently had to go back to writing C++ professionally after a many-year hiatus. We code in C++23, and I got a book to refresh me on the basics as well as all the new features.
And man, doing OO in C++ just plain sucks. Needing to know things like copy and swap, and the Rule of Three/Five/Zero. Unless you're doing trivial things with classes, you'll need to know these things. At which point you might as well stick to structs.
Now I'll grant C++23 is much nicer than C++03 (just import std!) I was so happy to hear about optional, only to find out how fairly useless it is compared to pretty much every language that has implemented a "Maybe" type. Why add the feature if the compiler is not going to protect you from dereferencing without checking?
butterisgood · 53m ago
I really don't like Object Oriented programming anywhere. Maybe Smalltalk had it right, but I've not messed with Pharo or anything else enough to get a feel for it.
CLOS seems pretty good, but then again I'm a bit inexperienced. Bring back Dylan!
tsunagatta · 45m ago
> You can write simple and readable code in C++ if you want to. You can also write complex and unreadable code in C++ if you want to. It’s all about personal or team preference.
Problem is, if you’re using C++ for anything serious, like the aforementioned game development, you will almost certainly have to use the existing libraries; so you’re forced to match whatever coding style they chose to use for their codebase. And in the case of Unreal, the advice “stick to the STL” also has to be thrown out since Unreal doesn’t use the STL at all. If you could use vanilla, by-the-books C++ all the time, it’d be fine, but I feel like that’s quite rare in practice.
MontagFTB · 1h ago
When NIST released its summary judgement against C++ and other languages it deemed memory unsafe, the problem became less technical and more about politics and perception. If you're looking to work within two arms' length of the US Government, you have to consider the "written in C++" label seriously, regardless of how correct the code may be.
jandrewrogers · 26m ago
Nothing is going to happen for the foreseeable future, at least in the parts of government I tend to work with. It doesn't even come up in discussions of critical high-reliability system. They are still quite happy to buy and use C++, so I expect that is what they will be getting.
Jtsummers · 51m ago
The government is still happily commissioning new software projects that use C++. That may change in a few years, and some organizations may already be treating C++ more critically, but so far it's been unimpactful.
nzeid · 1h ago
> Just using Rust will not magically make your application safe; it will just make it a lot harder to have memory leaks or safety issues.
You know, not sure I even agree with the memory leaks part. If you define a memory leak very narrowly as forgetting to free a pointer, this is correct. But in my experience working with many languages including C/C++, forgotten pointers are almost never the problem. You're gonna be dealing with issues involving "peaky" memory usage e.g. erroneously persistent references to objects or bursty memory allocation patterns. And these occur in all languages.
AlotOfReading · 59m ago
C++'s design encourages that kind of allocation "leak" though. The article suggests using smart pointers, so let's take an example from there and mix make_shared with weak_ptr. Congrats, you've now extended the lifetime of the allocation to whatever the lifetime of your weak pointer is.
Rc::Weak does the same thing in Rust, but I rarely see anyone use it.
loeg · 59m ago
They're both problems, and forgotten pointers are more common in C, or C++ before 2011 (unique_ptr vs manual new/delete).
andrewmcwatters · 1h ago
What's worse in languages like Go, which I love, is that you won't even immediately how to solve this unless you have experience dropping down into doing things you just would have normally done in C or C++.
Even the Go authors themselves on Go's website display a process of debugging memory usage that looks identical to a workflow you would have done in C++. So, like, what's the point? Just use C++.
I really do think Go is nice, but at this point I would relegate it to the workplace where I know I am working with a highly variable team of developers who in almost all cases will have a very poor background in debugging anything meaningful at all.
beej71 · 20m ago
It doesn't mention the horrific template error messages. I'd heard that this was an area targeted for improvement a while ago... Is it better these days?
WCSTombs · 1h ago
Good article overall. There's one part I don't really agree with:
> Here’s a rule of thumb I like to follow for C++: make it look as much like C as you possibly can, and avoid using too many advanced features of the language unless you really need to.
This has me scratching my head a bit. In spite of C++ being nearly a superset of C, they are very different languages, and idiomatic C++ doesn't look very much like C. In fact, I'd argue that most of the stuff C++ adds to C allows you to write code that's much cleaner than the equivalent C code, if you use it the intended way. The one big exception I can think of is template metaprogramming, since the template code can be confusing, but if done well, the downstream code can be incredibly clean.
There's an even bigger problem with this recommendation, which is how it relates to something else talked about in the article, namely "safety." I agree with the author that modern C++ can be a safe language, with programmer discipline. C++ offers a very good discipline to avoid resource leaks of all kinds (not just memory leaks), called RAII [1]. The problem here is that C++ code that leverages RAII looks nothing like C.
Stepping back a bit, I feel there may be a more fundamental fallacy in this "C++ is Hard to Read" section in that the author seems to be saying that C++ can be hard to read for people who don't know the language well, and that this is a problem that should be addressed. This could be a little controversial, but in my opinion you shouldn't target your code to the level of programmers who don't know the language well. I think that's ultimately neither good for the code nor good for other programmers. I'm definitely not an expert on all the corners of C++, but I wouldn't avoid features I am familiar with just because other programmers might not be.
I write C++ daily and I really can't take seriously arguments how C++ is safe if you know what you're doing like come on. Any sufficiently large and complex codebases tend to have bugs and footguns and using tools like memory safe languages limit blast radius considerably.
Smart pointers are neat but they are not a solution for memory safety. Just using standard containers and iterators can lead to lots of footguns, or utils like string_view.
rs186 · 1h ago
Is there anything new here? Aren't these the same talking points people have been making for the past few years?
justicehunter · 1h ago
I'm not sure what I feel about the article's point on boost. It does contribute a lot to the standard library and does provide some excellent libraries, like boost.Unordered
Night_Thastus · 1h ago
Boost is an awful whole with a couple very nice tiny parts inside.
If you can restrict to using the 'good' parts than it can be OK, but it's pulling in a huge dependency for very little gain these days.
kronicum2025 · 56m ago
The safety part in this article is incorrect. There's a google doc somewhere where Google did an internal experiment and determined that safety c annot be achieved in C++ without an owning reference (essentially what Rust has).
jasperry · 1h ago
The author argues that if rewriting a C++ codebase in Rust makes it more memory-safe, that's not because Rust is memory-safe. What?
agentultra · 34m ago
That’s because the author thinks it’s the second system syndrome carrying the weight.
I think Rust is probably doing the majority of the work unless you’re writing everything in unsafe. And why would you? Kinda defeats the purpose.
bluGill · 1h ago
I would argue that rewrite in C++ will make it a lot better. Rust does have some nice memory safe features that are nice enough that you should question why someone did a rewrite and stuck with C++, but that C++ rewrite would fix a lot.
jandrewrogers · 44m ago
I think there is significant merit to rewriting a legacy C++ (or C) codebase in very modern C++. I've done it before and it not only greatly reduced the total amount of code but also substantially improved the general safety. Faster code and higher quality. Because both implementations are "C++", there is a much more incremental path and the existing testing more or less just works.
By contrast, my experience with C++ to Rust rewrites is that the inability of Rust to express some useful and common C++ constructs causes the software architecture to diverge to the point where you might as well just be rewriting it from scratch because it is too difficult to track the C++ code.
pie_flavor · 1h ago
Fresh codebases have more bugs than mature codebases. Rewriting does not fix bugs; it is a fresh codebase that may have different bugs but extremely rarely fewer bugs than the codebase most of the bugs have been patched out of. Rewriting it in Rust reduces the bugs because Rust inherently prevents large categories of bugs. Rewriting it in C++ has no magical properties that initially writing it in C++ doesn't, especially if you weren't around for the writing of the original. Maybe if there is some especially persnickety known bug that would require a major rearchitecture and you plan to implement this architecture this time around, but that is not the modal bug, and the article is especially talking about memory safety bugs which are a totally separate kind of thing from that.
the_af · 1h ago
You left out the full argument (to be clear, I don't agree with the author, but in order to disagree with him you have to quote the full argument):
The author is arguing that the main reason rewriting a C++ codebase in Rust makes it more memory-safe is not because it was done in Rust, but because it benefits from lessons learned and knowledge about the mistakes done during the first iteration. He acknowledges Rust will also play a part, but that it's minor compared to the "lessons learned" factor.
I'm not sure I buy the argument, though. I think rewrites usually introduce new bugs into the codebase, and if it's not the exact same team doing the rewrite, then they may not be familiar with decisions made during the first version. So the second version could have as many flaws, or worse.
jasperry · 30m ago
The argument could be made that rewriting in general can make a codebase more robust, regardless of the language. But that's not what the article does; it makes it specifically about memory safety:
> That’s how I feel when I see these companies claim that rewriting their C++ codebases in Rust has made them more memory safe. It’s not because of Rust, it’s because they took the time to rethink and redesign...
If they got the program to work at all in Rust, it would be memory-safe. You can't claim that writing in a memory-safe language is a "minor" factor in why you get memory safety. That could never be proven or disproven.
Night_Thastus · 1h ago
Did you read what they wrote? Their point is that doing a fresh rewrite of old code in any language will often inherently fix some old issues - including memory safety ones.
Because it's a re-write, you already know all the requirements. You know what works and what doesn't. You know what kind of data should be laid out and how to do it.
Because of that, a fresh re-write will often erase bugs (including memory ones) that were present originally.
puzzledobserver · 1h ago
That claim appears to contradict the second-system effect [0].
The observation is that second implementation of a successful system is often much less successful, overengineered, and bloated, due to programmer overconfidence.
On the other hand, I am unsure of how frequently the second-system effect occurs or the scenarios in which it occurs either. Perhaps it is less of a concern when disciplined developers are simply doing rewrites, rather than feature additions. I don't know.
I won't say the second-system effect doesn't exist, but I wouldn't say it applies every single time either. There's too many variables. Sometimes a rewrite is just a rewrite. Sometimes the level of bloat or feature-creep is tiny. Sometimes the old code was so bad that the rewrite fully offsets any bloat.
Animats · 51m ago
So Boost is dying off? Good to know.
franky47 · 1h ago
What’s a good (ie: opinionated) code formatter and unit test framework for C++ these days?
I just had a PR on an old C++ project, and spending 8 years in the web ecosystem have raised the bar around tooling expectations.
Rust is particularly sweet to work with in that regard.
lang4d · 1h ago
My go to for formatting would be clang-format, and for testing gtest. For more extensive formatting (that involves the compiler) clang-tidy goes a long way
jonstewart · 1h ago
Catch2 is great as a unit test framework.
Running unit tests with the address sanitizer and UB sanitizer enabled go a long way towards addressing most memory safety bugs. The kind of C++ you write then is a far cry from what the haters complain about with bad old VC6 era C++.
IshKebab · 1h ago
The only formatter is clang-format, and it isn't very good. Better than nothing though.
scuff3d · 1h ago
A lot of this article boils down to "C++ is great... If you don't use most of the language"
justinhj · 1h ago
Not a terrible thing on its face
e-dant · 47m ago
If there are as many typos in some code as are in the article, there would be a whole lot of segfaults, too
g42gregory · 1h ago
I am not sure C++ needs a defense. Especially after C++ 11 cleanup.
IshKebab · 1h ago
Terrible article.
> you can write perfectly fine code without ever needing to worry about the more complex features of the language
Not really because of undefined behaviour. You must be aware of and vigilant about the complexities of C++ because the compiler will not tell you when you get it wrong.
I would argue that Rust is at least in the same complexity league as C++. But it doesn't matter because you don't need to remember that complexity to write code that works properly (almost all of the time anyway, there are some footguns in async Rust but it's nothing on C++).
> Now is [improved safety in Rust rewrites] because of Rust? I’d argue in some small part, yes. However, I think the biggest factor is that any rewrite of an existing codebase is going to yield better results than the original codebase.
A factor, sure. The biggest? Doubtful. It isn't only Rust's safety that helps here, it's its excellent type system.
> But here’s the thing: all programming languages are unsafe if you don’t know what you’re doing.
Somehow managed to fit two fallacies in one sentence!
1. The fallacy of the grey - no language is perfect therefore they are all the same.
2. "I don't make mistakes."
> Just using Rust will not magically make your application safe; it will just make it a lot harder to have memory leaks or safety issues.
Not true. As I said already Rust's very strong type system helps to make applications less buggy even ignoring memory safety bugs.
> Yes, C++ can be made safer; in fact, it can even be made memory safe. There are a number of libraries and tools available that can help make C++ code safer, such as smart pointers, static analysis tools, and memory sanitizers
lol
> Avoid boost like the plague.
Cool, so the ecosystem isn't confusing but you have to avoid one of the most popular libraries. And Boost is fine anyway. It has lots of quite high quality libraries, even if they do love templates too much.
> Unless you are writing a large and complex application that requires the specific features provided by Boost, you are better off using other libraries that are more modern and easier to use.
Uhuh what would you recommend instead of Boost ICL?
I guess it's a valiant attempt but this is basically "in defense of penny farthings" when the safety bicycle was invented.
fithisux · 1h ago
"Rust shines in new projects where safety is the priority, while C++ continues to dominate legacy systems and performance-critical domains."
the truth
IncreasePosts · 1h ago
I think, if one of the most prominent C++ experts in the world(herb sutter), who chaired the C++ standards committee for 20+ years, who has evangelized the language for even longer than that - decides that complexity in the language has gotten out of control and sits down to write a simpler and safer dialect, then that is indicative of a problem with the language.
My viewpoint on the language is that there are certain types of engineers who thrive in the complexity that is easy to arrive at in a C++ code base. These engineers are undoubtedly very smart, but, I think, lack a sense of aesthetics that I can never get past. Basically, the r/atbge of programming languages (Awful Taste But Great Execution).
EGreg · 1h ago
Python’s “there should be one obvious way to do it” slogan often collides with reality these days too, since the language sprawled into multiple idioms just like C++: for printing you can use print("hi"), f-strings like f"hi {x}", .format(), % formatting, or concatenation with +; for loops you can iterate with for i in range(n), list comprehensions [f(i) for i in seq], generator expressions (f(i) for i in seq), or map/filter/lambda; unpacking can be done with a,b=pair, tuple() casting, slicing, *args capture, or dictionary unpacking with *; conditionals can be written with if/else blocks, one-line ternary x if cond else y, and/or short-circuit hacks, or pattern matching match/case; default values can come from dict.get(k,default), x or default, try/except, or setdefault; swapping variables can be done with a,b=b,a, with a temp var, with tuple packing/unpacking, or with simultaneous assignment; joining strings can be done with "".join(list), concatenation in a loop, reduce(operator.add, seq), or f-strings; reading files can be open().read(), iterating line by line with for line in f, using pathlib.Path.read_text(), or with open(...) as f; building lists can be done with append in a loop, comprehensions, list(map(...)), or unpacking with [*a,*b]; dictionaries can be merged with {*a,*b}, a|b (Python 3.9+), dict(a,*b), update(), or comprehensions; equality and membership checks can be ==, is, in, any(...), all(...), or chained comparisons; function arguments can be passed positionally, by name, unpacked with * and \*, or using functools.partial; iteration with indexes can be for i in range(len(seq)), for i,x in enumerate(seq), zip(range(n),seq), or itertools; multiple return values can be tuples, lists, dicts, namedtuples, dataclasses, or objects; even truthiness tests can be if x:, if bool(x):, if len(x):, or if x != []:. Whew!
lyu07282 · 1h ago
But hey at least python forces you to use whitespace properly hinthinthint
pie_flavor · 1h ago
I don't think there could be any purer of an expression of the Blub Paradox.
> Just use whatever parts of the language you like without worrying about what's most performant!
It's not about performant. It's about understanding someone else's code six months after they've been fired, and thus restricting what they can possibly have done. And about not being pervasively unsafe.
> "I don’t think C++ is outdated by any stretch of the imagination", "matter of personal taste".
Except of course for header files, forward declarations, Make, the true hell of C++ dependency management (there's an explicit exhortation not to use libraries near the bottom), a thousand little things like string literals actually being byte pointers no matter how thoroughly they're almost compatible with std::string, etc. And of course the pervasive unsafety. Yes, it sure was last updated in 2023, the number of ways of doing the same thing has been expanded from four to five but the module system still doesn't work.
> You can write unsafe code in Python! Rewriting always makes the code more safe whether it's in Rust or not!
No. Nobody who has actually used Rust can reasonably arrive at this opinion. You can write C++ code that is sound; Rust-fluent people often do. The design does not come naturally just because of the process of rewriting, this is an entirely ridiculous thing to claim. You will make the same sorts of mistakes you made writing it fresh, because you are doing the same thing as you were when writing it fresh. The Rust compiler tells you things you were not thinking of, and Rust-fluent people write sound C++ code because they have long since internalized these rules.
And the crack about Python is just stupid. When people say 'unsafe' and Rust in the same sentence, they are obviously talking about UB, which is a class of problem a cut above other kinds of bugs in its pervasiveness, exploitability, and ability to remain hidden from code review. It's 'just' memory safety that you're controlling, which according to Microsoft is 70% of all security related bugs. 70% is a lot! (plus thread safety, if this was not mentioned you know they have not bothered using Rust)
In fact the entire narrative of 'you'll get it better the second time' is nonsense, the software being rewritten was usually written for the first time by totally different people, and the rewriters weren't around for it or most of the bugfixes. They're all starting fresh, the development process is nearly the same as the original blank slate was - if they get it right with Rust, then Rust is an active ingredient in getting it right!
> Just use smart pointers!
Yes, let me spam angle brackets on every single last function. 'Write it the way you want to write it' is the first point in the article, and here is the exact 'write it this way' that was critiquing. And you realistically won't do it on every function so it is just a matter of time until one of the functions you use regular references with creates a problem.
the_af · 1h ago
> In fact the entire narrative of 'you'll get it better the second time' is nonsense, the software being rewritten was usually written for the first time by totally different people, and the rewriters weren't around for it or most of the bugfixes. They're all starting fresh, the development process is nearly the same as the original blank slate was - if they get it right with Rust, then Rust is an active ingredient in getting it right!
Yes, this is a serious flaw in the author's argument. Does he think the exact same team that built version 1.0 in C++ is the one writing 2.0 in Rust? Maybe that happens sometimes, I guess, but to draw a general lesson from that seems weird.
When I made a meme about C++ [1] I was purposeful in choosing the iceberg format. To me it's not quite satisfying to say that C++ is merely complex or vast. A more fitting word would be "arcane", "monumental" or "titanic" (get it?). There's a specific feeling you get when you're trying to understand what the hell is an xvalue, why std::move doesn't move or why std::remove doesn't remove.
The Forest Gump C++ is another meme that captures this feeling very well (not by me) [2].
What it comes down to is developer experience (DX), and C++ has a terrible one. Down to syntax and all the way up to package management a C++ developper feels stuck to a time before they were born. At least we have a lot of time to think about all that while our code compiles. But that might just be the price for all the power it gives you.
[1] https://victorpoughon.github.io/cppiceberg/
[2] https://mikelui.io/img/c++_init_forest.gif
If I'm writing a small utility or something the Makefile typically looks something like this:
- Use a build system like make, you can't just `c++ build`
- Understand that C++ compilers by default have no idea where most things are, you have to tell them exactly where to search
- Use an external tool that's not your build system or compiler to actually inform the compiler what those search paths are
- Oh also understand the compiler doesn't actually output what you want, you also need a linker
- That linker also doesn't know where to find things, so you need the external tool to use it
- Oh and you still have to use a package manager to install those dependencies to work with pkg-config, and it will install them globally. If you want to use it in different projects you better hope you're ok with them all sharing the same version.
Now you can see why things like IDEs became default tools for teaching students how to write C and C++, because there's no "open a text editor and then `c++ build file.cpp` to get output" for anything except hello world examples.
This... doesn't really hold water. You have to learn about what the insane move semantics are (and the syntax for move ctors/operators) to do fairly basic things with the language. Overloaded operators like operator*() and operator<<() are widely used in the standard library so you're forced to understand what craziness they're doing under the hood. Basic standard library datatypes like std::vector use templates, so you're debugging template instantiation issues whether you write your own templated code or not.
I don't think move semantics are really that bad personally, and some languages move by default (isn't that Rust's whole thing?).
What I don't like is the implicit ambiguous nature of "What does this line of code mean out of context" in C++. Good luck!
I have hope for C++front/Cpp2. https://github.com/hsutter/cppfront
(oh and I think you can write a whole book on the different ways to initialize variables in C++).
The result is you might be able to use C++ to write something new, and stick to a style that's readable... to you! But it might not make everyone else who "knows C++" instantly able to work on your code.
This wasn't possible when they were added to the language and wasn't really transparent until C++17 or so but it has grown to be a useful safety feature.
Rust's move semantics are good! C++'s have a lot of non-obvious footguns.
> (oh and I think you can write a whole book on the different ways to initialize variables in C++).
Yeah. Default init vs value init, etc. Lots of footguns.
> everyone only uses 20% of C++, the problem is that everyone uses a different 20%
You could also inherit a massive codebase old enough to need a prostate exam that was written by many people who wanted to prove just how much of the language spec they could use.
If selecting a job mostly under the Veil of Ignorance, I'll take a large legacy C project over C++ any day.
COBOL sticks around 66 years after its first release. Fortran is 68 years old and is still enormously relevant. Much, much more software was written in newer languages and has become so complex that replacements have become practically impossible (Fuchsia hasn't replaces Linux in Google products, wayland isn't ready to replace X11 etc)
Sure, there are still Fortran codes. But I can hardly imagine that Fortran still plays a big role in another 68 years from now on.
Re Matlab: I still see it thriving in the industry, for better or worse. Many engineers just seem to love it. I haven't seen many users of Julia yet. Where do you see those? I think that Julia deserves a fair chance, but it just doesn't have a presence in the fields I work in.
Of course, the article doesn't mention lambdas.
Borrowing from stack is super useful when your lambda also lives in the stack; stack escaping is a problem, but it can be made harder by having templates take Fn& instead of const Fn& or Fn&&; that or just a plain function pointer.
Like, I'm not god's gift to programming or anything, but I'm decently good at it, and I wrote a use-after-return bug due to a lambda reference last week.
Meanwhile in Rust you can freely borrow from the stack in closures, and the borrow checker ensures that you'll not screw up. That's what (psychological) safety feels like.
[1] Not me making this up - I started getting into guns and this is what people say.
Why go through all the trouble to make a better array, and require the user to call a special .at() function to get range checking rather than the other way around? I promptly went into my standard library and reversed that decision because if i'm going to the trouble to use a C++ array class, it better damn well give me a tiny bit of additional protection. The .at() call should have been the version that reverted to C array behavior without the bounds checking.
And its these kinds of decisions repeated over and over. I get its a committee. Some of the decisions won't be the best, but by 2011 everyone had already been complaining about memory safety issues for 15+ years and there wasn't enough politics on the comittee to recognize that a big reason for using C++ over C was the ability of the language to protect some of the sharper edges of C?
And out of all the tools and architecture I work with, C++ has been some of the least problematic. The STL is well-formed and easy to work with, creating user-defined types is easy, it's fast, and generally it has few issues when deploying. If there's something I need, there's a very high chance a C or C++ library exists to do what I need. Even crossing multiple major compiler versions doesn't seem to break anything, with rare exceptions.
The biggest problem I have with C++ is how easy it is to get very long compile times, and how hard it feels like it is to analyze and fix that on a 'macro' (whole project) level. I waste ungodly amounts of time compiling. I swear I'm going to be on deaths door and see GCC running as my life flashes by.
Some others that have been not-so-nice:
* Python - Slow enough to be a bottleneck semi-frequently, hard to debug especially in a cross-language environment, frequently has library/deployment/initialization problems, and I find it generally hard to read because of the lack of types, significant whitespace, and that I can't easily jump with an IDE to see who owns what data. Also pip is demon spawn. I never want to see another Wheel error until the day I die.
* VSC's IntelliSense - My god IntelliSense is picky. Having to manually specify every goddamn macro, one at a time in two different locations just to get it to stop breaking down is a nightmare. I wish it were more tolerant of having incomplete information, instead of just shutting down completely.
* Fortran - It could just be me, but IDEs struggle with it. If you have any global data it may as well not exist as far as the IDE is concerned, which makes dealing with such projects very hard.
* CMake - I'm amazed it works at all. It looks great for simple toy projects and has the power to handle larger projects, but it seems to quickly become an ungodly mess of strange comments and rules that aren't spelled out - and you have no way of stepping into it and seeing what it's doing. I try to touch it as infrequently as possible. It feels like C macros, in a bad way.
What exactly do you mean by a "Wheel error"? Show me a reproducer and a proper error message and I'll be happy to help to the best of my ability.
By and large, the reason pip fails to install a package is because doing so requires building non-Python code locally, following instructions included in the package. Only in rare cases are there problems due to dependency conflicts, and these are usually resolved by creating a separate environment for the thing you're trying to install — which you should generally be doing anyway. In the remaining cases where two packages simply can't co-exist, this is fundamentally Python's fault, not the installer's: module imports are cached, and quite a lot of code depends on the singleton nature of modules for correctness, so you really can't safely load up two versions of a dependency in the same process, even if you hacked around the import system (which is absolutely doable!) to enable it.
As for finding significant whitespace (meaning indentation used to indicate code structure; it's not significant in other places) hard to read, I'm genuinely at a loss to understand how. Python has types; what it lacks is manifest typing, and there are many languages like this (including Haskell, whose advocates are famous for explaining how much more "typed" their language is than everyone else's). And Python has a REPL, the -i switch, and a built-in debugger in the standard library, on top of not requiring the user to do the kinds of things that most often need debugging (i.e. memory management). How can it be called hard to debug?
As for significant whitespace, the problem is that I'm often dealing with files with several thousand lines of code and heavily nested functions. It's very easy to lose track of scope in that situation. Am I in the inner loop, or this outer loop? Scrolling up and down, up and down to figure out where I am. Feels easier to make mistakes as well.
It works well if everything fits on one screen, it gets harder otherwise, at least for me.
As for types, I'm not claiming it's unique to Python. Just that it makes working with Python harder for me. Being able to see the type of data at a glance tells me a LOT about what the code is doing and how it's doing it - and Python doesn't let me see this information.
As for debugging, it's great if you have pure Python. Mix other languages in and suddenly it becomes pain. There's no way to step from another language into Python (or vice-versa), at least not cleanly and consistently. This isn't always true for compiled->compiled. I can step from C++ into Fortran just fine.
> I'm often dealing with files with several thousand lines of code and heavily nested functions.
This is the problem. Also, a proper editor can "fold" blocks for you.
> Being able to see the type of data at a glance tells me a LOT about what the code is doing and how it's doing it - and Python doesn't let me see this information.
If you want to use annotations, you can, and have been able to since 3.0. Since 3.5 (see https://peps.python.org/pep-0484/; it's been over a decade now), there's been a standard for understanding annotations as type information, which is recognized by multiple different third-party tools and has been iteratively refined ever since. It just isn't enforced by the language itself.
> Mix other languages in and suddenly it becomes pain.... This isn't always true for compiled->compiled.
Sure, but then you have to understand the assembly that you've stepped into.
I can't fix that. I just work here. I've got to deal with the code I've got to deal with. And for old legacy code that's sprawling, I find braces help a LOT with keeping track of scope.
>Sure, but then you have to understand the assembly that you've stepped into.
Assembly? I haven't touched raw assembly since college.
How exactly are they more helpful than following the line of the indentation that you're supposed to have as a matter of good style anyway? Do you not have formatting tools? How do you not have a tool that can find the top of a level of indentation, but do have one that can find a paired brace?
>Assembly? I haven't touched raw assembly since college.
How exactly does your debugger know whether the compiled code it stepped into came from C++ or Fortran source?
You can do much better in CMake if you put some effort into cleaning it up - I have little hope anyone will do this though. We have a hard time getting developers to clean up messes in production code and that gets a lot more care and love.
Ignore the fact that having more keywords in C++ precludes the legality of some C code being C++. (`int class;`)
void * implicit casting in C just works, but in C++ it must be an explicit cast (which is kind of funny considering all the confusing implicit behavior in C++).
C++20 does have C11's designated initialization now, which helps in some cases, but that was a pain for a long time.
enums and conversion between integers is very strict in C++.
`char * message = "Hello"` is valid C but not C++ (since you cannot mutate the pointed to string, it must be `const` in C++)
C99 introduced variadic macros that didn't become standard C++ until 2011.
C doesn't allow for empty structs. You can do it in C++, but sizeof(EmptyStruct) is 1. And if C lets you get away with it in some compilers, I'll bet it's 0.
Anyway, all of these things and likely more can ruin your party if you think you're going to compile C code with a C++ compiler.
Also don't forget if you want code to be C callable in C++ you have to use `extern "C"` wrappers.
Unless you use the C++20 [[no_unique_address]] attribute, in which case it is 0 (if used correctly).
Nitpick, I guess, but Windows 1.0 was released in November 1985:
https://en.m.wikipedia.org/wiki/Windows_1.0
Also, avoid using C++ classes while you're at it.
I recently had to go back to writing C++ professionally after a many-year hiatus. We code in C++23, and I got a book to refresh me on the basics as well as all the new features.
And man, doing OO in C++ just plain sucks. Needing to know things like copy and swap, and the Rule of Three/Five/Zero. Unless you're doing trivial things with classes, you'll need to know these things. At which point you might as well stick to structs.
Now I'll grant C++23 is much nicer than C++03 (just import std!) I was so happy to hear about optional, only to find out how fairly useless it is compared to pretty much every language that has implemented a "Maybe" type. Why add the feature if the compiler is not going to protect you from dereferencing without checking?
CLOS seems pretty good, but then again I'm a bit inexperienced. Bring back Dylan!
Problem is, if you’re using C++ for anything serious, like the aforementioned game development, you will almost certainly have to use the existing libraries; so you’re forced to match whatever coding style they chose to use for their codebase. And in the case of Unreal, the advice “stick to the STL” also has to be thrown out since Unreal doesn’t use the STL at all. If you could use vanilla, by-the-books C++ all the time, it’d be fine, but I feel like that’s quite rare in practice.
You know, not sure I even agree with the memory leaks part. If you define a memory leak very narrowly as forgetting to free a pointer, this is correct. But in my experience working with many languages including C/C++, forgotten pointers are almost never the problem. You're gonna be dealing with issues involving "peaky" memory usage e.g. erroneously persistent references to objects or bursty memory allocation patterns. And these occur in all languages.
Rc::Weak does the same thing in Rust, but I rarely see anyone use it.
Even the Go authors themselves on Go's website display a process of debugging memory usage that looks identical to a workflow you would have done in C++. So, like, what's the point? Just use C++.
I really do think Go is nice, but at this point I would relegate it to the workplace where I know I am working with a highly variable team of developers who in almost all cases will have a very poor background in debugging anything meaningful at all.
> Here’s a rule of thumb I like to follow for C++: make it look as much like C as you possibly can, and avoid using too many advanced features of the language unless you really need to.
This has me scratching my head a bit. In spite of C++ being nearly a superset of C, they are very different languages, and idiomatic C++ doesn't look very much like C. In fact, I'd argue that most of the stuff C++ adds to C allows you to write code that's much cleaner than the equivalent C code, if you use it the intended way. The one big exception I can think of is template metaprogramming, since the template code can be confusing, but if done well, the downstream code can be incredibly clean.
There's an even bigger problem with this recommendation, which is how it relates to something else talked about in the article, namely "safety." I agree with the author that modern C++ can be a safe language, with programmer discipline. C++ offers a very good discipline to avoid resource leaks of all kinds (not just memory leaks), called RAII [1]. The problem here is that C++ code that leverages RAII looks nothing like C.
Stepping back a bit, I feel there may be a more fundamental fallacy in this "C++ is Hard to Read" section in that the author seems to be saying that C++ can be hard to read for people who don't know the language well, and that this is a problem that should be addressed. This could be a little controversial, but in my opinion you shouldn't target your code to the level of programmers who don't know the language well. I think that's ultimately neither good for the code nor good for other programmers. I'm definitely not an expert on all the corners of C++, but I wouldn't avoid features I am familiar with just because other programmers might not be.
[1] https://en.cppreference.com/w/cpp/language/raii.html
Smart pointers are neat but they are not a solution for memory safety. Just using standard containers and iterators can lead to lots of footguns, or utils like string_view.
If you can restrict to using the 'good' parts than it can be OK, but it's pulling in a huge dependency for very little gain these days.
I think Rust is probably doing the majority of the work unless you’re writing everything in unsafe. And why would you? Kinda defeats the purpose.
By contrast, my experience with C++ to Rust rewrites is that the inability of Rust to express some useful and common C++ constructs causes the software architecture to diverge to the point where you might as well just be rewriting it from scratch because it is too difficult to track the C++ code.
The author is arguing that the main reason rewriting a C++ codebase in Rust makes it more memory-safe is not because it was done in Rust, but because it benefits from lessons learned and knowledge about the mistakes done during the first iteration. He acknowledges Rust will also play a part, but that it's minor compared to the "lessons learned" factor.
I'm not sure I buy the argument, though. I think rewrites usually introduce new bugs into the codebase, and if it's not the exact same team doing the rewrite, then they may not be familiar with decisions made during the first version. So the second version could have as many flaws, or worse.
> That’s how I feel when I see these companies claim that rewriting their C++ codebases in Rust has made them more memory safe. It’s not because of Rust, it’s because they took the time to rethink and redesign...
If they got the program to work at all in Rust, it would be memory-safe. You can't claim that writing in a memory-safe language is a "minor" factor in why you get memory safety. That could never be proven or disproven.
Because it's a re-write, you already know all the requirements. You know what works and what doesn't. You know what kind of data should be laid out and how to do it.
Because of that, a fresh re-write will often erase bugs (including memory ones) that were present originally.
The observation is that second implementation of a successful system is often much less successful, overengineered, and bloated, due to programmer overconfidence.
On the other hand, I am unsure of how frequently the second-system effect occurs or the scenarios in which it occurs either. Perhaps it is less of a concern when disciplined developers are simply doing rewrites, rather than feature additions. I don't know.
[0] https://en.wikipedia.org/wiki/Second-system_effect
I just had a PR on an old C++ project, and spending 8 years in the web ecosystem have raised the bar around tooling expectations.
Rust is particularly sweet to work with in that regard.
Running unit tests with the address sanitizer and UB sanitizer enabled go a long way towards addressing most memory safety bugs. The kind of C++ you write then is a far cry from what the haters complain about with bad old VC6 era C++.
> you can write perfectly fine code without ever needing to worry about the more complex features of the language
Not really because of undefined behaviour. You must be aware of and vigilant about the complexities of C++ because the compiler will not tell you when you get it wrong.
I would argue that Rust is at least in the same complexity league as C++. But it doesn't matter because you don't need to remember that complexity to write code that works properly (almost all of the time anyway, there are some footguns in async Rust but it's nothing on C++).
> Now is [improved safety in Rust rewrites] because of Rust? I’d argue in some small part, yes. However, I think the biggest factor is that any rewrite of an existing codebase is going to yield better results than the original codebase.
A factor, sure. The biggest? Doubtful. It isn't only Rust's safety that helps here, it's its excellent type system.
> But here’s the thing: all programming languages are unsafe if you don’t know what you’re doing.
Somehow managed to fit two fallacies in one sentence!
1. The fallacy of the grey - no language is perfect therefore they are all the same.
2. "I don't make mistakes."
> Just using Rust will not magically make your application safe; it will just make it a lot harder to have memory leaks or safety issues.
Not true. As I said already Rust's very strong type system helps to make applications less buggy even ignoring memory safety bugs.
> Yes, C++ can be made safer; in fact, it can even be made memory safe. There are a number of libraries and tools available that can help make C++ code safer, such as smart pointers, static analysis tools, and memory sanitizers
lol
> Avoid boost like the plague.
Cool, so the ecosystem isn't confusing but you have to avoid one of the most popular libraries. And Boost is fine anyway. It has lots of quite high quality libraries, even if they do love templates too much.
> Unless you are writing a large and complex application that requires the specific features provided by Boost, you are better off using other libraries that are more modern and easier to use.
Uhuh what would you recommend instead of Boost ICL?
I guess it's a valiant attempt but this is basically "in defense of penny farthings" when the safety bicycle was invented.
the truth
My viewpoint on the language is that there are certain types of engineers who thrive in the complexity that is easy to arrive at in a C++ code base. These engineers are undoubtedly very smart, but, I think, lack a sense of aesthetics that I can never get past. Basically, the r/atbge of programming languages (Awful Taste But Great Execution).
> Just use whatever parts of the language you like without worrying about what's most performant!
It's not about performant. It's about understanding someone else's code six months after they've been fired, and thus restricting what they can possibly have done. And about not being pervasively unsafe.
> "I don’t think C++ is outdated by any stretch of the imagination", "matter of personal taste".
Except of course for header files, forward declarations, Make, the true hell of C++ dependency management (there's an explicit exhortation not to use libraries near the bottom), a thousand little things like string literals actually being byte pointers no matter how thoroughly they're almost compatible with std::string, etc. And of course the pervasive unsafety. Yes, it sure was last updated in 2023, the number of ways of doing the same thing has been expanded from four to five but the module system still doesn't work.
> You can write unsafe code in Python! Rewriting always makes the code more safe whether it's in Rust or not!
No. Nobody who has actually used Rust can reasonably arrive at this opinion. You can write C++ code that is sound; Rust-fluent people often do. The design does not come naturally just because of the process of rewriting, this is an entirely ridiculous thing to claim. You will make the same sorts of mistakes you made writing it fresh, because you are doing the same thing as you were when writing it fresh. The Rust compiler tells you things you were not thinking of, and Rust-fluent people write sound C++ code because they have long since internalized these rules.
And the crack about Python is just stupid. When people say 'unsafe' and Rust in the same sentence, they are obviously talking about UB, which is a class of problem a cut above other kinds of bugs in its pervasiveness, exploitability, and ability to remain hidden from code review. It's 'just' memory safety that you're controlling, which according to Microsoft is 70% of all security related bugs. 70% is a lot! (plus thread safety, if this was not mentioned you know they have not bothered using Rust)
In fact the entire narrative of 'you'll get it better the second time' is nonsense, the software being rewritten was usually written for the first time by totally different people, and the rewriters weren't around for it or most of the bugfixes. They're all starting fresh, the development process is nearly the same as the original blank slate was - if they get it right with Rust, then Rust is an active ingredient in getting it right!
> Just use smart pointers!
Yes, let me spam angle brackets on every single last function. 'Write it the way you want to write it' is the first point in the article, and here is the exact 'write it this way' that was critiquing. And you realistically won't do it on every function so it is just a matter of time until one of the functions you use regular references with creates a problem.
Yes, this is a serious flaw in the author's argument. Does he think the exact same team that built version 1.0 in C++ is the one writing 2.0 in Rust? Maybe that happens sometimes, I guess, but to draw a general lesson from that seems weird.