35 comments

[ 0.68 ms ] story [ 18.2 ms ] thread
(comment deleted)
30 years late, but I will take it. Contracts look useful and less messy than exceptions.
There is a small hint of it at the end, but I really hope compile time contract assertions become more common. I know some languages like spark, dafny and a few others do it and generate implicit contracts for things like divide by 0. I've been experimenting with my own custom language that do these things and going back to c++ every day at work is actually a slight let down because of it.
One thing that I'm curious about regarding all of this: I thought all of this stuff landed in C++26, yet we are still getting papers like https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2026/p43...

> The C++26 draft has not yet had its final ballot

This is co-authored by Bjarne, and so I'm sure it's not trivially false, but maybe I am just missing some detail. I know Bjarne was threatening to cast a veto of C++26 over this, but I thought he did not?

Anyone who follows the process a bit more than me have some context here?

Everybody has their own ideas of what they want from Contracts. C++26 contracts are trying to get a minimal system that everybody can agree on. The current contracts are not good enough for anybody who wants them - but it is good enough that they can start figuring out the details of making all the different factions happy.

C++26 contracts are written by people with experience in ADA/SPARK. While we don't have experience in C++ contracts, there is plenty of experience elsewhere. I find it odd that the paper didn't mention Spark at all!

The criticism that it is experimental in all compilers is a fact that can never be anything else. Chicken and egg - nobody will make this non-experimental until it is in the standard. There have many small scale experienements with contracts - enough to agree we want to use this on a larger scale but we need it in the standard first.

> The current contracts are not good enough for anybody who wants them -

This is a recurring pattern across large changes to c++. Modules and coroutines both are great examples of this.

> but it is good enough that they can start figuring out the details of making all the different factions happy.

I don’t think there’s really a plan to make the factions happy, there’s a plan to get X in, say it’s in and then ignore any actual criticism in favor of “it was the best we could do” while pointing at the other groups for not accepting the massive flaws.

The only complaints I've heard about modules that is real is it took some time to be ready. Everything to use is from people who don't use C++ and want to pick on it.
I’ve written c++ every day for the last 15 years. The problem with modules is they’re the meeting point of a pile of decisions (or lack of). Modules have been talked about for longer than I have been programming and I still don’t know of a project that is using them that has seen a compile time improvement.

You might argue that modules aren’t the solution to compile times, but for a very long time they were. Now they’re a better way to structure code, except they’re not really backwards compatible. That dorsnt matter because the committee doesn’t consider that bit at the same time refuses other changes that may have similar impacts.

I think c++ is caught between a rock and a hard place. There’s a group that wants only existing behaviours standardised, and another that wants the language to be a force that brings the ecosystem with it. What we get is the latter group proposing changes that look like progress, but no (or limited) real change happening due to the first group, while the first group are forced to have the language change almost for the sake of it to placate the latter group.

Modules have just reached to the point where the tooling is all ready for people to adopt. Right now we are seeing the early adopters start to use modules. We are still waiting to see what they report. They are certainly a major change to how you program C++ and so adoption is going to be slow - retrofitting something new to an existing project is always hard. I still have some C++98 code that has naked new and delete. I'd love to get rid of it but it would be a long painful process to refactor and it's not worth it when the code has been stable for decades. I'm still hopeful that they're a useful thing for the various benefits they should provide, but only time will tell. People who claim that modules have failed because we haven't seen benefits yet are just ignoring the reality that change is going to be slow by nature.
>> The current contracts are not good enough for anybody who wants them - > This is a recurring pattern across large changes to c++. Modules and coroutines both are great examples of this.

Coroutines are ready since C++20, there is some stuff missing in the language (`for co_await` being the most obvious thing), but the feature is useful as is...

The current state of C++ next is maintained in what is called the C++ draft.

People (from the committee of experts appointed as national body representatives or invited experts) submit a proposal which is essentially a set of changes to make to the C++ draft, just like a merge request. A proposal, by the way of it's changes can either add a feature to C++ or remove features from C++ (kind of like deleted code).

In each C++ meeting, they have a vote for each proposal in the meeting and decide whether that proposal is allowed to act on the C++, thereby determining if the features gets in the draft (if the proposal was proposing a feature) or if the features is kicked out of the draft (if the proposal was advocating for removal of a feature).

Once a proposal has been voted in the draft, only another proposal can remove that feature from the draft.

Every 3 years, they seal the current state of the draft into a standard and send it for voting to the official ISO C++ committee of national bodies (different from committee of experts we mentioned above). And I think each national body has a veto. (that is the vote has to be unanimous, but not sure here).

At this point, first the National bodies can make comments where they can threaten to veto the standard if their comment is not looked at. Then, the committee of experts can either respond to the comment or follow the comment or do whatever.

The official committee (essentially national body members) then votes and can only approve or reject the standard in the whole. So, if they reject of example C++ next now, there will be no C++26.

The whole process from sealing to actual voting takes around a year or so. In the mean time the committee of experts starts working on the next c++ standard from the sealed state forward without waiting for the committee to ratify the current one.

What Bjarne is doing is that he was threatening to get a national body to veto the proposal so that there is no C++26 at all. So, his point was, either accept his paper as it is, or he probably gets US or Denmark or some NB (not sure which) to vote no on the C++ standard.

Thanks for this! I vaguely knew most of it but it's great to hear more details.

I think that my misunderstanding here is because I thought that the vote in Croydon back in March was the last chance to veto things, but re-reading https://herbsutter.com/2026/03/29/c26-is-done-trip-report-ma...

> are now producing the final document to be sent out for its international approval ballot

So yeah, I guess in most cases this final ballot is a rubber stamp (not a bad thing, actually, I'd argue it's the way it should be) but maybe this time it is not.

Yeah, Croydon was the deadline according to the committee's internal process on changing the draft before it is sent for ballot (rubber stamped as you said typically). What Bjarne is asking for is: 1. either an exception to the c++ committee's internal rule about changing the draft after the definitive meeting (in this case croydon) 2. or veto in the national ballot as you said.

By the way, didn't realise when I answered this that I was answering to you. Thanks for all the work on Rust! Your views on Rust and C++ are both much appreciated.

You're welcome!

Just to be extra clear about it, while there's clearly some dysfunction going on in WG21, I don't think Rust's process is free of it either. I do think there's a lot of pros to the way Rust does things, but this stuff is just very hard, in general.

I wish I had actually written "The elephant in the room" back when the safe c++/profiles stuff was going on, but I never actually did. Oh well. Probably wouldn't have changed much anyway.

This does sound a lot like there's a real risk of C++ imploding, in some form or another. (Arguably, it has been in that state for a while now.)

I personally agree that contracts probably shouldn't be in the standard, but this whole situation looks like a mess.

> And I think each national body has a veto. (that is the vote has to be unanimous, but not sure here).

No veto. Every P-member has a vote (abstain/approve/disapprove). Whether C++26 gets published is decided by numerical consensus.

I recently watched the c++ documentary and it was super sobering in how it mirrors this description of the process. https://herbsutter.com/2026/06/04/c-the-documentary-released...

The true goal of C++ is the self-preservation and funding of the ISO Committee specification “engine”, while compilers are merely an accidental by-product.

Once you see this then suddenly a lot of odd behavior makes sense. For example the committee can’t break ABI because then the old companies wouldn’t fund the new c++ standard, but would fund a committee that maintains/forks the old thing. The complexity / bureaucracy also provides jobs for those involved in many ways including writing new books every year and or consulting.

While end consumers might really care about compile speed, modularization, security, and all of the things modern languages give, that is secondary to keeping the committee alive.

Younger me would be like, oh no this is horrible someone will fix this! Older me is more sober and understands that once a system is up and running it will continue as is (this being an example of Pournelle’s Iron Law of Bureaucracy). Security by the way of migrations to Rust is causing what the committee sees as the first real threat to its existence as its patrons start adopting more and more Rust. As a result for the first time c++ is going to break compatibility as a means to keep them around just a little longer.

(comment deleted)
Between how long it took us to get standard library hardening in C++ and seeing what ISO did to the co-founder of MPEG, I'm convinced ISO is fundamentally incapable of actually being responsive to stakeholders, specifically because of the insane national body vetocracy.

For context, under Leonardo Chiariglione's stewardship, MPEG attempted to ship a royalty-free codec called Internet Video Coding (IVC) and it was immediately torpedoed by Samsung claiming ownership. In any sane environment you would amend the standard to remove the claimed technology, but ISO specifically does not allow you to do this. There is no obligation for an ISO participant to identify the patents being claimed unless they refuse to offer a license on FRAND terms. Ergo, Samsung just said "we own this and will sell licenses for money", and IVC was dead in the water as a standard[0].

Leonardo attempted to bring this to the attention of ISO, but the actual formal process for this was blocked by... you guessed it, a national body vetoing it. So the patent policy that prohibits ISO from distinguishing between royalty-free and royalty-bearing codecs stayed. Oh, and then they cut MPEG up into six pieces so Leonardo would have nothing to run anymore.

C++ was an unusual language in that, for about 10-15 years, the only other competing systems programming language was C - another ISO standard, and the one C++ was originally based off of. The standard answer to "but I want memory safety" was "use a garbage collector"[1]. I distinctly remember hearing interviews with compiler developers talking about how adding even these basic features to C++ would be interminably painful, because you'd inevitably have to debug some deeply nested macro in a library somewhere, so shut up and just enjoy that we gave you Vector<T>.at().

The day Rust becomes an ISO standard is the day it becomes dead to me.

[0] IVC was specifically designed to be inferior to the royalty-bearing H.265 standard, as Leonardo himself wanted to keep the royalty-free codecs second-tier.

[1] To be clear, there was research into non-GC languages with memory safety - that's where Rust got its ideas from - but it was a very small niche until Mozilla put their feet down and gave legitimacy to something.

Re: [1] - correct me if I'm wrong, but from what I remember, Rust originally did have GC and relied on it for safety, but as development went on, they added more static checks and eventually, very late into pre-alpha phase, realized they don't actually depend on GC anymore and can cut it out? As in, Rust wasn't part of the non-GC safety research at all, it just happened organically?
(comment deleted)
Yes, but at this point the critical piece that made no-GC memory safety possible - linear types - had already been researched and known in the FP community. Rust's critical invention was "what if we modeled heap ownership and borrowing with linear types".

Okay, strictly speaking, Rust types are affine, not linear. Leaking Rust values is a safe operation. In a linear Rust the compiler would have to prove all values do not leak, but this would be incredibly difficult and probably make reference counting illegal.

Yeah, this makes sense. Although all this affine type stuff was also the basis for the C++ move semantics (although the resulting type system isn't affine at all, the mental model is very much that, with deleted copy constructors and all), which predates Rust project by at least a few years. So by the time Rust 1.0 rolled out, it wasn't a new concept at all even in system programming circles.

The actually innovative thing about Rust is how they made object lifetimes into a H-M-esque type system and used this 50 year old algorithm to detect dangling pointers at compile time.

To further this, "destructive move" as C++ calls it almost happened, but ended up not. So it almost had it the same way as Rust too.
The funny thing is, Rust doesn't quite have a destructive move either. Or, at the very least, it's not exposed to the type system. The Drop trait that tells you if a value of a type T was destroyed can only give you a &mut T to it. There's no type to represent a value you own stored in memory you don't. So we have the funny situation where if you implement Drop, you can't take values out of the thing that got dropped.
Destructive move is when the move skips destructor. Rust does have that. What it doesn't have is destructive destructuring - you can't skip the destructor when destructuring a struct. Meaning you can only destructure structs that don't impl Drop.
> Rust's critical invention was "what if we modeled heap ownership and borrowing with linear types".

Rust did not invent this (and I don’t believe Rust’s creators claim it did), see e.g. “Linear regions are all you need”[1] (ESOP 2006) and in general the work around Cyclone[2] in the 2000s. There was also Mezzo[3], which did very similar things but described them in a different style (effects instead of affine types), and a fair bit of work that went beyond what Rust can currently express (e.g. fractional capabilities). What Rust did is succeed at bringing a conservative subset of this academic work to production—which is not a small deal, mind you; others (including the Cyclone team) tried and failed.

[1] https://link.springer.com/chapter/10.1007/11693024_2, https://www.cs.cornell.edu/people/fluet/research/substruct-r...

[2] https://gallium.inria.fr/~fpottier/slides/fpottier-2007-05-l...

[3] https://protz.github.io/mezzo/

You paint the sponsors in an unnecessarily negative light here.

They want to fund code they will use and that requires updating versions to be doable for like a million not twenty million.

Everyone loses site of the massive sizes of the codebases involved. When your codebase is measured in millions LoC minor breaks can be devastating.

Minor steps are fine and appreciated but "rip off the bandaid" is better left to alternative projects like Rust.

(comment deleted)
bjarne/hsutter and their whole "club" have been (from my admittedly outsider perspective) using the "founding principles" in bad faith in the c++ comittee for a while now, see the strong-arming of safety profiles into the standard while they are in no way workable or anything more than a half-useless solution to anything they claim to solve https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p34... / https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p34... / https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p36...
I haven't followed the contracts discussion particularly closely, but my understanding of the situation is this:

Contracts has the problem that everybody has a slightly different idea of what they want from the feature. What exists today in the draft standard is a messy compromise that has a very broad consensus. However, there are few people who are vehemently against the current compromise and are taking every opportunity to try to upset that compromise.

Now on top of that, there is a separate issue in that the C++ standards committee has started to become too aggressive in adopting new features, and implementers are starting to complain about that. Contracts is one of the new features that is in the camp of the-standard-is-moving-too-quickly, but it's far from the only one and probably not the worst offender, given that there is fairly high demand for contracts. (Constexpr-all-the-things is probably the worst offender from a cost/benefit ratio?)

Currently, the C++26 draft is out to the national bodies for balloting, and the vote in the US national body passed by the thinnest of margins. I haven't heard of the results from other national bodies yet.

Off-topic: oh wow the most of the Appendix part looks Claude verbatim. Not something I'd expect in a paper from Stroustrup.
This seems like great stuff. Some libraries already do this, so why not standardize the behavior (to the extent it can be done)?