The result of the C++26 DIS ballot
train-it.eu
train-it.eu
https://www.youtube.com/watch?v=KAWA1DuvCnQ
Slides are here:
https://www.aristeia.com/TalkNotes/TheLastThingDNeeds2-ups.p...
The conclusion is "The last thing D needs is someone like me." meaning D should avoid designing a language where you basically need a niche of lawyers crawling through the language standard to decipher the meaning of various features and then write about how to safely use those features. It's not that languages shouldn't have experts who give good advice, but that the nature of advice in C++ has come down to explaining arbitrary rules, inconsistencies, and obscure corner cases rather than how to use the language effectively to solve actual problems.
He says at some points (taken from the transcript):
"There are some arbitrary, wacky decisions, in my opinion ... There's a lot of, in my opinion, simple arbitrary choices that did not have to be made that make explaining things more complicated and also make working with the tool more complicated."
"Much too much of what I've written about has been tool use, talking about language idiosyncrasies, arbitrary decisions, things you need to be able to remember."
"There is epicycle on epicycle on epicycle inside this language."
And then he followed it up a few years later with a blog post explaining that he won't be updating his book with language related fixes because he no longer trusts himself to know what's right from what's wrong:
"C++ is a large, intricate language with features that interact in complex and subtle ways, and I no longer trust myself to keep all the relevant facts in mind."
https://scottmeyers.blogspot.com/2018/09/the-errata-evaluati...
I’m a “traveling programmer” in Korea. But when I go out to a work site because they say I have to work on C++, as you know, there are so many versions that it’s painful.
Can't imagine what it must be nowadays.
For instance, I can now avoid SFINAE in C++20 and beyond, which was always the ugliest part of C++ templates to me. C++20 concepts simplified most of my metaprogramming needs.
I guess it's fine if one specializes on C++ programming only. But when one needs to use different languages and C++ is used sporadically, I feel like it might be substantially harder than other languages.
So use a minimal approach to C++.
Everyone's trying to bring in the shiniest new toys from all other languages. So-called "modern C++" is an unbearable menu of every possible flavor of procedural, functional, OOP, templates, strong/weak typing, metaprogramming, and so much more. End result is a Frankenstein mix of C, Fortran, Pascal, Python, F#, Scala, C#/Java, Visual Basic, LUA, TCL, Rust, and what not... and that's before we even talked about the STL/STD situation in C++.
The only correct way to work with C++ is to agree on the most minimal subset of features needed for consistency and productivity in your codebase, stick to those and avoid adopting 95% of the crap that's being brought in. Ignore the noise.
And then there's the constant fear of UB, which the compiler doesn't tell you about. This language became too painful for me at least a decade ago.
Technically, you're only learning to mentally unfold multi-level nested templates just to verify how they work, and all for the sake of making the program look small with less boilerplate?
This is complete nonsense. For me, C++ died with the 11 standard.
Unless I am mistaken macros have been around for ages and are available in many many languages.
Hopefully we would have moved on into fully bootstraped alternatives, but open source has decided to build their alternative languages on top of LLVM and GCC instead, with some minor exceptions.
Note that I am starting to have a "find it hard to keep up with the language changes" similar feeling with Java, C#, Python and TypeScript.
9 out of 22 countries voted "no", six would have been enough. These were Denmark, Finland, Iran, Italy, Japan, Luxembourg, Romania, Spain, and Sweden. In a addition and independently only 12 of the 20 participating members approved when 14 were needed.
The dispute is most likely because of a single feature called "contracts".
Very simplified these are conditions placed in a function's signature that are supposed to be checked at runtime.
The proposed implementation of this feature has been controversial from the start with prominent members of the community (Bjarne Stroustrup amongst them) expressing concerns.
The reflection feature is good, I would've settled for less but there's some pretty cool stuff enabled by it.
- direct to struct JSON parsing with property-name aliasing via annotations
- field creation/renaming, I've made a make_named<"a","b">(1,"hello") to create an object with fields named a and b (think of std::make_tuple on steroids)
- I'm basically halfway done with a DB abstraction that can be used similarly to C#'s Linq.
struct [[=sql26::name("posts")]] post { int id; std::string name; };
dbcontext<post> dbctx;
for(auto post:dbctx.posts.where([](auto post) { return post.id>100; }) { ... }
^- in the above example the template inclusion of post creates the posts-field in the context, the where predicate lambda gets a decorated variant of the post type members that are then deferred until execution (starting iterating the itererable).
It's dangerously powerful though since all of this is enabled by consteval, so any IDE support will need to be running the consteval code continiously in these scenarios to update type-info before being able to do code completion (even if people are probably way into LLM's to bother anymore?).
The talk isn't online yet since they haven't had time to edit the videos.
The JSON and make_named example/code can be found in my repo, haven't pushed the SQL feature yet as I'm not happy with some other parts of the API surface yet (aggregation is hard to express/translate compactly and unambigiously).
The actual ISO approvals for C++17 and C++23 came in 2018 and 2024 respectively, so it’s pretty likely this will still be called C++26 if it comes out any time in the next three years
Because here it is trivial to make them backwards compatible, by just using a PRE() and POST() macro which are empty pre-C++26.
The contracts_assert is either static or runtime, which the compiler can decide. Better than explicit static/asserts, which are either unnecessary or costly.
I think defaulting all assertions to enforce would've been better with an optional soft modifier (ie "soft pre(foo)" ), as it is now it's just always assert in a trenchcoat.
What the contracts committee should do is go back and revisit the entire thing with regard to correctness only and not performance. Do the same thing as in Eiffel (not at all easy), which might mean a change in the core language semantics itself. This would be a huge change but maybe acceptable for the benefits it brings. There should only be a simple binary compilation switch between the two versions of the language.
I think the above is doable but it would be a new version of the C++ language and with changes to the toolchain all the way to the binary metadata and ABI. So you would have a "Raw/Performant/Backward compatible C++" and a "Safe Managed C++ with contracts". They could probably interop like Rust does with "unsafe" keyword.
This was the vote to promote the current proposal to draft standard.
[1] https://www.iso.org/stages-and-resources-for-standards-devel...
Also: LEWG is the Library Evolution Working Group.
C++ needs #secure and #insecure built-in. Kill all undefined-behavior and minimize implementation behavior. Maybe add new library types with default safety. Put the unfixable stuff behind #insecure.
I see immediate benefits of things added in C+11, C++14 and C++17. Basically they made it safer and less error-prone.
This may be similar to Java vs Kotlin race, where Kotlin added improvements, while Java was still stuck in 1.8. The answer was to add as many features to the language as possible. Looks a bit like C++ is starting to do the same.
Because Java is losing market to languages with many features. Which is good. Given history of Java under Oracle supervision, and the availability of Rust, Go and C#, I won't ever touch any JRE-based language.
Rust is much less common than version control, but so is C++.
Some of the craziest things about C++ metastasised and are now everywhere in programming, so they don't seem as crazy - but if you're a non-programmer they will still be crazy in C++ and Rust doesn't have them.
For example why does "const" mean immutable? In Rust it means constant, like you'd expect. Why is "Hello" six units of storage space? In Rust it's five, because duh. Why does passing this HugeDoodad into a function expensively copy the HugeDoodad? In Rust it doesn't do that.
This was a thing in the early 2000s, but very certainly hasn't been the norm for a very long time now, at least in my part of the world.
If it's different where you are, you need to take immediate action and inform your company leadership of this extreme liability.
There are, surprisingly, quite a few, including some very high-profile ones.
This is an exaggeration.
For me, C+11/C++14 made the language much more approachable and readable.
It was only that from then on, the language was to be updated regularly.
Would myself (not in the committee) argue that contracts as is would most probably be relegated to modules support hell in terms of support and implementation variations, and I think it's in everyone's interest not to repeat that.
The fact that contracts allow non pure functions to be called is just begging to be a large source of bugs to be. I think that if they started with pure functions, then in future standards mechanised some way to call non pure functions? Would be better and more accepted.
Just like reflection, instead of being overly encompassing, we were given at least the beginning to something great. (Though I dislike some syntax and utility functions, as well as the bareness of some reflection, e.g. can't reflect on templates, other than is it a template.)
I understand the concept but having a feature that's not consistent among compilers, targets, ... all while doing absolutely nothing to solve the _real_ problems with C++. Like that the build model is still the obsolete TU model of C, while adding multiple compile-time features that inevitably end up causing build times to skyrocket considerably. Or that modules are still DOA after 6 years. Or that the syntax is full of bullshit anti-features that could be at least fixed by having a proper build model (like Rust) and editions (like Rust).
Having yet another feature that only works sometimes with quirky semantics is dumb and I understand why many people feel like it should be shelved to prioritise the features people _really_ care about, like meta
And what are those? You seem to assume that "everyone" (except the committee) is in agreement about them.
I like the editions idea. We could have a memory-safe C++ successor without being weighed down by old mistakes.
Any C++ replacement language should support all the features of C++ to be suitable...
Rust is doing everything it can here, these APIs are labelled unsafe, and on a system where they can work, they will work. You can see similar in the filesystem code. On Windows, or a modern Linux, you get what you'd like to have, and on somebody's SysV clone where that's not possible it's still not possible from Rust.
Rust has no reason to touch the original Unix API. Take a snapshot of the values at startup and write an API around that, any runtime modification of the Unix environment is suspect anyway and anyone who wants to deal with that rotten mess can jump through half a dozen hoops.
> Rust is doing everything it can here, these APIs are labelled unsafe
Unix gave us C, clearly Rust should have just labeled every C standard library function like malloc and free unsafe and thrown up their hands instead of introducing ownership semantics and all that messy compiler logic around it. After all Rust can't fix how Unix works, so they shouldn't have tried in the first place.
As a systems language, Rust must provide access to the APIs of the underlying system, and on UNIX, that’s, well, UNIX.
Let me clarify. There is no reason for std::env to be dragged down by UNIX, it could be its own, modern, safe thing with the Unix API living in std::pet_cemetary or some comparably clear namespace for people who have to pass runtime information to a C library through absolutely unsafe ways. Environment variables are usefull, the unix limitations make them less so.
It could be a completely separate "modern, safe thing" which roughly nobody has any use for and which would be confusing since what people want are environment variables and this would instead be its own "modern, safe thing" for some reason.
Mutex<HashMap<String,String>> is probably a reasonable "modern, safe thing" for the handful of people who actually would get value out of this, and the fact it's not labelled "Environment variables" because that's not what it is probably also avoids people who needed the actual environment variables cursing because they were hidden down the back of the sofa.
Why not? Is it the lack of race conditions? The lack of crashes or memory leaks? Is it the fact that you came up with it in five seconds and it is still a million times better than what we have? Or is it the fact that the holy book of Posix spells out how to do it badly in C and because of that we are never allowed to replace it with something better?
I'd start with the basics: A scanf() replacement would be nice, having a ostream/printf() alternative, but not something for input feels very unfinished.
Basic Unicode support is also still a mess.
Another thing I don't get: Why is uninitialized memory still the default? Why haven't they made the uninitialized state explicit in any of the numerous language updates?
But then input handling is much more complex than output handling.
Also, 26 now initialises trivial variables with erroneous values, and is no longer undefined behaviour to act on them.
This is only partially true. From the proposal [0]:
> Moreover, a variable that has a well-defined, erroneous initial object representation under this proposal can still lead to undefined behaviour later on:
void f(T&);
void g(bool);
void h() {
T* p; // uninitialized, has erroneous value (e.g. null)
bool b; // uninitialized, erroneous value may not be valid bool
f(*p); // dereferencing has undefined behaviour
g(b); // undefined behaviour if b is invalid
}
[0]: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27...From a language perspective the only one I can think of is that C++ coroutines are much more powerful than what Rust gives you at the moment, even though they are very footgun-dense (quelle surprise).
But yeah, overall there is very little reason to pick C++, especially now it's feasible to translate existing C++ to other languages.
But isn't using Qt like learning a whole new layer of language on top of C++, the meta compiler, signal/slot system etc and then Qt have its own set of standard classes like QString (instead of using std::string)
The signal/slot system actually doesn't need MOC anymore, and the custom container classes are pretty obvious.
That said I think some Rust GUI frameworks are finally starting to mature. I quite like gpui-kit (formerly gpui-component). Maybe not as easy to use as Qt but it doesn't matter so much now with AI.
For anything weirder than that (PIC?) where Rust is no option, it's not like you have no choice either: You can just pick C.
I don't get this in particular. All of these devices have C, which seems like a better fit for the problems you'd likely have on a platform that's small or obscure enough that it hasn't got something nicer than C++
I think when 20% of your code is trying to energize a solenoid or wrangle a temperature sensor and another 20% is trying to make the vendor's awful LCD controller do something useful and not insane you'd be just as happy writing the mnemonics for machine code instructions and you'd spend less time staring at diagnostics trying to guess why it's doing whatever it's doing because your ten year old fork of GCC has a bug.
Yes obviously. Or potentially Zig once it is more stable.
Doing it in assembly in 2026 is absurd.
One of the easiest ways to generate passive income.
Most of the things the committee has been "working on" are realistically _side projects_ today with AI. I've made countless additions to my clang fork the most notable being a source compatible borrow checker, ie you turn it on and it tells you where you effed up. Zero source changes. Equally as correct as Rust. For any sane C++ program. The committee still isn't capable of implementing this btw.
C++ is perhaps the worst case, but C and Python also suffer badly. Java, C#, and Swift perhaps too.
Once a language reaches broad adoption, it should be frozen. If you want to make changes, then feel free to call it something else. The only good reason for standards committees is to resolve ambiguities in the initial specification.
It’s a misapplication of skills and interests. Language people want to add new stuff, fix old stuff, and make their language universally applicable. Putting them in charge of the spec is bound to end in a C++ style disaster.