What's new in C++26 (part 1)
mariusbancila.ro
mariusbancila.ro
- If you're working in a large C++ code base, you are stuck working with C++. There is no migrating to something like Rust. The overhead of training your engineers in a new language, getting familiar with a new tool chain, working with a new library ecosystem, somehow finding a way to transition your code so it works with existing C++ code and isn't buggy and adapts to the new paradigms is all extremely expensive. It will grind your product's development to a buggy halt. It's a bad idea.
- Every time a new set of features (e.g. reflection, concepts, modules, etc.) is released, people bemoan how complicated C++ continues getting. But the committee isn't adding features for the sake of adding features, they're adding features because people are asking for them, they're spending years of their lives writing papers for the committee trying to improve the language so everyone can write better code. What you find horrifying new syntax, I find a great way of fixing a problem I've been dealing with for years.
- Yes, it's a gross homunculus of a language. If I could switch our team to Rust without issues, I would in a heartbeat. But this is the beast we married. It has many warts, but it's still an incredible tool, with an amazingly hard working community, and I'm proud of that.
1) "CPP keeps getting complex in useless ways. Just use C (maybe C with classes style)". This viewpoint is correct in the sense that modern CPP is essentially a different language than C++98. But I disagree with the rest incredibly strongly - modern C++ is more expressive, safer, and often more performant than the old-school style. Things like unique_ptr, string_view/spans, RAII, etc are very useful and reduce boilerplate code as well as manage complexity.
2) "CPP is garbage, use Rust instead". I have not personally written in Rust, but I do find it to be a very interesting language. I would consider very strongly writing a new project in Rust. But most C++ projects are not new, and although us nerds always love rewriting perfectly working code, it's a good way to shoot your business in the foot.
3) "The template system is obscene". I mean, this is true. :) I do occasionally sprinkle metaprogramming into my code, because it solves some problems incredibly well. But it is essentially a different language grafted on at compile time. if constexpr, concepts, etc help enormously with this problem. And yes, those have all been introduced very recently...
Then, you gotta hire new people when those leave, and the rust hiring ecosystem is also just not there yet.
I worked mostly in robotics. Literally everything is cpp. All the grad students know it. Ros is there setting the mental models for better or worse. The list goes on.
YMMV, but even small bits of python, Go, or (yes) Rust that have crept into the robotics stacks at the various places I've worked have created problems for incoming new-hires, or for maintenance even for senior folks. Python less so than others, but python is challenging to deploy on vehicle, b/c of various hard and soft problems.
In particular, Rust interop with CPP is poor. Should I recompile all ros packages to allow me to call a few things in Rust? Not at this time.
I'm hopeful for the "Rust is robotics" movement, however https://robotics.rs/
The state of the field is so entrenched in CPP though there's more hope in embedded land with the widespread use of C.
Then there are all those industry standards whose definitions are only available in C, and eventually C++.
Likewise when I need to plug into JVM, CLR, V8, ART runtimes, I am reaching for C++, no need to introduce another layer into the sandwich, in terms of build tools, IDE tooling and stuff to debug.
To prove you are not 'boosting'... could you give a convincing example?
Reflection is absolutely gonna feel completely alien to people for a while, but there's a lot of areas in our codebase where I wish I could simply describe a data layout and have the efficient code generated for me instead of writing tons of boilerplate. Take JSON serialization for example. Currently, you have to write your (de)serialization by hand, but with the new reflection stuff one could do it based on a struct's members, and with less error. It'll be wonderful for writing new libraries that will make our lives easier.
It's a proper quantum leap compared to pre-reflection
The 2026 proposal has some neat ideas (I like the ability for the developer to give a reasons for modifying behavior that may create otherwise cryptic error messages, for instance); but the more things one packs in there, the uglier, bloated the specs, and the more complicated and buggy compilers will be.
Once C with Classes was an experimental pre-processor to try out bringing in some Simula ideas into the C world. Today, C++ has become a language that changes dramatically every half a decade, where the main question is "will it compile" if you receive someone else's code, and where even experienced developers cannot tell from compiler error messages what's wrong (g++). The undoubtedly clever people who have been working on it have nevertheless committed war crimes in anti-orthogonality.
Tip: introduce a versioning mechanism like Rust has it, so that you are freed from the burden of having to be backwards-compatible.
Perhaps you meant monstrous?
The dev community (and software profession) is crying out for legible, parsable notation and greater safety. All the modern languages are drawing us towards some of these crucial goals. Python above all for its legible/usable notation, Rust for its compile-time and run-time characteristics; Go somewhere in the middle.
As a recovering C++ coder who discovered that there are better languages, I think that within the Tower of Babel that is the coding-language community, C++ has leased an entire floor for its ravings to the congregation.
People should use more typedef to make C/C++ look sane, but there is some pushback that it hinders readability, but I feel that it is the opposite.
Templates are not that bad as a user, but as a template author, they're a completely different programming language that makes it much harder to express even simple ideas. (Concepts may have changed that, but I haven't had a chance to use them.)
My take would be they are bad for both users and authors.
In 2024 the expected compiler output for a syntax error in a statically typed language is a specific-as-possible report where in the written source the syntax fails - not 40 lines of illegible template error messages.
There are some cases where templates are the best design option. But they should be used only as the last resort when it’s obvious that’s the best way.
Naturally reality often times doesn't match expectations.
https://www.amazon.com/Move-Semantics-Complete-Guide-First/d...
Consistent naming conventions help a lot, but then that just introduces assumptions that could be wrong.
As with most points of code style, it comes down to taste.
I haven’t fuzzed a C++ compiler myself, but our team recently tried fuzzing a relatively simple S-expression-based compiler and discovered several issues in a few weeks [1]. I can only imagine what could be uncovered in C++ compilers. If this hypothesis holds, it suggests a significant attack vector that might elude even the smartest security researchers who are only analyzing repository codes and dependencies.
[1] "Why the Fuzz About Fuzzing Compilers?": https://www.coinfabrik.com/blog/why-the-fuzz-about-fuzzing-c...
[1] https://www.cs.tufts.edu/~nr/cs257/archive/john-regehr/findi...
One example of a higher order reasoning about this is [1] (includes metrics).
[1] "As TVL rises, so does the probability of being hacked" https://www.bittrap.com/resources/defis-growing-pains:-as-tv...
Herb Sutter always tries to sell cppfront in a different way, due to his position at WG21.
It would be rather odd if the chairman of WG21 would also be proposing a C++ replacement.
Yes, knowing underlying levels of abstraction may be useful e.g., godbolt.org is excellent, knowing CPU caches, pipelines, branch prediction, out-of-order execution may be essential for getting orders of magnitude improvement in performance.
It doesn't mean the abstraction itself is useless.
Also plenty of languages compile to native code via C or C++ generation, Eiffel, Nim and some Scheme compilers being the most notorious ones.
However the WG21 chairman can't in a political correct way, assert that like Objective-C and C++ did to C, cppfront if successful will trail its own path, effectively being yet another C++ replacement language.
As of today, C++17 is the latest one can aspire to use for portable code, and better not making use of parallel STL features.
Naturally when code portability doesn't matter, it is another thing.
All my C++ side projects are written against C++latest on Visual C++, and make full use of modules and concepts.
* std::span is in! https://stackoverflow.com/q/45723819/1593077
* Designated initializers (like in C99)
* Spaceship operator and default comparison ops
* More language constructs can be constexpr'ed
* Better structured binding
* using on enums
* Don't need to say "typename" as much :-)
* Bunch of minor improvements to the standard library
Note I did not say coroutines. I still don't understand how that boondoggle made it into the language the way that it has.
As for the rest, the point stands regarding portable code across various C++ compilers.
I agree on the co-routines, while I know C# co-routines relatively well, and the C++/CX stuff that was used as inspiration for Microsoft's initial proposal, they are a bit of a mess, when key WG21 members also don't fully grasp how they have to be implemented, and we need two hour sessions on C++ conferences to go through "hello world" kind of implementations.
It's not a trap if you weren't expecting bounds checking.
> we need two hour sessions on C++ conferences to go through "hello world" kind of implementations.
After one hour it became clear to me I am going to stay away from that stuff until either it becomes much more usable (unlikely TBH) or someone forces me to use it...
I suppose C++26 brings std::span::at, although exceptions are a different can of worms.
Pre-C++98 compiler frameworks used bounds checking by default.
And yes, if I am calling the shots, bounds checking are enabled in release builds.
Never has been a problem other than performance cargo cult folks.
Thankfully governments are making this less of discussion.
No disagreement there. But I'd prefer to turn it on across the board via compiler flag rather than pull in a special library for it and remember to use that library consistently. And if that's the case, I don't see std::span as any more problematic on this front than the rest of the standard library.
(Yes, I know, GSL isn't really a special library on Windows. But anywhere else, it is.)
Which compilers? I'd bet there are compilers that are still stuck at c++98.
The point is, obviously, use other features introduced in C++20 and not have to deal with artificial restrictions when you opt to onboard onto whatever feature you'd like.
To me C++20 has more to do with designated initializers than modules, for the very obvious reasons. It's fine if you take a pass at an upgrade and prefer to take the hit of migrating through a bigger delta, but framing this thing as "what is the point" is indeed missing the whole point.
However I do agree with the feeling for large scale adoption.
The way modules and concepts went down, or the way GC API got added only to be removed, or ongoing contracts discussion, has pretty much settled my opinion that WG21 really needs to adopt the same approach as other programming language communities.
Papers without working implementations for community feedback shouldn't be accepted at all.
I think that everyone has misguided and naive expectations on how such a radical change would roll out to production software.
Changing dpendency management and updating build systems is a hard sell for professional projects delivering production software. It's the most radical change in how you're software is built with zero upside in terms of features. Best case scenario your software works as it always did. Worst case scenario you wasted tons of developement effort to retool and revamp your whole CICD pipeline just to break your project. Hard sell. I mean, why do people think so many projects are still stuck with C++11?
Drastically reduced compilation time is a huge upside for modules.
You can achieve those already with the adoption of basic architecture principles and the incorporation of tools like compiler caches such as ccache. Those who have an interest in those already do it. Modules are no silver bullet and change nothing.
Apple and Google kept using clang header modules, switched focus to their C++ replacements, and clang transition to C++20 modules languished until a few heroes stepped in to do the work.
Meanwhile GCC is still work in progress.
And build tools are still a mess, even cmake doesn't have yet a story for header units.
As for Microsoft, except for Office, there isn't a single Microsoft product, especially C++ SDKs, that make use of modules in any form.
This is quite different from how other programming language ecosystems migrate features from preview into stable.
Currently the Standard is at C++23 and we are ~4 years behind (C++20 is not portable, as you say). At this rate, by the time we get to C++40 or 50, compilers could be behind to a comical degree, like 15 years.
Personally I am interested to see how many unimplemented features it takes before the Committee takes action. (I would find it superbly amusing if they simply did nothing and we got to a point where no new C++ features ever became available.)
It will be good enough for the industry use cases where C++ matters, while other languages keep slowly eroding C++'s market share.
Example of such scenario, LLVM, GCC, JVM, V8, CLR are all currently settled on C++17, maybe eventually C++20, they don't need any additional features, for their C++ use cases, other than having GCC and clang keep up with ISO.
How many people care about COBOL or Fortran 2023 standards?
One notable exception is that I did a project with C++20's coroutines recently.
Source: I've been writing C++ for 8 years.
C++ is not supposed to be fresh. It’s supposed to be portable, and allow fine tuning of programs to bare metal while allowing a sort of high level implementation of API:s (but often fragile and badly designed).
Some new features are excellent, others are not, and the history is plagued with weird historical feature gaps obvious to anyone familiar at all with more consistent languages.
So if something feels weird, there is always a good chance it’s not you, it’s the language (committee).
* Support for multiple, different, programming paradigms.
* Very strong backwards compatibility, all the way back to C.
... then some "freakness" is to be expected. And I do believe some of the additions (to the library and the languages) have been excessive. However, I disagree with your characterization of language development work.
1. Most people on the committee, AFAICT, are from industry rather than academia. And if you consider national bodies, I think the ratio is even higher.
2. "Keeping the language fresh" is not a goal and not what the committee does. Most of what's added to the language are things that people have been complaining about the lack of for _decades_.
3. Feature proponents are those who want to "bolt on new stuff". Committee members are tasked with preventing new stuff being just bolted on.
4. Some new additions are necessary, and others are not necessary but useful, for "tuning programs to bare metal".
Finally - I agree that committee-work has the drawback of less consistency; and there are definitely warts. But for an established language with huge existing codebases and many stake-holders, and with the design goals I mentioned above in mind - an international committee and consensus-building is better than appointing some benevolent dictator.
And are useless now, because everybody who had that problem either already solved it (the solution could have been "use another language") or did realise that it is not worth the hassle. I guess the best examples are `std::format` or `std::thread`.
> But for an established language with huge existing codebases and many stake-holders, and with the design goals I mentioned above in mind - an international committee and consensus-building is better than appointing some benevolent dictator.
That depends, but yes, everything is better than letting Stroustroup "decide".
It might be better if it had a true BDFL, instead of a spiritual guide, and I do worry about the committee getting too far ahead of the industry and leaving it behind, plus what will happen when Stroustrup finally retires in earnest.
But yeah, now and then it does produce a turd, and there’s only so much turd-polishing you can really do.
I guess I’m just saying it’s a development model with pros and cons. The pros are necessary. The associated cons are inevitable.
Everyone has one vote, and everything turns around politics to win mini-elections per feature evolution stage.
[1] https://github.com/google/dawn/blob/40cf7fd7bc06f871fc5e4823...
[2] https://github.com/protocolbuffers/protobuf/blob/c964e143d97...
[3] https://github.com/facebook/react-native/blob/77b3a8bdd6164b...
[4] https://github.com/NVIDIA/cccl/blob/07fef970a33ae120c8ff2a9e...
However the adoption rates of newer C++ features are in fact new are way lower. From what I see lots of projects still use the language as C with Classes, basically, and that ain't going to change any time soon. The GP nailed it - C++ is adding a lot of esoteric stuff that very few people actually need or want.
There is a reason why C++17 is the best we can currently hope for in what concerns portable code, given the actual support across industry compilers, and company project guidelines.
Many embedded shops might still be discussing between adopting C++11 or C++14.
C++20 is still too fresh for my industry, especially for embedded where runtimes require certification for functional safety. Maybe in two years.
What can I tell The Committee? Stop. No, we don't need a single central ex cathedra library for networking. Or graphics. Or SIMD. Even the existing filesystem library is so broken it's dangerous (the standard specifies if it's used on an actual filesystem it's undefined behaviour -- which means using <filesystem> means your program could provoke the legendary nasal daemons just by being run). Stick to generic basics and leave the specialized stuff that not everyone needs to third-party libaries. Nothing wrong with a marketplace of libraries to serve an entire economy of requirements.
> Behavior is undefined if calls to functions provided by subclause [filesystems] introduce a file system race.
~Nobody uses all the recent features, but some new C++20 stuff does get adopted very quickly, like 3-way comparisons, constinit, abbreviated function template, etc.
For C++23, support for it is severely lacking in MSVC at least, so that's going to severely impact users.
There can't be full C++23 support when they are still busy adding C++17 and C++20 features.
It depends what industry you're working on. A lot of HFT shops keep up to date with the latest compiler and make extensive use of new features that improve the ergonomics and compile-time performance of template metaprogramming, which is important for achieving the lowest possible latency.
That's verifiably not true.
https://www.jetbrains.com/lp/devecosystem-2023/cpp/
Anecdotally, all the stuff I do has been minimum C++20 for a few years. If you're using e.g. Qt 6, released in 2020, you're using at least C++17 features without knowing it ; same for recent versions of boost which start depending on C++17 or C++20 depending on the features / libraries.
Some reason I can think of:
- Can't update the compiler (eg, porting the code base to the new compiler is too complicated)
- No compiler support for the new standard that target a specific platform that one still want to support.
- Too much work to update the whole code base to work with the new standard.
- A 3rd party library is not supporting new standard yet.
- The team is reluctant to have to learn new technologies.
Some are somewhat valid reason, some are less, some are indication of deeper problems.
(P.S: My C++ code base is using C++20. Didn't move to C++23 yet because I think some customers might not be ready for it yet for one of these reasons, but I'm going to push for it at some point.)
"One major gripe I have with cars is the number of people that know how to drive one is very close to zero."
Where I work (big tech) everything is c++17. I don't know what the schedule is but in a couple of years every bazel and CMake will get bumped to c++20. And so on.
With Python, there is no standard per se, it is whatever CPython does, and everyone else has to try to mimic CPython.
Most of the new features are for library writers.
From my limited experience - high-quality internal libraries are simply not the reality; less likely to be achieved than winning the lottery. Companies typically:
* are not able to identify candidates able of writing high-quality C++
* do not try to attract SW engineers by committing to high-quality code.
* don't believe they should invest developer time in making a library more robust, and bringing them to the level of polish of a popular publicly-available FOSS libraries.
* do not have a culture of acquiring, honing and sharing coding skills and expertise, with the help of actual experts. Again, time and effort is mostly not invested in this.
Quality gaps like described above - I think this happens when you try to develop C++ without actual experience in C++. C++ is so weird anyone trying to ”do the right thing in the language they are most familiar with” generally get it wrong for the first few years. And then you end up with a quagmire nobody wants to volunteer to clean up.
This is not a skill issue as such or lack of talent. C++ simply is so weird and there is so much bad ”professional advice” that you are expected to loose a few limbs before being able to navigate the design landscape full of mines.
Not only that, but the rookie developers coming in get inculcated into that. That's what they're used to, and they have all the motivation to continue writing poor code, because they need to avoid their better code clashing with what's already written - clashing compilation-wise and style-wise.
Of course, it's not 100% all bad, there are gradual improvements in some aspects by some developers.
I'm not into plusplus, however i'm curious. How the tuple get evaluated to a condition ? is that lowered to if `to && ec` ?
The if statement determines which branch to take based on the value of the condition. This value is contextually converted to a bool and evaluated[1].
[0] https://en.cppreference.com/w/cpp/utility/to_chars_result
Your comment seems to imply the condition is evaluated before initialising the variable(s) at all; is that what you meant? If so, this beast would work (even though it's undefined behaviour to construct a std::string from nullptr, and std::string is not convertible to bool):
const char* foo() // may return nullptr
if (std::string s = foo())But I could be wrong, the paper for the feature is linked but I didn't read it (!).
Yes exactly, my example would work?
> My hunch is to remember that in `auto [to, ec] = std::to_chars(p, last, 42)` the two names `to` and `ec` are not "real" variables/objects, but ...
Oh so my example wouldn't work after all (because std::string s is a "real" variable/object)?
In case of structured binding
The decision variable of the declaration is the invented variable e introduced by the declaration.
but in your case its simply: The decision variable of the declaration is the declared variable.Thus, in your example, the bool check would apply to "s", after the expression is evaluated.
The fact that foo() may return nullptr at runtime and your "s" is UB is your fault for running with scissors.
so "this beast would work" for some definition of "work". But not because of order of evaluation.
Most modern C++ compilers would warn you about not using a bool in a conditional anyway.
This is a contradiction. There is no expression in my code that evaluates to s. foo() is an expression, and then std::string s = ... is assignment initialisation, which is not an expression.
Edit: I suppose that if I used another form of initialisation, the answer becomes a bit more obvious:
if (std::string s('x', 3))
(Not that this makes sense but just the point is to use a constructor with more than one argument.) In this case it's clear the test has to be the just-initialised variable. In fact there could be no arguments at all!x = y is an expression statement in C++, which can be evaluated in an "if" for its side-effects.
And no, don't ask mé why somebody might think that a bool is a suitable type to check for success or error.
It seems to be down.
runtime errors when in a rare path are often never tested until a customer hits that rare case. this is on of the reasons I won't use python for a larga project, eventually you will have critical errors in production because not only didn't you test the code but you didn't even get the minimun proof that it works that a compiler provides.
That's why I won't use C++ programmers in a large project
Career wise, many people are picking up Rust and almost no one is picking up C++, while experienced C++ devs either retire or switch to a higher level language due to landscape change. I would trust supply and demand to be in favour of C++ 10 years from now.
There are also attempts to make C++ more memory safe like Carbon[1] or Circle compiler [2]. If they succeed, why would anyone want to switch to Rust? Also Rust is not ideal for security from a different perspective - I think the lack of a package manager is one C++ strongest points. After working for 9 years with npm, you really appreciate that the dependency you install is usually just a single dependency (even an option for a single header file is common), when there's a package manager, people will abuse it (like install a package with 3 dependencies of its own for something that could be 50 LOC copy-paste) and managing the security of the supply chain is nearly impossible (it will be a legal requirement soon in EU though).
Anyway, I wanted to ask. How is the contracting market looking in C++ world? I'm guessing it depends on the domain heavily? I'm mainly asking about QT and anything that would be desktop / mobile apps / systems programming except video games, but I'm curious in general.
I believe Reflection is being taken very seriously and will be included in standard 26.
Note that over the years "TFA" has lost its profane meaning and is generally used in a neutral way.
Rust is already a good systems language and is getting adoption. D is a great c++-alike already and for 20 (?) years.
There is a mature C++ toolchain for any processor and OS you can imagine.
Simply adopting a different C++ compiler or a newer version of one you are already using can take many months for a large company. Migration to even Carbon would probably take 10x as much effort.
Second, it is mostly a Google thing for their C++ use, it is still mostly a frontend implementation at this point, with semantics yet to be fully defined.
They are also open that Carbon is basically an experiment.
Does it mean that the compiler is more than just a frontend? Or maybe I don't understand what a frontend is?
Frontend in a compiler, is what converts the text code representation of the language into some intermediary format, usually a graph or intermediate language, that is than further processed for type checking and other semantic analysis, suffering other transformations in the process, until fed into the backend, which takes it from there for the further phases required to generate machine code.
https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/index...
I don't understand why you provided that link to goldbolt though? What was it supposed to demonstrate?
Also, you said that one need a backend for a frontend (to be useful I guess). Do you mean to say that the "Carbon" frontend does not have any backend to work with?
I am sorry I bothered you with my annoying questions..
These kinds of "masking" edits prevent good communication. If you want us all to disregard a comment you now totally disown, then just write an edit that prepends/appends that.
If they're fine with accepting the down votes either way, I still want to register my complaint, pointless as it may be in practice.
In terms of UX, it probably would be better if HN allowed a commenter to “dead” their comment, including the attached subthread. People who cared could still view it with showdead, but everyone else would be saved time.
I guess with C++38 we'll get a `always_definetly_ignore_this_wothout_any_diagnostic_whatsoever`.
https://godbolt.org/z/sjefeGvPf https://godbolt.org/z/8a7Ps4KdW
The standards committee are thorough in their mission to including everything and the kitchen sink in C++.
(foo, _, bar) = function_returning_a_triplet();
since you only want the first and third items; the underscore is the placeholder.Useful feature, convenient feature, doesn't complicate your life as a programmer, no need to even remember it, it'll just come to you. Good thing to have in the language IMNSHO.