C++26: Standard Library Hardening Experiments

(cppstories.com)

56 points | by ibobev 3 hours ago

4 comments

  • steveklabnik 2 hours ago
    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?

    • whateverboat 2 hours ago
      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 proposals which is essentially merge requests to make changes to the C++ draft. 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 (which calls for removal of contracts from the C++ draft before it goes to committee of national bodies), or he probably gets US or Denmark or some NB (not sure which) to vote no on the C++ standard (when it eventually goes to the committee of national bodies with the contracts in it, kind of like throwing baby with the bathwater).

      • steveklabnik 1 hour ago
        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.

        • whateverboat 1 hour ago
          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.

      • Mond_ 37 minutes ago
        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.

    • RicardoLuis0 2 hours ago
      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...
    • bluGill 2 hours ago
      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.

      • maccard 5 minutes ago
        > 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.

    • jcranmer 52 minutes ago
      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.

    • scott_s 2 hours ago
      I have not been following, but some searching lead me to the conclusion that contracts are currently in the draft, but Stroustrup and some others are loudly saying that is a mistake. See: https://wrocpp.github.io/posts/contracts-dispute/
  • Cieric 2 hours ago
    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.
    • superxpro12 2 hours ago
      i know in the embedded space this would be invaluable. compile time contracts, or compile time abstract base class would enable compile time resolution of virtuals. so then i can do compile-time polymorphism and c++ is suddenly really attractive in the sub 64k memory space. Maybe -flto does this idk. But all the pieces are there.
      • fhrow4484 16 minutes ago
        > compile time abstract base class would enable compile time resolution of virtuals. so then i can do compile-time polymorphism

        What's wrong with static polymorphism that have been around for at least 31 years? (1995 per [1]). Also know as CRTP [2] Apart, of course, from ugly verbose compilation errors...

        And now c++23 "deducing `this`" [3,4] modern replacement which is supposed to improve compilation time and remove the verbose errors.

        [1] https://www.artima.com/articles/the-most-important-c-non-boo...

        [2] https://en.cppreference.com/cpp/language/crtp

        [3] https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p08...

        [4] https://devblogs.microsoft.com/cppblog/cpp23-deducing-this/

      • jmalicki 22 minutes ago
        How would this allow compile-time resolution of virtuals that was not possible before?

        Gcc can already do link-time devirtualization in some cases.

      • Cieric 2 hours ago
        Yeah, I heard spark was used on a small component in the nvidia gpu firmware so others seemingly agree. I'm mainly in the user mode driver space so my ideas have been around having a kernel mode driver that (assuming a correctly functioning pc) can't crash and user mode drivers that can't be exploited (at least in the rop chain sense). I'm kind of picking ideas from other languages that I like zig's error handling, ada's contracts, rust's lifetimes (hopefully soon to be replaced with more contracts instead), and things like how you can use "gas" in lean to prove a loops will terminate. I'm mainly building it up with AI right now for experimentation, but I also can't really trust it to be correct either because of using AI. Once I settle on the syntax more and pump out a lot more tests, I'm probably going to rewrite the compiler by hand (hopefully in the custom language itself.)
      • bluGill 2 hours ago
        Contracts are written such that the compiler can diagnose a detected violation if it wants to. However most contracts realistically need whole program analysis to diagnose and no compiler can do that - you want a separate static analysis for that. (this doesn't exist, but there is hope people start writing those)
        • Cieric 2 hours ago
          You sounds like you have more experience than me in this space (specifically contracts). I'm curious if you have any examples right off hand that would need whole program analysis. I need more examples to throw at my toy language that's not just another lock free work stealing queue.
          • bluGill 1 hour ago
            If I have more experience than you that means you have no experience at all. I've never used contracts in anything (not even a toy). I've been following contracts in hopes that they can be the next step in my quality journey, but I have no real world experience myself.

            By whole program analysis I mean you need the entire call tree of a function - stopping only when you can validate that the range of values is constrained to legal values. For some functions this is really simple, while for others the whole flow can be thousands of functions.

          • steveklabnik 1 hour ago
            C++ contracts are not a compile-time construct, they're a runtime construct.

            Take the example from the article. The contract trips at runtime, not at compile time.

            • bluGill 1 hour ago
              The only required enforcement is runtime (even then it is optional). However nothing stops the compiler from detecting a violation at compile and time failing because of an error (or perhaps warning?)

              There is a lot of interest in static analysis enforcing contracts, but this will likely require some additions to the contract specification.

      • rramadass 1 hour ago
        You might want to take a look at Real-time C++: Efficient Object-oriented and Template Microcontroller Programming by Christopher Kormanyos for some ideas.

        Also take a look at David Crocker's Escher Technologies "Escher C Verifier and Escher C++ Verifier" (https://www.eschertech.com/products/ecv.php) and articles on "Verified Design-By-Contract" etc. linked to in my comment chain here - https://news.ycombinator.com/item?id=48544022

  • pama 3 hours ago
    30 years late, but I will take it. Contracts look useful and less messy than exceptions.
    • cenamus 3 hours ago
      They solve completely different problems though
      • tialaramex 2 hours ago
        Suppose your function doodle_widget is supposed to take a Gonzo Widget, but you're worried somebody might call it with a Non-Gonzo Widget and that can't work.

        Traditionally you write code which checks the Widget to see if it's Gonzo and if not you throw an exception. Callers can pick, for this function in particular, whether to handle the Exception, in which case they get that Exception to look at, or they can "bubble it up" to be handled in their caller, and so on all the way to the top of the program where if it bubbles up it's reported and then exits the program.

        With Contracts you write a contract for the function with a pre-condition that the Widget is Gonzo. Your users (programmers who might call doodle_widget) can pick: If they fail a contract the program exits immediately reporting a violation ("quick enforce"), it reports the violation via a global contract handler and then exits ("enforce") or it just reports to the handler but doesn't exit ("observe") or finally, they ignore it entirely ("ignore")

        These just aren't that different. The contract is maybe slightly better because of the enhanced semantic discovery - you could imagine tooling which gives you a yellow squiggly line because your code violates a contract requirement for example, it's definitely not practical to check exception raising that way.

        • bluGill 2 hours ago
          That is one use where either can be used.

          However contracts cover a lot of other cases (and as the other replies point out contracts are probably the wrong answer here - a concept is your right answer allow someone else to write a new/different Gonzo complaint widget in the fiture). A contract can check cases where have the right type, but something is wrong anyway. If you need a sorted list a contract can check that....

          Likewise exception is useful for a lot of things that should not be a contract. Running out of disk space is still a common problem - you do not want a contract that there is enough disk space, this is an error you need to ask how to handle (often the user would free up disk space external to your program and retry a save).

        • Almondsetat 2 hours ago
          >Suppose your function doodle_widget is supposed to take a Gonzo Widget, but you're worried somebody might call it with a Non-Gonzo Widget and that can't work.

          Can't you just use concepts?

          • jandrewrogers 1 hour ago
            Yes, these types of scenarios are commonly handled with C++20 concepts. The main thing contracts do is provide a standardized scaffolding for enforcement.
          • tialaramex 2 hours ago
            No. Bjarne's C++ 20 Concepts are basically duck typing, you can express that you want a type where we can call the "is_gonzo" function but you can't say that you only want values of that type in which it's true.

            Obviously you could re-design the software to follow a Rust-style type-state paradigm, have a NonGonzoWidget and GonzoWidget type which both inherit from Widget and now you can have your function take a GonzoWidget - but that's not what my comparison was about and this technique while possible is less common in C++

            Edited to add: Actually, I should clarify that concepts have an idea called "modelling" and you can model anything you want, but the problem is that the machine doesn't care. So you can have a concept which models strings being about how awesome Donald Trump is, and the compiler won't and can't check that, but now a C++ program with a string matching that concept and the value "Trump is a moron" is an invalid C++ program, still compiles, still probably works, but your concept wasn't "modelled" so the program was not valid for whatever that's worth....

        • jayd16 2 hours ago
          How do you handle I/O type exceptions with contracts?
          • jsmith45 59 minutes ago
            You wouldn't.

            But keep in mind that there are multiple kinds of exceptions.

            Some exceptions, indicate scenarios the caller could reasonably have avoided. This include things like argument bound or null checks. A caller absolutely could avoid these exceptions by doing its own checks. This can be split between checks that the caller really should have done, like not passing null to a function that cannot take null, vs those where baking the relevant knowledge into the caller would be undesirable (perhaps because future versions of the library expect to accept more values).

            There are exceptions that in theory a caller could avoid, but in practice it is impractical, like an exception thrown by a parser of some complex format if the provided input isn't legal. The only good way to avoid such an exception is to have a non-throwing parser that you can check with, but you probably don't want to parse twice. An alternative interface for the parser might be able to totally avoid the exception, returning either succeeded (with result tree) or fail with error message, but that would be a design choice of the implementor, not the caller.

            There can be exceptions that indicate a logic bug in the impleentation (things like throwing if some invariant the implementation is in charge of is violated), but more often this is assertions instead.

            Lastly, you have exceptions that there is no possible way the caller could always avoid. IO exceptions are among these. While you can sometimes do existence, space, or permission checks or similar to reduce the probability of getting certain exceptions, something else could race your app between the check and performing IO, and make them happen anyway.

            The primary target for contracts are exceptions that callers both could and should have avoided, and the exception/assertion case that is trying to verify the implementation is working as expected.

            The other categories of exceptions are more or less totally out of scope.

          • tialaramex 2 hours ago
            You would absolutely be entitled to write a contract which says there are never I/O problems. It could even make sense in some cases, though often not.