79 comments

[ 2.6 ms ] story [ 137 ms ] thread
noob question: why is there still this sort of energy/effort put towards C++ when Rust is available?

edit: thanks for downvoting a genuine question!

Not all organizations are in a position to make the switch or even want to. I personally like Rust and find it interesting, but that doesn't mean I would throw away my C++ codebase.

I'm sure other people will be able to share reasons their organizations use C++

>> I'm sure other people will be able to share reasons their organizations use C++

Rust is great and offers a great path forward, but it was not around 20+ years ago when $BIG_PROJECT was written. C++ was around, popular, and useful so $BIG_PROJECT was written in C++. $BIG_PROJECT made $BIG_COMPANY millions and is still in use today.

$BIG_PROJECT engineers are looking into migrating parts of $BIG_PROJECT to Rust, but the work is still early and the $BIG_PROJECT's millions of lines of C++ won't be replaced overnight. Improved, more uniform tooling for C++ would simplify maintenance for $BIG_PROJECT and make it easier to move $BIG_PROJECT to newer C++ toolchains and even other C++ toolchain vendors.

Maybe one day $BIG_PROJECT will migrate fully to Rust, or perhaps $BIG_PROJECT will be re-written from the ground up in Rust, but for now $BIG_PROJECT has to work.

I'm not a Rust apologetic, but even if the standard tooling committee appears, most big projects won't migrate to these tools, considering that they've been using some building scripts for 10-20 years and maintaining dependencies in hacky ways. These standard tools will mostly help new projects in C++ which can start from scratch and use vcpkg and whatever building tool will be selected (probably cmake or meson).
Projects will slowly migrate, as things are updated ' when a third party library release a version with this they will add support. When they need new features in their build system they will add them in this format, creating a weird hybrid until one day they turn the old stuff off.
There are a few things to note here.

First, the hacky build systems of old are increasingly unsustainable; I've seen quite a few projects migrate to things like cmake in part because not having that kind of build system just doesn't work anymore. (And you get people like Mozilla or Google who write their own build system just for their software, but the end result is the same--you've got some sort of modern-ish build system being integrated). Even at $WORK, some of our old build system stuff with confusing make rules and the like is being shifted to a (hopefully) cleaner cmake stuff, albeit far more slowly than I'd like.

Second, it's worth noting that tooling improvements can motivate change. The ur-example here is the compilation database idea Clang introduced. From what I've seen, every build system that can support it (sorry, autotools) has added information to extract this useful tool. If you can come up with similarly useful build system summary information that is useful for tooling, you're likely to see relatively swift adoption of it.

Third, C++ is already undergoing changes that will introduce build system breakages. Most notably and obviously, modules. Build systems need to adapt to support this, and if people are already making the switch to get new features, incorporating other useful tooling additions at the same time would see adoption.

> I've seen quite a few projects migrate to things like cmake in part because not having that kind of build system just doesn't work anymore

The problem is that CMake is also a cardboard castle built on numerous hacks that break every time a wind blows by. For library users it might be bearable, but for library writers it is absolute hell. And the consistent churn of new half-baked features and subpar documentation really doesn't help. (People talk about "modern" CMake like they do with "modern" C++, the churn is so similar...)

The solution that I've found now is: I've built my own build system in Python that outputs a Ninja file, dead simple. Don't really have the urge to use CMake again (unless when I need to at $WORK)

Let me play devil's advocate here. So you have your own Ninja file, great.

How it deals with:

- Use sanitizers

- Compile for several operating systems, even some later you might need to port to.

- Debug/relase/minsize builds

- disable/enable warnings as errors

- run test suites

- use ccache

- install stuff

- consume external libraries

- choose a nested common nested dependency for the same version for a lib, and, transitively, do it for all subdependencies (something I handle with Conan and/or Meson wraps)

- dll import/export and symbol exposure

- compile static/dynamic PIE/PIC libraries

- custom compilation flags to distribute your lib god-does-not-know-where-yet. (for example distro maintainers)

Now you might tell me you do not need much of that. And you would have a point. The problem is that when you start to mix and match projects

If you have done all that, you did it ad-hoc. CMake at least can do it for all your projects. And CMake is really bad, IMHO, I much prefer Meson.

For all the bad things CMake has, if you do even a 10th of this ad-hoc, you are already wasting time compared to using a battle-tested tool like CMake or Meson.

> Use sanitizers

You don't need CMake for this. You just add the relevant flags onto the specific compiler you're using, and CMake doesn't really help you with that.

> Compile for several operating systems, even some later you might need to port to.

Have you tried using it with Windows, especially with Clang / Clang-CL? I've tried it for several days and gave up (the final reason I ditched CMake and went on building my own).

> Debug / Release / Minsize builds

> Disable / Enable warnings as errors

Again, add the relevant flags to your compiler? Don't see how CMake helps this.

> Run test suites

I personally use doctest for this, and you just need to compile your test executable with the header-only library. Again, no need for CMake. I really don't see how CTest really helps, maybe it's a teeny bit cleaner.

> Install stuff

> Consume external libraries

I really don't like how Fetch_ContentDeclare works, I prefer having my dependencies being explicitly inside my repo (instead of needing to download from the Internet) whether it be in source or as a git submodule.

And anyways, you need an external package manager other than CMake if you really want to manage this stuff properly in a more NPM/Cargo-esque way.

> choose a nested common nested dependency for the same version for a lib, and, transitively, do it for all subdependencies

I don't know if I have understood your sentence right... but CMake doesn't really like having different versions of the same library inside one project (because of CMake lacking any proper modules / namespaces), I remember struggling with this issue before.

> DLL import/export and symbol exposure

> Compile static/dynamic PIE/PIC libraries

> custom compilation flags to distribute your lib god-does-not-know-where-yet

Again, compiler flags.

Overall, CMake might be nice if you are just using other people's libraries, don't really have that many customizations needed, and have relatively simple build processes (no complex custom code generation / compiler needed to be run). But if you are anywhere outside of that then prepare for a hell-like experience struggling with all the archaic under-documented options and searching for obscure StackOverflow questions. Like, the whole experience of using CMake feels so ad-hoc, up to the point that it seems better to make your own that fits for your specific use-case.

> You don't need CMake for this. You just add the relevant flags onto the specific compiler you're using, and CMake doesn't really help you with that.

Meson does, at least. And you might have at least clang/msvc/gcc with different flags for address/thread/ub sanitizers. You might be in that situation. If you are, it is not worth anymore to go do it yourself. You have this for CMake, btw (do not know quality-wise): https://github.com/arsenm/sanitizers-cmake.

> I don't know if I have understood your sentence right

I mean this:

- A uses B uses C 1.3.2

- D uses C 1.4.1

- C uses E 5.1

- F uses E 5.3

Now you have to use the same E and the same C nested dep version for both packages. This is not trivial with a realistic amount of dependencies it can get hairy very quickly. Conan deals with this. You can say: grab 5.2 and 1.3.2 and it will do the thing as long as you know that those versions are actually compatible with your packages.

> Overall, CMake might be nice if you are just using other people's libraries, don't really have that many customizations needed, and have relatively simple build processes (no complex custom code generation / compiler needed to be run).

Are you aware that this makes your project a personal thing that others cannot use? I mean, yes, you can do that, but it is useless outside of your uses unless you either package it for Conan/Vcpkg or build it with a reasonable build system (CMake/Meson/maybe Bazel?/Scons).

> the whole experience of using CMake

it sucks a bit but it works and it has improved. Also, even more important, it is battle tested. But let me recommend you Meson if you hate CMake as much as I do. I work with Meson when I can. The DSL is nice and easy. A piece of cake.

> it seems better to make your own that fits for your specific use-case

I understand your frustration and feeling. I have been there. It is easier to drop a Makefile or something you understand quickly and it will work for you. The problem is when you start with the builds/compilers/shared vs static/sanitized and install targets dance. That makes it unfeasible to run your own solution in many cases bc you are going to make mistakes all these tools already made and corrected and they are battle-tested.

> And you might have at least clang/msvc/gcc with different flags for address/thread/ub sanitizers. You might be in that situation.

Still, how is CMake helping with that situation? You've linked up an external repo with CMake scripts to solve this, why isn't this part of CMake then? Why am I resorted to use someone else's abandoned hacky build scripts from 4 years ago, which might probably have issues? I would rather just do this myself and add the relevant sanitizer flags (and I'm only using Windows LLVM at the moment, so I only need to deal with that).

> ...it can get hairy very quickly. Conan deals with this.

So CMake doesn't do this, Conan is actually doing all the work. And Conan is another complex piece of package manager machinery that I need to integrate into my workflow, which is slow, breaks often, and doesn't have the packages that I need (and even if they have them, don't have the options I need for customization). I've tried using it before and the experience wasn't that great.

> Also, even more important, it is battle tested

If it is battle tested, why are people still struggling with it so much? Why are people spending so much time fixing build scripts instead of writing actual code?

> But let me recommend you Meson

Does it work on Windows with LLVM Clang? That is the most important initial question. If not, I'll pass.

> Are you aware that this makes your project a personal thing that others cannot use?

If I'm building a end application (like a game or a GUI app), then I really don't need to worry about this.

But if I'm building a library for others to use, then I would make sure that there are minimal dependencies (as the tradition with good, frequently used C++ libraries) with ample room for customization of various options using #define flags. I would design it such that one can quickly integrate into any build system without much hassle. (Libraries that I use such as CGLTF, IMGUI, and physfs are all designed in this way. They all don't have CMakeLists.txt in their repos, but are still used frequently in production. It's fine.) For the few libraries that are a bit hard to build on source because of various reasons (like SDL2), I will precompile it and use the DLL binary with the headers.

> bc you are going to make mistakes all these tools already made and corrected and they are battle-tested.

Seeing from all the hackish solutions and workarounds people have written for CMake, I really don't think it is reducing the number of mistakes you're going to make.

The find package set of functions can find metadata and it is a correct way to do it. Same for Meson and pkg config. If you have to do transitive dependency handling by hand, believe me it is nearly impossible without these tools.

There is a lot of CMake hacky code around, but there is also a proper way to do it that works :)

Also, in Meson at least, it is easy to change to compile dependencies from system to subpprojects without touching the build files or even choose selectively which dependencies to use. And it works well transitively.

You can argue that CMake is complex, but the truth is that it adds value.

I say this from a real hate to CMake. But it works.

As for SDL2, as an example, only in Windows you can have it compiled for different runtimes (debug release) in different modes ( static, dynamic), multithreaded and later you have to choose whether to compile SDL statically or dynamically. Now repeat configs for Linux/Mac/clang/gcc. I have done this before. No, it will not scale.

If it is for personal stuff u do not need to release u can do something hardcoded by hand. Otherwise you will be wasting a non-trivial amount of time doing it, wsy more than without a proper build system, no matter how much you hate them...

Rust doesn't have Qt
Not only those are rudimentary unofficial bindings but that looks unmaintained and is already out of date. Last updated 2021.

So no. Rust does not have official Qt support.

It's surprising to me that this was downvoted. Many a Rust project pulls several hundred Cargo dependencies that the developer probably hasn't even checked against basic things like outstanding bugs. The lack of standard package management in C++ sometimes is for the best.
> https://github.com/rust-qt/examples/blob/master/widgets/basi...

this is ridiculous. rust does not have overloading ?

Nope! Rust doesn’t have function overloading like C++. What would that code look like in C++?

(Rust has operator overloading - but that’s not the same thing).

Rust doesn't have any sort of ad hoc polymorphism. Of course, you would usually have a sensible name for these functions (maybe new_0a is a sensible name, I'm not a Qt programmer but I rather doubt it).

Rust's "constructors" aren't magic, whereas the C++ constructors are magic, so they need ad hoc polymorphism or you could only have one constructor for each type.

Let's compare familiar types which weren't built using some sort of FFI magic, C++ std::vector and Rust's alloc::vec::Vec.

std::vector has 10 constructors, they can't have different names, so they're distinguished by their parameters, perhaps your IDE will prompt you with a list of options or you'll remember the parameters you need to do what you intended.

Vec::new() makes a Vec, Vec::new_in(allocator) makes a Vec using a specific allocator, Vec::with_capacity(4) makes a Vec with capacity for 4 things and so on.

Somebody else mentioned operators, note that Rust doesn't really overload operators either. In Rust the operators are getting implemented. If you don't implement an operator, then it doesn't exist, whereas in C++ the operators often have some pre-defined behaviour and you can change that using overloading.

For example if your type Doodad should like to be able to use the + operator on other Doodads, you can implement core::ops::Add<Doodad> for Doodad - now the + operator works when both sides are Doodads. If you'd like a += b; to work, you'd implement core::ops::AddAssign<Doodad> for Doodad. These traits require methods with the appropriate signature e.g. AddAssign::add_assign(&mut self, rhs: Doodad) saying this function needs a mutable reference to a but consumes b.

Oh, before I forget:

Because Rust doesn't have ad hoc polymorphism often people realise they wanted parametric polymorphism here. For example C++ 23 can almost do "bananas".contains("nanas") finally, but it uses a bunch of overloading to pull that off, since Rust doesn't have this, it chose to reify the idea that's filling out that slot in the C++ functions as a Trait, and it calls this the trait Pattern. So, all the places where you mean "You know, for matching strings" you can use any of the ways of matching strings because they implement the Pattern trait

  "bananas".contains('b')

  "bananas".contains("nanas")

  "bananas".contains(char::is_whitespace)

  "bananas".contains(MyCustomThing { "is it fruit?" })
> std::vector has 10 constructors, they can't have different names

Except you can have static member functions (calling private constructors) if you do want that. Of course that doesn't compose as well as overloaded constructors which e.g. lets all constructors for a type T be accessed via std::vector<T>::emplace_back().

It's not exactly Qt, but some former Qt folks are making https://slint-ui.com/
and knowing three of them IRL I really trust them to make something amazing - they already do especially with the work on microcontrollers and it will likely be my first choice if I have to show an UI from an uc - but API-wise Slint is quite similar to QML with a declarative tree approach ; having worked now on maybe 3 dozens of distinct projects using either QML or Qt Widgets (traditional widget tree retained API), ranging from one-shot software used at 1 event written in an afternoon, to car dashboards, to traditional WIMP author software, to freakin Unity3D plug-ins, I still find the widget API better for many, many cases (mainly in the technical and CRUD UIs which I mostly use my computers for).

But when I say "Rust does not have Qt" this is actually not what I refer to.

A big point of Qt is that you have a complete consistent library with an event loop that will handle everything from GUI to network / serial port communication / media playback / JS scripting / database access / ... transparently, with APIs that are fairly cohesive. With Rust whenever I looked at it it was async API flamewar and the need to use 50 libraries that all have slightly different conventions, namings, etc. Qt brings consistency, just like boost does, and that's why I like using those ; most of the time I don't even have to think about what the name of something is going to be in a class / type I've never used, because it's obvious from the naming scheme of the library.

> A big point of Qt is that you have a complete consistent library with an event loop that will handle everything from GUI to network / serial port communication / media playback / JS scripting / database access / ... transparently

A kitchen sink library, re-implementing absolutely everything. I do mean everything there's even a QString to use because heaven forfend a C++ library wouldn't have its own custom String class...

The temptation to build kitchen sink libraries is exactly what this proposal seems to be fighting. No, I don't expect they will win.

Kitchen sink libraries usually work in all supported platforms, no need to play tetris with OS and compiler version support.
I think the reason QString was necessary was because STL's std::string was just really lackluster (and still is). The problems:

- An barebones API that's hard to use (missing really basic functions like contains() and split(), although they might come on C++2-god-knows-fuck-when)

- Until recently (C++20), didn't have a convenient way to format strings. QString::args() isn't that nice, but at least it's far better than using the stream operators. It's just sad that people were hyped that std::format was finally coming in the year two-thousand-fucking-twenty...

- Dealing with encodings and locales. Unicode conversions, anyone? Like, C++17 actually even deprecated the whole <codecvt> header! I understand it was absolute shit, but the audacity to remove it without presenting an alternative...

> A kitchen sink library, re-implementing absolutely everything

yes, and having written projects in both the kitchen sink and the many-libraries approaches, the one that consistently shipped software fast is the one with the kitchen sink framework

I really hope their project succeeds, even outside of it being written in Rust. There is a very real and urgent need for a framework for complex cross-platform desktop GUIs, and Qt (which was really the only good solution for it) is currently sinking under its weight.
This is the only correct answer.

Although give it 10 years and that issue should be resolved.

(comment deleted)
Rust doesn't solve any real problem.

It's a meme language that is only used for writing blog posts and internet commentary.

So, Linus Torvalds, who rejected calls for code written in C++ to be accepted into the Linux kernel for decades because he thought that the extra features it provides were not worth the added complexity it would bring, has decided to allow Rust support in Linux because... he suddenly got infected with brain worms that made him want to be a crowd-following blogger writing commentary for internet upvotes?

And not because he thinks Rust might be able to solve actual problems in kernel development?

I want whatever drugs you're taking.

To be completely honest, I would wager it was more a matter of ego than anything rational. C++ kept improving over time and he knew that, but rather than revise his position and admit to an error, he stubbornly persisted until Rust came along, and that gave him an out. "Well, C++ is too shitty; but Rust, a language that has not been around for even a decade, that's was I want to add support for in the kernel". Rust has pretty much all the failings he accused C++ of having, it just has memory safety as an additional benefit.
> Rust has pretty much all the failings he accused C++ of having, it just has memory safety as an additional benefit.

Memory safety is one hell of a benefit. In contrast, if you look at Linux' coding style, C++ really doesn't have any benefit over C.

Not to mention, many of C++'s advantages come from the STL, which wouldn't work without extra work in kernelspace. Rust has been designed for running on bare metal from day 1.

Linux would benefit from a compiler to build a vtable where plugins are needed. Linux would benefit from a STL like library that might be home grown but will support more types than whatever they are doing now .
You're talking about migrating kernel code to C++, but I'm talking about supporting C++ code in the kernel. That is, if third parties wanted to write Linux drivers, the only supported way was to do it in C.

That aside, the kernel does do polymorphism the hard way (with unions and arrays of function pointers) in a few places; the example I saw was some filesystem code, I think. C++ is also much more type-safe than C, mostly by refusing to implicitly convert between unrelated pointer/reference types and preventing you from inadvertently doing something absurd. References also make null checks unnecessary and convey to the caller that they're supposed to pass something valid, and RAII simplifies a lot of resource management. Templates also reduce boilerplate and are type-safe, although they're also a harder sell and not everyone's cup of tea.

I agree that memory safety is a huge advantage (although on the other hand, a double linked list in Rust is currently impossible without unsafe blocks), but I refuse to believe this decision has nothing to do with stubbornness.

> the kernel does do polymorphism the hard way (with unions and arrays of function pointers) in a few places

Using C++ classes has some disadvantages compared to C-style polymorphism - especially related to memory layout and allocation - in C++, memory is allocated by the code instantiating the object, not by the object's code, so you have to know the size of the type (including private fields) in any place where you are instantiating it. Not sure how relevant this is for kernel code.

> C++ is also much more type-safe than C, mostly by refusing to implicitly convert between unrelated pointer/reference types and preventing you from inadvertently doing something absurd

This part I agree with.

> References also make null checks unnecessary and convey to the caller that they're supposed to pass something valid

I think the distinction between references and pointers is one of C++'s worse ideas. You can't generally replace pointers with references either.

> RAII simplifies a lot of resource management

RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors.

> Templates also reduce boilerplate and are type-safe

Templates are more type-safe than macros, but not that much more (since the template language is essentially a dynamically-typed program, even though its output is a C++ AST that will be further type-checked). Like RAII, they also require you to use other features of C++, especially operator overloading, and likely also copy (and more recently, move) constructors.

> I agree that memory safety is a huge advantage (although on the other hand, a double linked list in Rust is currently impossible without unsafe blocks), but I refuse to believe this decision has nothing to do with stubbornness.

I do agree that stubbornness may well be a component. However, I believe that there is a coherent argument that can be made that supporting C++ for kernel modules is not worth it, while supporting Rust for kernel modules is. I'm not saying that this is the argument that Linus is making, but I do believe it can be made.

Especially since we also need to remember that all kernel modules are part of the kernel source tree. Supporting an additional language has a significant cost for everyone who is maintaining the kernel, since they need to add tooling to handle that extra language for all targeted platforms.

It should also be remembered that C++ compilers are even worse than C compilers at mis-using instances of undefined behavior to mis-optimize code, especially since they typically rely even more on optimization steps to have half-decent performance.

> RAII doesn't work without bringing in a whole lot of other heavy-duty features: mainly exceptions, but also constructors and destructors.

You don't need exceptions to make RAII work. It does make fallible resource allocation a little bit trickier (the RAII object needs to be prepared to be in a live-but-failed-allocation state), but it's very doable. Constructors and destructors are absolutely not heavy-duty features.

They are heavy duty precisely because they rely on exceptions to signal error conditions (or, in the case of destructors, are completely unable to signal errors safely at all), at least in combination with RAII.

Without exceptions, RAII is quite cumbersome - especially in kernel mode, where you can't assume that memory allocation is always successful, so even memory allocation is a fallible resource allocation. Not to mention, RAII makes it impossible to check whether you successfully released the resource, which is a concern that the kernel can't always ignore the way user-space C++ code usually can.

The key to RAII is not so much constructors as destructors. If you want to be able to signal construction failure you just have an init() member function that returns a bool or some integer. As for dynamic allocation, when I worked on driver development for Windows, I just had an allocate<T>() function that returned a properly constructed std::unique_ptr<T> with the deallocation function properly set and with the T fully constructed (you may need more than one allocation function if you need to allocate from multiple contexts that require allocation in slightly different ways).

>Not to mention, RAII makes it impossible to check whether you successfully released the resource

Actually, RAII makes it much easier by encoding that knowledge into the owning object. Using the example above, you could call allocate<T, do_something_special_on_deallocation_failure>(). Then whenever the pointer goes out of scope you'll do the special thing without the user of the object having to know what that special thing is.

All of this complicates the program significantly, and greatly reduces the advantages of RAII. If you're not using the constructors for initialization, than your desturctors also have to handle the case where the objects didn't even attempt to acquire the resource they may represent, for example.

Also, how to handle a failure to release a resource is context dependent, you can't encode it in the type of the resource unless you create a different type for each call site.

If you really need to do something different at each release point then you can have do_something_special_on_deallocation_failure() notify the error to the release point by a number of different mechanisms.

Yes, all of this makes the code more complicated. The point of these features is not to make the code simpler, but to make it more robust. Rust is also more complicated than C.

Yes, without exceptions is more involved, but way easier than any C alternative doing couple-of-functions mstching for alloc/dealloc.
If you're relying on exceptions to make destructors fallible, you are going to have a very bad time. The protocol of throwing an exception is to destroy all objects in scope, and if doing so causes more exceptions to need to be thrown, you're going to end up either with a hard crash or one of the exceptions being destroyed. If the fallibility of resource deallocation is really important, then RAII isn't a good model to use (I prefer something like a connection.with_transaction([](Transaction &T) -> Result) model myself for this).

Given that fallible destructors aren't an issue, exceptions are only an issue for RAII if constructors can only fail with exceptions. Note that Rust has fallible constructors without exceptions, and C++ could implement that too, though it is definitely less ergonomic than exceptions.

> Not to mention, RAII makes it impossible to check whether you successfully released the resource, which is a concern that the kernel can't always ignore

Serious question: what does the kernel do if it fails to release a resource? Like memory, for example?

> You can't generally replace pointers with references either.

If this were generally true, I would expect to see a lot more use of pointers than references in c++ code, but in practice it's the exact opposite--it's rare that one needs to use a pointer rather than reference. Basically only if it needs to be able to be null or if it needs to be able to be modified.

In C code, you'll find many uses of pointers for iteration, which can't be replaced with C++ references. C++ typically also uses pointers in these cases, but wraps them in a layer of iterator templates (that is, hopefully, optimized out into a raw pointer access).

Not to mention, references obscure the difference between copying an object and sending its address at the call site, and obscure the difference between accessing a local object and a pointed-to object at the access site - a major disadvantage compared to pointers. Especially for a project which heavily uses email patches for code review and discussion.

Also, there are programming errors that can lead to a NULL reference, and there is no way to guard against that in code using the reference (well, none that doesn't generate Warnings, and/or is liable to be optimized out) - whereas at least with pointers you can always check in your own code.

Note that I was talking about using pointers to pass a single object by reference. In such cases references are 100% better than pointers, if the pointer is never supposed to be null.

>Also, there are programming errors that can lead to a NULL reference, and there is no way to guard against that in code using the reference (well, none that doesn't generate Warnings, and/or is liable to be optimized out) - whereas at least with pointers you can always check in your own code.

On the other hand, if you find you've received a null reference as a parameter then you know that something has definitely gone wrong, because unlike with pointers null references are impossible in the absence of UB. If all you know is that the function has received a null pointer then you could waste a lot of time trying to figure out how the program reached that state, when in actuality the problem is that someone else wrote out of bounds.

> In C code, you'll find many uses of pointers for iteration, which can't be replaced with C++ references.

In c++, ranged for loops are both far more common and idiomatic for iteration, and will compile to the most efficient form possible. At least for gcc and clang, you definitely don't have to 'hope' that they will be optimized to the equivalent pointer-based code--they will be.

> ... whereas at least with pointers you can always check in your own code.

Regarding null references -- the only way for that to happen is by dereferencing a null pointer, which of course is equally invalid with or without references.

BUT: if all you have is pointers, then--all else being equal--you will have many more places where you may need to check whether a pointer is null.

Once you've converted a pointer to a reference by dereferencing it, you (and the compiler) can legitimately assume that it's never null. If you ever encounter a 'null reference', the problem is never with the reference, it's always guaranteed to be with a deference somewhere higher up the stack. As a result, when references are available and preferred, there are not nearly as many places where you have to decide whether to check for null in the first place.

>It should also be remembered that C++ compilers are even worse than C compilers at mis-using instances of undefined behavior to mis-optimize code, especially since they typically rely even more on optimization steps to have half-decent performance.

Nonsense. Modern toolchains treat C and C++ as almost interchangeable. For example, Clang compiles both naively to a machine-independent IR and then performs all its optimizations on that. "C is portable Assembly" has been a myth for a long, long time. Nowadays C is effectively as high level as C++, just with fewer features.

The Linux kernel uses GCC (for a long time, it used a specific version of GCC), and it uses some flags to disable certain notions of UB, some of which were particularly added for Linux. Do these work for C++ code? Possibly, but who knows.
So they had the GCC people define the behavior based on a flag. Since undefined behavior means that all behaviors are permissible, including defined behavior, I see no reason why any C++ compiler couldn't do this.
> It should also be remembered that C++ compilers are even worse than C compilers at mis-using instances of undefined behavior to mis-optimize code, especially since they typically rely even more on optimization steps to have half-decent performance.

Could you provide a concrete example of this? Personally I've not seen anything like what you seem to be describing.

> You're talking about migrating kernel code to C++, but I'm talking about supporting C++ code in the kernel. That is, if third parties wanted to write Linux drivers, the only supported way was to do it in C.

That hasn't really stopped anyone who wants to write their out of tree drivers in C++.

> That aside, the kernel does do polymorphism the hard way (with unions and arrays of function pointers)

C++ virtual functions are needlessly inefficient for interface classes where you only have a handful instances for each implementation (most commonly only one). Support for something like structs of function pointers with a little bit of sugar so you don't need to explicitly pass the this pointer would be very velcome even outside kernel space.

Wake me up when some real kernel module actually gets written in Rust.

(Actually, no, strike that, I don't want to sleep forever.)

You're getting lots of explanations for why people don't switch to rust, mostly existing projects, but I'd like to point out that plenty of people still start new projects in C++ as well. Most game dev has to be c/c++ if you want to release on consoles. This isn't technically true, but in practice it is most of the time. Not everybody wants to program in rust's pseudo-functional style. Some people like C because if you can generally map nice C code to its assembly in your head.

In my opinion, memory safety also gets a little overblown. Most applications don't really need memory safety, and for the ones that do, C++ smart pointers are good enough. I'm sure plenty of people will have strong opinions against that.

Ultimately there is this sort of energy towards c++ because there are orders of magnitude more projects and developers that use C++, and it would be silly to stop work on C++ every time a C++ killer came along.

> Most game dev has to be c/c++

There are certainly a number of high-quality C libraries hanging around (SQLite, libcurl, etc) that might be used, but I don't think anyone's doing serious game dev in C these days. It really is all about C++, and C# for Unity.

> C# for Unity

Scripting doesn't count for this comparison. Unity is still a C++ engine.

Not since Burst compiler started to be used to replace C++ code, additionally C# is the only thing most people can touch on Unity, unless they write native plugins.
For all it's faults. C++ (along with other languages) already has an international standards body.

While a language made by committee is invariably garbage (citation: JavaScript), there is something to be said for stabilizing the standard for safety-sensitive systems like flight, space, medicine, automotive, and the ilk. Not a grate look if your space-balloon goes over like a lead-balloon.

Also, Rust is not something you can just "switch" to; it's not javascript or python. You have to UNLEARN a lot of bad nuns before you can truly be productive in Rust. Learning rust is a steep climb, coming from languages like C & C++; if you are coming from a language like python or lisp, it's a damn near smooth-vertical-shaft.

Frustratingly, a lot of the books for newbs are like: "So you wanna do this cool thing in Rust? Then do this tutorial project for this crate!", and they don't actually go over idiomatic rust algorithms. The way rust handles code and data, lends to "different" ways of solving problems. The best way to learn rust, is to read rust, but that can get confusing with the traits and typing bounds and lifetimes and unwraps. On the other hand you get to say "turbofish" a lot; so there's that, which is nice.

And so the issue becomes one of monkey-power. I can find bucket-fulls of hairless apes to bludgeon in C or C++ code, but it takes a more sophisticated `Ook<T>` to see the Octarine that is Rust.

> For all it's faults. C++ (along with other languages) already has an international standards body.

Not everybody in the C++ community is convinced this is a benefit.

C++ has an international standards body without self-restraint and good taste, and one which cannot fathom the idea that its own discontinuance could be of benefit.
C++ can be more pleasant to write than Rust, especially if you limit yourself to modern features, OO-style, etc... It's also extremely mature, has a library for everything, is on every platform known to mankind, etc...

C++ has a lot of baggage and if you maintain old C++ software I'm sure it's a massive PITA but starting fresh in C++ isn't a bad experience.

The simples answer is that many orgs have accumulated megatons of high quality production code that cost them unknown billions in total to create and that runs half of the world. Throwing it away is insanity. Hence need to improve on what is already available.

Also not everyone believes in silver bullets and modern C++ is fairly god and easy enough to use. Just do not try to know ALL of the C++. This kind of expertise is needed by whole 2.5 people. Partially true for any complex enough language.

You are still more than welcome to start new projects in whatever language warms up your heart or rewrite already existing stuff.

P.S. I do not ever downvote post no matter what does it say.

Why? Either (1) you have so much c++ that moving it rust is a waste of money; we have 10s of millions loc (2) you need access to 3rd party lib in the eco system not native rust (3) c/c++ builds are a pain in the butt. Even if one was sick of c++ and like rust it's for new stuff, not maintenance of existing c++ stuff
Really hope this happens

Using vcpkg with CMake/Meson/Xmake mostly solves the package management+ build system problem but God help you if the lib you want doesn't have a vcpkg definition or CMake file

xmake has its own package management repository and also supports package integration from conan/conda/brew/pacman/dub/portage/apt. Even if we don't find the package we need from vcpkg, we can still get it automatically from any other package management repository.
Kind of yes, but as someone who started studying CMake only recently, I'm terrified of the fact that it's a metalanguage (CMakeLists) above another metalanguage (Makefile) on top of another metalanguage (command line) to compile projects in different language (C++). The amount of things CMake does under the hood is insane to me. And if you don't have a clue, at least in general, how it does its thing, you're walking thin ice...
Agree, totally. Rust and golang got build deps in the compiler w/o wrapping make
That'll fix C++.

More standards.

Nothing better than a language designed by a committee of middle-managers with a half-warmed-over-IQ.

Just came here to tell you that I upvoted you and my initial sentiment resonates with your wording.
It's mostly run by code-golfers which is much worse.
Presumably C will piggyback on this.
Guys, you may be 20 years too late, but I still applaud you. We need this.