CppCon
Sutter argues C++ can eliminate 98% of memory vulnerabilities and 90% of language complexity by adopting an unambiguous second syntax that transpiles directly to standard C++.
AI-assisted summary of Can C++ be 10x Simpler & Safer? - Herb Sutter - CppCon 2022 — original source. Check the original for full context.
Source published:
Key ideas
- Herb Sutter introduces cppfront, an experimental pre-alpha compiler translating an unambiguous second syntax (Cpp2) directly into standard ISO C++20 (Cpp1) without breaking backward compatibility. (12:35)
- The project tests Bjarne Stroustrup's long-standing conjecture that an internal language 10% the size of C++ can achieve 50x safety (eliminating up to 98% of CVE categories) and 10x simplicity. (15:00)
- Prompted by White House executive orders and Commerce Department warnings declaring C and C++ memory-unsafe, Cpp2 statically enforces bounds, lifetime, and initialization safety by default. (40:00)
- An internal audit of Windows security vulnerabilities by Herb Sutter and Joe Bialek revealed that 100% of the examined bounds violations would have been prevented by bounds-checked spans. (55:10)
- Cpp2 introduces unified declarations (`name: type = value`), six explicit parameter modes, compiler-enforced definite initialization before use, and eliminates raw owning pointers and pointer arithmetic. (17:30)
Detailed notes
## Background This keynote address was published on YouTube by the CppCon channel on November 12, 2022. It features Herb Sutter discussing experimental avenues to evolve C++ beyond its traditional incremental 10% three-year improvements to make the language fundamentally simpler, safer, and more toolable.
## TL;DR Herb Sutter presents Cpp2 and its accompanying open-source compiler cppfront, an experimental alternate syntax designed to test Bjarne Stroustrup's conjecture that C++ can be 10x simpler and 50x safer. By compiling down to standard ISO C++20 without breaking backward compatibility, Cpp2 establishes a clean bubble that eliminates legacy syntactical warts, enforces definite initialization, and replaces raw owning pointers and pointer arithmetic with safe defaults. Sutter demonstrates how features like unified declarations, automatic bounds-checking contracts, pattern matching via inspect, and standardized parameter modes dramatically slash accidental complexity and memory CVEs while preserving zero-overhead execution and seamless C++ interoperability.
## Atmosphere & style The presentation carries the electrifying energy of an ambitious, high-stakes keynote delivered to a deeply knowledgeable engineering community. Sutter speaks with passionate conviction, blending candid self-deprecation about his prototype's early limitations with rigorous technical authority. Watching it feels like witnessing an inflection point—marked by earnest audience applause when safety bugs are systematically dismantled, flashes of dry humor regarding historical language pain points, and an inspiring call for community collaboration to revitalize C++ from within.
## Bulletin - [12:35](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=755s) Herb Sutter introduces cppfront, an experimental pre-alpha compiler translating an unambiguous second syntax (Cpp2) directly into standard ISO C++20 (Cpp1) without breaking backward compatibility. - [15:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=900s) The project tests Bjarne Stroustrup's long-standing conjecture that an internal language 10% the size of C++ can achieve 50x safety (eliminating up to 98% of CVE categories) and 10x simplicity. - [40:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2400s) Prompted by White House executive orders and Commerce Department warnings declaring C and C++ memory-unsafe, Cpp2 statically enforces bounds, lifetime, and initialization safety by default. - [55:10](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3310s) An internal audit of Windows security vulnerabilities by Herb Sutter and Joe Bialek revealed that 100% of the examined bounds violations would have been prevented by bounds-checked spans. - [17:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1050s) Cpp2 introduces unified declarations (`name: type = value`), six explicit parameter modes, compiler-enforced definite initialization before use, and eliminates raw owning pointers and pointer arithmetic.
## Key takeaways - [00:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=0s) Standard ISO C++ improves incrementally by roughly 10% every three years because strict 100% syntactic backward compatibility prevents fixing historical defaults and warts. - [10:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=600s) Following the precedent of Bjarne Stroustrup's original Cfront compiler, cppfront bypasses the cost of modifying production compiler forks by compiling Cpp2 into clean modern C++20. - [17:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1050s) Cpp2 provides an unambiguous, context-free grammar with order-independent declarations, left-to-right reading order, and automatic `import std;` module inclusion. - [20:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1200s) Universal Function Call Syntax (UFCS) in Cpp2 allows non-member functions to be called via member dot notation (such as `thing.ssize()`), vastly improving IDE autocompletion and toolability. - [30:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1800s) Cpp1 and Cpp2 code can be mixed seamlessly within the exact same source file, enabling an incremental, non-breaking adoption path comparable to TypeScript over JavaScript. - [40:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2400s) Federal cybersecurity mandates and vulnerability data demand that low-level systems languages eliminate lifetime, initialization, type, and bounds defects. - [46:15](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2775s) Type queries and casts across all types (variants, optionals, anys, and polymorphic pointers) are consolidated into two unified operators: `is` and `as`. - [52:26](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3146s) Pointer arithmetic, raw pointer indexing, and naked `delete` operations are prohibited, directing developers toward bounds-checked spans and arena-allocated smart pointers (`unique.new`). - [01:00:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3600s) Cppfront automatically injects subscript bounds safety assertions (`cpp2::assert_in_bounds`) across all containers exposing `.size()` without requiring standard container wrappers. - [01:04:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3885s) Contracts in Cpp2 are segregated into distinct global groups (`bounds`, `type`, `null`), allowing critical memory checks to remain active in production while toggling heavy business logic. - [01:07:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4065s) Pointers in Cpp2 are non-null by default, and the identifier `NULL` is banned outright from the language. - [01:16:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4590s) Definite first-use analysis tracks branch flow across functions to ensure local variables are initialized before access without paying the cost of zero-initialization dummy values. - [01:25:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5100s) Cpp2 formalizes six clear parameter passing intents (`in`, `copy`, `inout`, `move`, `forward`, and `out`), eliminating manual reference choice cognitive overhead. - [01:22:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4950s) Multiple named return values lower directly into synthesized structs that remain completely ABI-compatible with C++17 structured bindings. - [01:50:47](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6647s) The distinct name 'Cpp2' serves as an educational lever to prevent instructors from introducing obsolete C idioms and unsafe defaults to new programmers.
## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=0s) Doubling Down on C++: An Experimental Vision for 10x Simplicity and Safety
Herb Sutter opens by acknowledging that while his title sounds provocative, this is actually a talk he has been delivering in pieces for seven years. He sets an affectionate tone for the conference, noting that attendees gather at CppCon because they love C++ and view it as the best language available for building what they need. However, the language faces severe challenges, prompting an industry-wide wave of major C++ evolutionary and revolutionary experiments. Sutter emphasizes upfront that this project is his own personal experiment: he does not speak for Microsoft, nor does he speak for the ISO C++ Standards Committee. Because it is an experiment, failure remains the default outcome, but any successes are intended to be fed directly into future ISO C++ proposals.
Addressing the global community of seven million C++ developers, Sutter urges everyone to push the boundaries of C++ rather than jumping ship to alternate ecosystems. While acknowledging that greenfield language projects—and established languages like Rust—offer valuable lessons in building brand-new module systems and ecosystems, he focuses on the opposite end of the spectrum: refreshing C++ itself from within. His goal is to retain C++’s existing package managers, modules, guidance, and complete compatibility, while modernizing the baseline defaults. He grounds this ambition in measurable targets:
> “To me, safer, 50x safer means 98% fewer CVEs, vulnerability exploits, and bugs in those categories. 10x simpler means I can get rid of 90% of the paper of the books I teach today.”
Reflecting on a slide he first presented at CppCon 2018, Sutter argues that the heart of C++ has always been zero-overhead abstraction—knowing where objects live and how long operations take—paired with friction-free interoperability. He directly challenges the cultural masochism common in the community, pushing back against the idea that “if it doesn't hurt a little, it's not really C++.” Security vulnerabilities, memory unsafety, and complex syntax are not fundamental to C++’s identity. The reason ISO C++ only manages incremental ~10% improvements every three-year cycle, Sutter argues, is its strict adherence to 100% syntactic backward compatibility.
[04:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=285s) The "Judo Move": Applying Zero-Overhead to Backward Source Compatibility
To break through the limitation of incremental progress, Sutter proposes an intellectual and architectural maneuver he calls a "judo move": extending the language’s defining zero-overhead philosophy directly to backward source compatibility itself.
> “What if we applied that to backward source compatibility. That means we always have backwards 100% SFINAE macros, give us all of it. Backward source compatibility available. But, we only pay for it if we use it, is that possible?”
Sutter asks the audience to entertain a thought experiment supported by an active implementation: introducing an alternate, complete second syntax for C++. If this secondary syntax is fully expressive, self-contained, and unambiguous, it creates an isolated bubble of entirely new code. Because no legacy code has ever been written in this new syntax, the committee and developers would face exactly zero backward source compatibility constraints within that bubble. Designers can clean up historical warts, increase safety, simplify rules, and enhance tooling without breaking a single existing line of code. He compares this potential shift to the arrival of C++11, which introduced smart pointers and trailing return types; it felt like a brand-new language while still undeniably remaining C++.
```mermaid flowchart TD accTitle: The Zero-Overhead Source Compatibility Model accDescr: Diagram illustrating how legacy syntax retains full compatibility while a second syntax provides clean evolution without legacy constraints.
subgraph Legacy["Legacy Syntax Domain (cpp1)"] L1["100% Source Compatibility"] L2["Macros, SFINAE, Legacy Idioms"] L3["Existing C++ Ecosystem"] end
subgraph Alternate["Clean Bubble Domain (cpp2)"] A1["Zero Legacy Constraints"] A2["Modern Safe Defaults"] A3["Reduced Concept Count"] end
Legacy -->|"Friction-Free Interop"| Alternate Alternate -->|"Compiles to / Interops with"| Legacy ```
- **Zero-overhead backward compatibility**: Full access to historical features (macros, SFINAE) remains completely available, but code in the new syntax does not pay the architectural tax unless it uses them. - **Unconstrained evolution**: An unwritten syntax has no backward compatibility shackles, allowing a 30-year evolution runway for C++.
[06:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=405s) Refactoring the Concept Count and the Paper Trail of Proposals
Sutter details how this effort began in 2015, when he spent a year of his spare time investigating whether C++ could be systematically refactored. Rather than starting from a blank sheet of paper, he examined existing C++ constructs to identify disparate features that could be unified into a smaller number of composable, general-purpose mechanisms without dumbing down the language. The primary objective was reducing the overall "concept count"—a metric that encompasses not just the raw keyword count, but also the catalog of irregularities, special cases, and surprising interactions between disparate features that force developers into tedious rote learning.
Since 2016, Sutter has quietly validated parts of this unified architecture by isolating individual features and submitting them to the ISO committee as standalone proposals written in traditional C++ syntax. This allowed him to subject each design to intense committee scrutiny, discover bugs, and verify whether both the committee and the broader community actually wanted the problem solved.
Nearly every conference talk and ISO paper Sutter delivered over the previous six years originated directly from this overarching project. The single exception to his rule of always building a prototype first was the three-way comparison "spaceship operator" (`<=>`). Because the committee unexpectedly restarted discussions on comparisons right after C++17 shipped, Sutter took the spaceship design out of his back pocket and submitted it as an opportunistic paper without a working prototype. That lack of a prototype resulted in two major design bugs, which were subsequently fixed with the help of committee colleagues. Sutter halts his talk to ask the contributors pictured on his slide to stand, prompting a warm round of applause across the auditorium.
[10:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=600s) What Would Bjarne Do? Learning from Cfront
Herb Sutter reflects on his simplification efforts, pointing out that the spaceship operator (`<=>`) was the first piece of his simplification work to actually make it into the ISO C++ standard. He brags on it slightly because, while it added roughly a dozen pages of core language wording, applying it to the standard library eliminated even more pages, making the standard as a whole smaller. This serves as concrete proof that language simplification really can work.
However, a major obstacle has been the cost of prototyping. Prototyping experimental language features directly inside a production-grade compiler like Clang or Visual Studio, or via custom mini-libraries, is prohibitively slow and expensive. Faced with this bottleneck, Sutter asks himself: "What would Bjarne do?" Not modern Bjarne Stroustrup, he jokes, but the Bjarne of forty years ago (referencing a cardboard cutout slide). Forty years ago, Stroustrup solved the adoption and prototyping problem by writing Cfront—a compiler that translated C++ (initially "C with Classes") directly into C.
```mermaid flowchart LR accTitle: Cfront to cppfront Comparison accDescr: Historical analogy showing how Cfront translated early C++ to C, and how cppfront translates syntax 2 to standard C++20. subgraph Historic["1980s: Cfront Model"] direction LR A["C with Classes / C++"] -->|"Cfront"| B["C Code"] B -->|"C Compiler"| C["Every platform with a C compiler"] end subgraph Modern["Herb Sutter's Experiment: cppfront"] direction LR D["Syntax 2 (cpp2)"] -->|"cppfront"| E["Standard C++ (cpp)"] E -->|"C++20 Compiler"| F["Every platform with a C++20 compiler"] end ```
Stroustrup succeeded because he nailed a fifteen-second elevator pitch: C is powerful, fast, and close to the machine, but it lacks abstraction, so C++ would supply that abstraction while compiling down to C. That architectural choice gave C++ three decisive advantages: - It was immediately portable to any platform that had a C compiler. - It retained 100% interoperability with existing C libraries, linkers, debuggers, and optimizers. - Even if debuggers showed mangled symbol names for overloaded functions, the existing tooling still worked seamlessly.
Sutter emphasizes that without Cfront, modern C++ would not exist. He poses the core question of his experiment: “Could we do that again?”
---
[12:35](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=755s) Introducing `cppfront`: An Experimental C++20-Targeting Compiler
To test whether the Cfront approach could rejuvenate modern C++, Sutter created an open-source project called `cppfront` (hosted under his GitHub account, `hsutter`). It is a source-to-source compiler that translates an experimental syntax—which he calls "Syntax 2" or "cpp2"—into standard modern C++ ("Syntax 1" or "cpp").
```mermaid flowchart TD accTitle: cppfront Compilation Pipeline accDescr: Compilation pipeline showing how cpp2 files are parsed by cppfront into cpp files and then built with standard compilers. subgraph Authoring["Source Files"] S1["Pure.cpp2 file"] S2["Interleaved.cpp2 +.cpp file"] end subgraph Transformation["cppfront Tool"] CF["cppfront executable<br>(Handwritten manual parser, zero dependencies)"] end subgraph NativeToolchain["Target Compiler (C++20 Mode)"] CPP["Generated.cpp file"] COMP["GCC / Clang / MSVC"] BIN["Target Binary"] end
S1 --> CF S2 --> CF CF --> CPP CPP --> COMP COMP --> BIN ```
His goals mirror Stroustrup’s original ambitions: embrace C++ rather than fleeing to another language, but directly address the reality that C++ needs to become safer, simpler, and more toolable. Just as Cfront worked wherever a C compiler existed, `cppfront` works wherever an ISO C++20 compiler is available.
Sutter is careful to set expectations: this is an individual research project and is "hilariously incomplete." At the time of the talk, it does not yet support classes (which he plans to implement over the coming winter), though he notes that one can achieve a surprising amount of language simplification focusing purely on functions. His broader goal is to spark a conversation within the C++ community about what is possible for the language's evolution before developers abandon it for alternative languages.
The build process for `cppfront` is deliberately minimal: - It requires no external build systems—no CMake, no Bazel. - It contains no third-party libraries, no parser generators (no Yacc, no Bison). - The codebase was written from scratch starting from an empty editor using only the standard library and a custom, handwritten parser. - The entire build instruction for each major platform is a single command-line invocation compiling with a standard C++20 compiler.
---
[15:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=900s) Core Principles: Conceptual Integrity and Bjarne's 10% Conjecture
Sutter explains that the foundation of this work rests on principles he has reiterated in the opening sections of all his ISO committee papers over the prior seven years. Quoting Fred Brooks from *The Mythical Man-Month*, he notes that conceptual integrity is the single most critical attribute of system design: systems should hang together as if they were the product of a single mind.
For C++, this means refactoring the language into fewer, composable, orthogonal, and general features. Sutter connects this directly to Stroustrup's long-standing conjecture: “Bjarne has conjectured publicly for decades that within C++ there is a language 10% the size, struggling to get out.” Sutter’s explicit ambition is to see if he can finally prove Stroustrup right.
To keep the project grounded, he establishes strict constraints ("stakes in the ground"): - **No drive-by improvements:** Sutter eliminated several personal language preferences that failed to carry their weight or solve concrete, existing problems. - **Laser focus on safety, simplicity, and toolability:** Every addition must measurably improve at least one of these three axes. - **Zero-overhead and developer control:** The language must strictly retain fundamental C++ values—zero abstraction penalty and the ability to drop down and take low-level control when needed.
Sutter pleads with the audience not to misunderstand the project's intent: > “Please don't make the mistake of saying, ‘Oh, yeah, Herb gave a talk and he says he wants to make C++ prettier.’ That's not the point. That would not be interesting. It's fixing the semantics, changing defaults, removing special cases. That's the meat of it. The syntax is just to get us a bubble of new code.”
The syntax acts merely as the gateway into an evolutionary space where defaults can be safely fixed without breaking backward compatibility for billions of lines of existing code.
---
[17:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1050s) Syntax 2: Unified Left-to-Right Declarations and Modules by Default
Turning to the new syntax itself, Sutter establishes baseline requirements that any modern programming language should satisfy: - Context-free parsing - Order-independent declarations - Clean left-to-right syntax, quoting Niklaus Wirth's philosophy that declarations should read left to right "as nature intended" - Complementary syntax between declarations, usages, and expressions
Existing C++ code—from `class Shape` syntax dating back to 1980 to the trailing-return syntax `auto f(int i) -> std::string` introduced in C++11—is locked in place. Any breaking changes inside those braces would break the world.
To solve this, Syntax 2 unifies every single declaration under a consistent pattern: `name: type = value`.
| Declaration Type | Syntax 2 (cpp2) Formulation | Meaning / Notes | |:--- |:--- |:--- | | **Type** | `Shape: type = {... }` | Defines `Shape` as a new type with a body | | **Function** | `f: (i: int) -> std::string = {... }` | Defines `f` as a function taking `int`, returning `std::string` | | **Variable** | `vec: std::vector<std::string> = (...)` | Defines a vector of strings with initial values | | **Deduction (CTAD)** | `view: std::span = vec` | Deduces `std::span<std::string>` automatically via C++ semantics | | **Entry Point** | `main: () -> int = {... }` | Clean main function signature without extraneous boilerplate |
Sutter demonstrates this by presenting a complete, standalone program written in Syntax 2 on a single slide. The program compiles and executes without containing a single `#include` or `import` directive. In a pure Syntax 2 translation unit, the C++23 statement `import std;` is automatically injected by default. Developers no longer need to remember which specific standard library header to include.
[20:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1200s) Modules, Defaults, and Universal Function Call Syntax
Herb Sutter addresses concerns about build performance when adopting modern features like C++20 modules and bringing in the standard library. Some developers worry about the build speed of pulling in regex, parallelism, and every other standard header, but Sutter argues that these worries are misplaced with modular designs. In current implementations, writing `import std;` compiles faster than an old-fashioned `#include <iostream>`, making the entire standard library quicker to bring in than a trivial "Hello World" build. In his experimental syntax (Cpp2), `import std;` is simply made the default, though he notes that if the experiment shows otherwise, it can be adjusted.
```mermaid flowchart TD accTitle: Unified Function and Lambda Syntax in Cpp2 accDescr: Shows how single-expression functions, full functions, and lambdas share the identical declaration grammar. subgraph Grammar["One Syntax for Functions"] Full["Full Function:<br/>name: (params) -> return = { body }"] Expr["Single-Expression Function:<br/>name: (params) = expr<br/>(omits braces and return)"] Lambda["Lambda Function:<br/>:(params) = expr<br/>(omits name at expression scope)"] end Full -->|"omit boilerplate"| Expr Expr -->|"omit name"| Lambda ```
He then walks through key language features implemented in Cpp2. Parameter passing directly realizes the design from his earlier paper (P0708), using explicit passing intents like `in` and `out` while eliminating traditional raw references entirely from the surface syntax. Underscores (`_`) function as wildcards to express implicit template parameters cleanly. Crucially, Cpp2 adheres to the core philosophy that there should be only one unified syntax for everything, enriched by good defaults rather than competing duplicate constructs: - **Brace and Return Elision:** For single-expression or single-statement functions returning a value, curly braces and explicit `return` statements can be omitted entirely without introducing a separate grammar. - **Unified Lambda Grammar:** Because there is only one function declaration syntax, lambdas do not have a dedicated, distinct syntax; a lambda is simply an unnamed function written at expression scope, starting with `:(` rather than requiring specialized capture-bracket ceremonies. - **Order Independence:** Functions can call each other freely before they are formally declared or defined—eliminating the need for manual forward declarations, which drew enthusiastic applause from the audience.
Moving to generated code, Sutter shows a screenshot from CppFront rather than running a live demo for that specific slide to conserve time. The output illustrates that `[[nodiscard]]` is emitted by default on functions. He asks the audience how many wish `[[nodiscard]]` were the default in standard C++, drawing widespread agreement. Sutter quips, “When you write the compiler, you get to make choices,” highlighting that he wrote this compiler first and foremost for himself so that he could write C++ the way he wants.
```mermaid flowchart LR accTitle: Universal Function Call Syntax Fallback accDescr: How UFCS resolves member dot syntax to non-member functions like std::ssize. Call["thing.ssize()"] --> Check{"Member.ssize()<br/>exists?"} Check -->|"Yes"| MemCall["Call thing.ssize()"] Check -->|"No"| NonMemCall["Fallback to std::ssize(thing)"] ```
The emitted code also seamlessly handles Class Template Argument Deduction (CTAD) because the front-end directly emits standard C++ syntax (referred to as "syntax 1") from Cpp2 ("syntax 2"). Furthermore, Sutter highlights calling `.ssize()` on a container. When Bjarne Stroustrup failed to persuade the ISO committee to change all `.size()` members to return signed integers or to add `.ssize()` as a member across all containers, the committee instead provided the non-member `std::ssize` function. Because Cpp2 implements Universal Function Call Syntax (UFCS), invoking `thing.ssize()` simply falls back to the non-member overload automatically. Sutter reflects on how rapidly this wins developers over: “I was surprised as I was writing my dozens of examples and tests, I was surprised how quickly I just went to `.ssize()` and never looked back.”
[25:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1500s) Readable Generated Code and Pre-Alpha Compiler Demos
A central guarantee of Sutter's experiment is preserving developer investment. He insists that if the Cpp2 experiment ultimately fails—which is the statistical default for language experiments—developers must never feel trapped. If a project needs to abandon Cpp2, it can run the tool with the `-clean-cpp1` flag to strip the generated `#line` directives and keep the clean, human-readable ISO C++ output.
To achieve complete order independence within the generated code, CppFront automatically inspects the Cpp2 definitions and emits forward declarations in the exact relative locations needed among any existing C++1 code, followed by the actual Cpp2 definitions down below where they can mutually reference one another.
```mermaid flowchart TD accTitle: Order Independence Generation Strategy accDescr: Illustrates how CppFront splits definitions into forward declarations and implementations to guarantee order independence. Cpp2Src["Cpp2 Code (unordered)"] --> FrontEnd["CppFront Lowering"] FrontEnd --> FwdDecls["1. Emit Forward Declarations<br/>(interspersed with legacy C++1 code)"] FrontEnd --> Defs["2. Emit Function Definitions<br/>(all Cpp2 implementations can see each other)"] FwdDecls --> Output["Clean Standard C++1 Source"] Defs --> Output ```
Sutter exhibits a deliberately contrived straw-man test case featuring variables named `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, `j`, `k`, and `l` to prove how cleanly the transpiler preserves code structure and formatting: - Because the declaration syntax follows use, operators such as pointer dereferences become postfix in Cpp2, which removes the need for many nested parentheses. The compiler rewrites expressions into conventional prefix syntax (such as turning a dereference expression into `*f`) and correctly places parentheses and postfix increments (`++`). - Even though expressions and UFCS calls get moved or restructured, the emitted output retains the author's original indentation, indentation style, and exact comment locations. - He refutes the common assumption that transpiled or generated code is unavoidably messy: “The ugliness of generated code is directly proportional to the impedance mismatch. If your source is still C++, then you can make it beautiful.”
Sutter then transitions to live demos of his "pre-alpha" tool across real toolchains. He displays a mixed source file featuring traditional includes (`#include <iostream>`, `#include <string>`) and a standard `auto main()` function living alongside Cpp2 functions. Asking the audience to vote by applause on whether to test the compiler under Clang, Microsoft Visual C++ (MSVC), or GCC, GCC wins the loudest applause. Sutter shifts to his Ubuntu environment running inside the Windows Subsystem for Linux (WSL), remarking, “Thank you, Windows, for having actual Linux.” However, the terminal fails to register any keystrokes. After attempting an Ubuntu restart and finding it completely unresponsive, he jokes about the inevitable live-demo curse—“Wow, this has never happened before”—and pivots toward the audience's second-place compiler choice.
[30:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1800s) Mixing Cpp1 and Cpp2: The Tooling and Code Generation Pipeline
Herb Sutter begins a live demonstration of `cppfront` parsing `demo.cpp2`. After battling a small OS typing lag that he jokingly notes has never happened in months of testing, he runs the compiler. The tool immediately flags an error, which Sutter explains is completely intentional for the demonstration. The initial translation step passes its safety checks over the mixed syntax, but the downstream C++ compiler halts on an error traced directly back to the original `.cpp2` file: `'string' is not a member of 'std'`. Sutter explains that he deliberately wrote `strim` instead of `string` to demonstrate how error reporting functions across compiler boundaries:
> "So all the cool error messages we get today still work."
Fixing the typo allows the program to compile and link. Sutter remarks on the slight delay during the initial executable launch—attributing it to an unavoidable Windows virus scan on a fresh binary—before it runs swiftly on the second attempt. Inspecting the generated C++ source file reveals how `cppfront` bridges syntactic eras. At the top sits a generated header supplying necessary utility templates, such as parameter-passing conventions. Next, `cppfront` emits any traditional C++ (Cpp1) code exactly in sequence. Crucially, Cpp1 relies strictly on declaration order, so whenever `cppfront` encounters a definition in the new Cpp2 syntax, it hovers forward declarations at that precise location so earlier Cpp1 functions like `main` can see them. Finally, the Cpp2 implementations are emitted with proper braces and signatures appended at the bottom of the generated file. This mechanism allows developers to seamlessly interleave both syntaxes function-by-function within the very same source file.
```mermaid flowchart TD accTitle: Cppfront Compilation and Code Generation Pipeline accDescr: Flow diagram showing how cppfront parses mixed Cpp1 and Cpp2 source and produces standard Cpp1 output.
subgraph Input ["Source Input"] SRC["demo.cpp2 (Mixed Syntax)"] end
subgraph Front ["cppfront Lowering"] PARSE["Parse Mixed Syntax"] FWD["Emit Forward Declarations (for Cpp2)"] CPP1["Emit Cpp1 Blocks In-Order"] CPP2["Emit Lowered Cpp2 Bodies"] end
subgraph Output ["Target Artifacts"] GEN["Generated.cpp File"] COMP["Standard C++ Compiler (GCC / Clang / MSVC)"] end
SRC --> PARSE PARSE --> FWD PARSE --> CPP1 PARSE --> CPP2 FWD --> GEN CPP1 --> GEN CPP2 --> GEN GEN --> COMP ```
[32:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1965s) Pure Cpp2 Files and Named Memory Arenas
Sutter transitions to showing what happens when using the `-pure` compiler switch to enforce a modern-only Cpp2 file. Invoking `-pure` on a file containing legacy directives causes `cppfront` to issue an immediate diagnostic prohibiting the preprocessor altogether:
> "First thing it says is, no, no, no, CPP2, you don't get no preprocessor, you don't need no preprocessor."
Instead of `#include`, developers are instructed to use modern C++20 module semantics (`import std;`). Sutter highlights an underlying design principle: the compiler should enforce modern best practices by default, mirroring what educators already teach rather than perpetuating legacy baggage. Demonstrating this clean syntax, he rewrites `main` into Cpp2 form (`main: () = {... }`), moves it arbitrarily to the top of the file to illustrate complete order independence, and removes all manual includes because the standard library is implicitly accessible.
Moving to memory management, Sutter demonstrates heap allocation. While acknowledging that allocating a local string on the free store is bad practice, he uses it to show how dynamic memory operates without legacy raw pointers. In Cpp2, allocation occurs entirely through named memory arenas, which are objects exposing a templated `.new()` member. The runtime supplies two standard arenas out of the box: - `unique.new()` (which returns a `std::unique_ptr`) - `shared.new()` (which returns a `std::shared_ptr`)
If a developer writes an unqualified heap allocation expression without naming an arena, the compiler defaults to invoking `unique.new()`. Consequently, allocating dynamic memory creates a `std::unique_ptr<std::string>` automatically, cementing type-safe and memory-safe semantics by making `unique_ptr` the default pointer type.
[35:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2100s) UFCS, Toolability, and the Adoption Ramp
Extending the design to older APIs, Sutter demonstrates how Cpp2 interfaces with the C standard library. He shows a snippet opening a file and using `fprintf` alongside a C++ string's `.c_str()` to write the name of his dog, Lily—an Italian Greyhound—to a file named `dog`. When examining the code, he prompts the audience to catch a subtle detail: `fprintf` is being invoked directly on the file pointer using member-call syntax (`f.fprintf(...)`).
Sutter insists that Uniform Function Call Syntax (UFCS) is far more than convenient syntactic sugar:
> "It's about being more toolable, because if you call using the non-member function call syntax, IntelliSense can't help you."
Starting an expression with an in-scope object followed by a dot allows autocomplete and IntelliSense engines to discover every valid operation for that type. Blank lines and prefix functions provide no contextual anchors for developer tooling.
Reflecting on language evolution, Sutter connects this architecture to the philosophy of "don't pay for what you don't use," applying it directly to backward compatibility. He compares this gradual adoption ramp to the historic successes of Bjarne Stroustrup's original C++ design and Anders Hejlsberg's TypeScript: - **Bjarne Stroustrup's C to C++ transition:** Developers could take any `.c` file, rename it to `.cpp`, retain backwards compatibility, and introduce a single C++ class to gain immediate encapsulation benefits. - **TypeScript's JavaScript transition:** Renaming `.js` to `.ts` lets developers introduce type annotations incrementally on a single line. - **Cppfront's Cpp1 to Cpp2 transition:** Renaming `.cpp` to `.cpp2` retains 100% source compatibility with existing SFINAE tricks and preprocessor macros, completely bypassing the catastrophic breaking migration seen between Python 2 and Python 3.
```mermaid flowchart LR accTitle: Incremental Adoption Models Compared accDescr: Visual comparison showing how C++, TypeScript, and Cpp2 all share a file-renaming adoption model.
subgraph Legacy ["Legacy Baseline"] C[".c File"] JS[".js File"] CPP[".cpp File"] end
subgraph Modern ["Strict Supersets / Dialects"] CPPOUT[".cpp (Bjarne's C++)"] TSOUT[".ts (TypeScript)"] CPP2OUT[".cpp2 (Pure or Mixed)"] end
C -->|"Rename & add C++ feature"| CPPOUT JS -->|"Rename & add type annotation"| TSOUT CPP -->|"Rename & add Cpp2 syntax"| CPP2OUT ```
[38:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2280s) Targeting Safety: The Persistent "Hits" of Vulnerabilities
Sutter underscores that working entirely within a pure Cpp2 source file offers the prospect of writing in a dialect that is an order of magnitude simpler, safer, and safe by construction, while preserving seamless interoperability with legacy C++ libraries via imports. He expresses his pedagogical motivation:
> "And I can stop teaching 90% of what I personally have been teaching people for the last quarter century of my life. Because I want to teach people how to program, not how to encant a C++ detail."
Directing attention to software security, Sutter establishes his primary targets: type safety, bounds safety, lifetime safety, and initialization safety. Crediting Dave Abrahams for pointing him toward recent data, he references the MITRE 2022 CWE Top 25 Most Dangerous Software Weaknesses list. Sutter highlights that industry vulnerabilities remain dominated by the same familiar flaws: out-of-bounds writes, out-of-bounds reads, use-after-free conditions, null pointer dereferences, and integer overflows. These issues map directly onto gaps in bounds, lifetime, initialization, and type discipline that modern language evolution must eliminate by default.
[40:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2400s) The Safety Imperative: Executive Orders and Government Guidance
Herb Sutter steps away from purely theoretical discussions of vulnerability lists to focus on what programming languages can realistically solve. Looking at industry rankings of the top 13 software vulnerabilities, once you set aside issues outside a compiler’s reach—such as SQL injection or failure to sanitize input data—five of the top 13 remain squarely within the domain of language design. Year after year, the culprits remain the same four pillars: lifetime safety, initialization safety, type safety, and bounds safety. Integer overflow primarily matters in practice because overflowing integers become out-of-bounds indices, making it fundamentally a bounds safety problem.
Turning off his slides to speak candidly with the audience, Sutter addresses the dramatic shift in political and regulatory scrutiny surrounding memory safety since early 2021. He asks how many attendees, particularly those at US-based companies, have had their daily work altered by the United States executive order on cybersecurity. As hands go up across the room, Sutter recounts the catalyst: on May 8, 2021, President Joe Biden issued an executive order following a barrage of high-profile cyberattacks and ransomware incidents that shut down hospitals, crippled election infrastructure, and took critical oil pipelines offline. Cybersecurity ceased to be a niche engineering concern and became an urgent matter of state.
```mermaid flowchart TD accTitle: Government Response to Memory Unsafe Languages accDescr: Flow showing the escalation from major cyber incidents to government directives advising against C and C++ usage. subgraph Incidents["Catalysts"] A["Ransomware & Infrastructure Attacks<br/>(Hospitals, Pipelines, Elections)"] end subgraph Mandate["Executive Action"] B["May 2021: Executive Order on Cybersecurity"] C["60-Day Mandate to Dept. of Commerce & NIST"] end subgraph Guidance["Official Policy Shift"] D["July 2021 Guidance:<br/>'C and C++ are not memory safe'"] E["Recommendation:<br/>'Where possible, do not use memory unsafe languages'"] F["Active Funding to Rewrite<br/>Low-Level Infrastructure in Other Languages"] end A --> B B --> C C --> D D --> E E --> F ```
The executive order tasked the Department of Commerce and NIST with issuing recommendations within 60 days on how to secure software supply chains. By July 2021, the Department of Commerce released its official guidance. Sutter stresses the severity of their specific wording, highlighting two direct statements:
> “Some programming languages, such as C and C++, are not memory safe.”
Two sentences later, the guidance explicitly recommended:
> “Where possible, do not use memory unsafe languages.”
Sutter emphasizes that this is the first time a major government has formally advised industry against using C and C++, effectively translating to an edict to avoid them wherever possible. Governments are now actively backing that guidance with public funding to rewrite critical, low-level infrastructure in alternative languages. Sutter warns the audience against the complacency that has lingered since the 1990s and 2000s, where the community assumed that adding smart pointers and static analysis rules would be enough to skate by:
> “Call me paranoid, but when a government department starts telling you to do work and move to other languages, we should start to listen.”
- The May 8, 2021 US Executive Order on Cybersecurity responded directly to catastrophic ransomware disruptions, such as attacks on election systems, healthcare facilities, and energy pipelines. - The resulting Department of Commerce guidance from July 2021 explicitly singled out C and C++ as memory-unsafe and advised migrating away from unsafe languages where possible. - Software vulnerabilities are an active threat across all domains, especially internet-connected appliances and embedded systems that rarely receive security patches.
---
[44:31](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2671s) CPP2's Approach: Enforcing Best Practices by Default
Turning back to the mechanics of C++, Sutter frames the design philosophy of CPP2 (and the prototype compiler cppfront) around proactive protection. The guiding principle is static enforcement by default and safety by construction. Where dynamic checks are unavoidable, they must remain completely transparent and adhere to C++'s foundational "pay-for-what-you-use" model.
To illustrate safety by construction, Sutter references the earlier syntax demonstration where writing `s:= new string` automatically yields a `std::unique_ptr` rather than a raw pointer, making it structurally impossible to leak memory. Rather than inventing brand-new paradigms, cppfront enforces the rules already established in the C++ Core Guidelines. When code violates a guideline, the compiler issues diagnostics that steer the programmer directly toward modern Standard C++ alternatives. For example, if a developer attempts to declare a raw C-style `union`, cppfront rejects it with the explicit error message: `"don't use union, use std::variant instead."` By transforming existing community teachings and guidelines into hard defaults, CPP2 aims to deliver genuine safety while remaining unmistakably C++.
- Safety by construction ensures that dangerous constructs, like raw owning pointers from `new`, are transformed into safe abstractions like `std::unique_ptr` at the syntax level. - Compiler errors in cppfront are modeled after established C++ Core Guidelines, actively teaching modern idioms rather than silently permitting unsafe legacy practices. - Dynamic checks remain strictly visible and opt-in, preserving zero-overhead principles.
---
[46:15](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2775s) Unifying Type Safety and Generic Code with `is` and `as`
Sutter transitions to type safety by reviewing the C++ Core Guidelines type profile. In current C++, querying and casting types requires an array of disparate mechanisms: `dynamic_cast`, `static_cast`, `std::holds_alternative`, `std::get_if`, `std::any_cast`, and custom pointer checks. Revisiting his CppCon 2021 presentation on pattern matching, Sutter demonstrates how CPP2 unifies all type queries under the single keyword `is`, and all type casts under the single keyword `as`.
```mermaid flowchart LR accTitle: Unification of Type Queries and Casts in CPP2 accDescr: Divergent legacy C++ type query and cast spellings consolidated into the unified is and as keywords in CPP2. subgraph Legacy["Standard C++ (Divergent)"] direction TB Q1["std::holds_alternative<T>"] Q2["dynamic_cast<T*>!= nullptr"] Q3["typeid(x) == typeid(T)"] C1["std::get<T> / any_cast<T>"] C2["static_cast<T> / dynamic_cast<T&>"] C3["reinterpret_cast<T>"] end subgraph CPP2["CPP2 Unified Syntax"] direction TB UQ["x is T<br/>(Universal Type Query)"] UC["x as T<br/>(Universal Type Cast)"] end Q1 --> UQ Q2 --> UQ Q3 --> UQ C1 --> UC C2 --> UC C3 --> UC ```
This unification is essential for generic programming. Because disparate types in current C++ require wildly divergent syntaxes to inspect or extract their values, writing generic functions that operate seamlessly over built-ins, standard vocabulary types, and user types is exceedingly difficult. Sutter reminds the audience of the "big dragon" graphic from his 2021 talk, which emphasized that divergent syntaxes destroy genericity.
To demonstrate, Sutter walks through a live generic test function written in CPP2 that uses an `inspect` expression:
```cpp test: (x) -> void = { std::cout << typeid(x).name() << ": "; std::cout << inspect x -> std::string { is int = std::to_string(x as int); is std::string = x as std::string; is _ = "not an int or a string"; } << "\n"; } ```
Although full pattern matching with destructuring is not yet implemented in cppfront, this basic `inspect` syntax is fully functional today. Sutter shows that the single generic function can be invoked on diverse arguments: 1. A raw literal double (`3.14`), which matches the wildcard `_` and prints `"not an int or a string"`. 2. A `std::variant<int, double>` initialized to hold a `double`, which prints `"not an int or a string"`. 3. A `std::any` initialized with the string `"xyzzy"`, which matches `std::string` and prints `"xyzzy"`. 4. A `std::optional<int>` that is initially empty, which fails the `is int` check and falls through to `"not an int or a string"`.
When an `int` value is subsequently assigned to each of those container variables, re-running `test` on the variant, the any, and the optional cleanly inspects each one, identifies that it now holds an integer via `is int`, and converts it using `x as int`. Sutter highlights that all of this relies on existing Standard C++ dynamic typing facilities, but harmonized under a clean, unified syntax that makes generic code straightforward to write and read.
- CPP2 consolidates divergent cast syntaxes (`static_cast`, `dynamic_cast`, `any_cast`, `std::get`) into `as`, and type queries into `is`. - The `inspect` expression allows clean, functional-style matching against types, returning values directly from match arms. - Universal type querying enables a single template/generic function to inspect built-ins, `std::variant`, `std::any`, and `std::optional` without specialized boilerplate.
[50:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3000s) Lowering Pattern Matching and Rejecting Unions
Herb Sutter runs into unexpected technical friction when his Ubuntu WSL window quietly crashes and refuses to reopen, forcing him to abandon his planned GCC demonstration for the moment and joke that an unexpected update must have caused Ubuntu to give up. Moving forward on Windows, he invokes the compiler with `cppfront -p` (pure mode) so the code compiles in a standalone environment without importing or including standard headers. Inspecting the generated C++1 code, Herb highlights how Cpp2 dynamic typing lowers directly to standard library mechanisms, with `as` becoming a call to `cpp2::as`. When inspecting a generic function, the high-level `inspect` pattern match lowers into an immediately invoked lambda expression (IIFE). Pointing to the tiny horizontal scroll bar on screen, Herb presses Alt-Z to wrap the lines and reveals a massive, sprawling cascade of nested `if constexpr` branches generated under the hood. He emphasizes that while the generated C++1 plumbing is complex, the author only needs to interact with the clean, high-level Cpp2 syntax. Pivoting back to type safety, Herb tests what happens when a developer attempts to declare a raw C-style `union`: the compiler immediately halts with an explicit error urging the developer to use `std::variant` instead.
```mermaid flowchart TD accTitle: Cpp2 Lowering and Diagnostics Pipeline accDescr: High-level Cpp2 constructs lowering into verbose C++1 code or triggering modern safety diagnostics.
subgraph Input["Cpp2 Source Code"] A["inspect (pattern match)"] B["union declaration"] C["first++ (pointer math)"] end
subgraph CppFront["CppFront Processing"] D["Lower to IIFE with if constexpr"] E["Diagnostic: Reject raw union"] F["Diagnostic: Reject pointer arithmetic"] end
subgraph Output["Output & Guidance"] G["Emitted C++1 Standard Code"] H["Guidance: 'Use std::variant'"] I["Guidance: 'Use std::span / gsl::span'"] end
A --> D --> G B --> E --> H C --> F --> I ```
- In pure mode (`-p`), Cpp2 processes standalone code without injecting implicit imports or standard includes. - Pattern matching statements (`inspect`) are emitted into C++1 as immediately invoked lambdas containing nested `if constexpr` cascades. - Raw C-style unions are rejected outright by the compiler front-end, enforcing type-safe variants by default.
> “That's the code I want to write and let the rest be an implementation detail.” — Herb Sutter
---
[52:26](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3146s) Bounds Safety: Banning Pointer Arithmetic and Bitwise Operators
Herb shifts the focus to the Bounds Safety Profile defined in the C++ Core Guidelines. The core guidelines have long taught that a raw pointer must represent an address to exactly one single object rather than an unbounded array, and that developers should never perform pointer arithmetic. ISO C++ cannot simply ban pointer arithmetic because doing so would instantly break decades of existing C and C++ software. However, because Cpp2 (Syntax 2) is a clean slate without legacy code, Sutter simply makes the Core Guidelines rule the default by strictly forbidding pointer arithmetic, pointer indexing via brackets, and bizarre legacy constructs like bitwise complement operators on raw pointers. Demonstrating a loop iterating across a vector of strings (`words`), Herb shows raw pointers capturing the addresses of elements (`words.front&` and `words.back&`, noting that unary address-of is a suffix operator in Cpp2). When he attempts to increment the pointer in an idiomatic C-style loop (`first++`), the compiler immediately halts. Herb acknowledges that experienced programmers feel comfortable writing pointer increment loops because it worked for Kernighan and Ritchie, but warns that even a 1% failure rate is catastrophic.
- The C++ Core Guidelines rule that raw pointers point to single objects cannot be retrofitted into C++1 without breaking the world's C and C++ codebase. - In Cpp2, unary operators like address-of (`&`) are placed as suffixes rather than prefixes. - Banning pointer arithmetic also extends to rejecting bitwise operations (such as bitwise complement `~`) directly on raw pointer values.
> “Because if you get it wrong, your program compiles no warnings and appears to run.” — Herb Sutter
---
[55:10](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3310s) Tooling Guidance, Banning Owning Pointers, and the Windows Vulnerability Study
When CppFront encounters forbidden pointer operations, its diagnostic messages direct the developer to safe, modern idioms: incrementing a pointer triggers a diagnostic recommending `std::span` or `gsl::span`, while bitwise operations suggest using `std::bit_cast`. Sutter explains that the only non-standard elements his compiler ever recommends are `gsl::span` and `gsl::narrow`, solely because ISO C++ failed to mandate runtime bounds checking on `std::span`. Similarly, attempting to use raw `delete` produces a fatal error explaining that owning raw pointers do not exist in Cpp2, directing the user toward `unique.new`, `shared.new`, or eventually `gc.new`. Rewriting the iteration using `std::span` (leveraging Class Template Argument Deduction, CTAD) and utilizing Cpp2's universal `next` clause on loops, the code compiles cleanly and safely. To underline the real-world impact of bounds checking, Herb recounts spending a day with Microsoft security expert Joe Bialek reviewing a full year's worth of vulnerability reports across internal Windows source code. In that extensive historical dataset, every single bounds vulnerability would have been completely mitigated had the code been written using a bounds-checked span.
- CppFront diagnostics intentionally point developers to standard library mechanisms or Core Guidelines constructs (`gsl::span`, `gsl::narrow`, `std::bit_cast`). - Raw `delete` and owning raw pointers are eliminated from Cpp2; memory management requires smart factory helpers such as `unique.new` and `shared.new`. - All Cpp2 loop constructs (`for`, `do-while`, etc.) are refactored to support a uniform trailing `next` step expression. - A comprehensive audit of one year of Windows security vulnerabilities conducted by Sutter and Joe Bialek revealed that 100% of the bounds safety vulnerabilities examined would have been prevented by a bounds-checked span.
> “In that particular data set, Joe and I found every single one would have been caught if you'd just been using a bounds checked span.” — Herb Sutter
[01:00:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3600s) Automatic Subscript Bounds Checking Without Wrapping
Herb Sutter reflects on an awkward workaround often taught to developers: creating an artificial, extra `std::span` variable just to iterate over or index elements safely so static analysis tools stay satisfied. He admits that teaching people to introduce a redundant variable just to achieve safety felt a bit hokey, even if safety is well worth the trouble. That observation led him to question why the original container's subscript operator couldn't simply be bounds-checked on its own. Because one of his core design pillars for Cpp2 is seamless interoperability with C++—requiring direct calls with no thunking, no marshalling, and zero wrapping of the standard library—modifying or wrapping types like `std::vector` was completely out of the question. Herb realized that because he controls the compiler, he could solve the problem directly in code generation: “So I'm certainly not going to do anything crazy like wrap the standard library or wrap `std::vector`. But then I thought, I have a compiler. I think I know how to do this.”
```mermaid flowchart TD accTitle: Subscript Bounds Checking Flow in Cppfront accDescr: Diagram showing how cppfront intercepts indexing expressions and routes them through contract bounds checks.
subgraph Source["Cpp2 Source Code"] A["Container Subscript Expression<br/><code>words[3]</code>"] end
subgraph Compiler["Cppfront Lowering"] B{"Is argument integral<br/>AND does target have.size()?"} C["Lower directly to unchecked subscript<br/><code>words[3]</code>"] D["Wrap with bounds assert<br/><code>cpp2::assert_in_bounds(words, 3)</code>"] end
subgraph Runtime["Runtime Contracts Execution"] E["<code>cpp2::bounds.expects(index < size)</code>"] F{"Out of bounds?"} G["Access Container Element"] H["Default: Print violation & terminate<br/>OR Custom Handler via <code>set_handler</code>"] end
A --> B B -- No --> C B -- Yes --> D D --> E E --> F F -- No --> G F -- Yes --> H ```
To demonstrate, Herb writes a simple example containing a classic off-by-one bug: attempting to print the "third" word of a three-word `std::vector<std::string>` by indexing at subscript `3`. As hands slowly go up in the audience, he jokes, “Good. You scared me at first. Of course, I kind of took you by surprise. Yeah, I know. We still all do this. This is not the third word. It's the fourth word. Out of three.” Running the compiled binary initially results in an unchecked out-of-bounds access that happens not to crash, illustrating how silent undefined behavior easily masks bugs in ordinary C++.
- Herb emphasizes that true interoperability means direct execution against ISO Standard C++ types without foreign-function interface (FFI) wrappers. - The standard subscript operation on uninspected standard containers regularly lets memory bugs pass undetected unless explicit checking or tooling intervenes.
---
[01:03:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3780s) Source Location Diagnostics and Generated Assertions
Herb introduces cppfront's subscript bounds safety feature via compiler switches. Compiling the exact same buggy code with the `-s` switch (enable subscript bound safety contract checks) immediately changes the outcome: running the executable traps the bug and prints a clear message: `Bound safety violation, out-of-bounds access attempt detected`. Taking it a step further, combining `-s` with the `-a` switch (add source info)—which Herb jokes was an accidental pun on "public service announcement" (PSA)—injects exact source diagnostics. Running `demo.exe` with `-s -a` pinpoints the fault directly in the Cpp2 source file: `demo.cpp2: Line 5 in function main, bound safety violation`.
Herb explains that cppfront achieves this without altering standard library implementations. When translating Cpp2 syntax to standard C++, the compiler inspects every subscript expression where the index has an integral type and the target container exposes a `.size()` member function. If both conditions match, cppfront wraps the subscript invocation in a helper called `cpp2::assert_in_bounds`. Because it relies solely on the `.size()` convention, this mechanism works uniformly across `std::vector`, `std::array`, `std::string`, `std::span`, and user-defined containers. Beneath the surface, `cpp2::assert_in_bounds` delegates its check to a contract expression structured as `bounds.expects(condition, message)`.
- The `-s` compiler flag enables runtime bounds safety contract checks on indexed containers. - The `-a` compiler flag decorates checks with line numbers and file names (utilizing standard library source location support where available, such as MSVC). - Container checking works polymorphically across any type providing an integral subscript operator and a `.size()` method.
---
[01:04:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=3885s) Granular Contract Groups and Custom Error Handlers
Expanding on the design of runtime verification, Herb describes how contract handling is organized inside cppfront. Aligning with ongoing design efforts in the ISO C++ Contracts study group (SG21), Herb implemented pre- and post-conditions alongside assertions. In cppfront, contracts are partitioned into distinct, named contract group instances rather than handled as an all-or-nothing switch. Concrete built-in group objects include `bounds`, `type`, and `null`. Each group exposes an `.expects(...)` method and maintains its own customizable failure handler.
Herb highlights the engineering reality that motivated this design, crediting discussions with Joe Bialik and feedback from major product teams such as Windows: “One of the reasons is as we talk to different customers, including Windows, but also including others, one of the requirements is that certain errors like bound errors have to be checked all the time. Like there is no turning those off. But contracts can be used for other things. They can be used for business logic, and they don't want those contracts turned on all the time.” By representing contract groups as distinct global objects of type `contract_group`, applications can selectively enforce strict, non-negotiable checks (like memory and bounds safety) in release builds while disabling expensive business-logic contracts.
To illustrate handling custom errors, Herb demonstrates how an application can install its own diagnostic callback using `cpp2::bounds.set_handler(...)`, analogous to `std::set_terminate`. He writes a custom hook function, `call_my_framework(const char* message)`, and registers its address in `main`. When an out-of-bounds indexing occurs, control transfers directly to the custom handler rather than triggering an unceremonious crash to the console, allowing enterprise logging frameworks to intercept security-critical violations gracefully.
- Contract categories are represented as first-class, named C++ objects (`bounds`, `type`, `null`), enabling separate toggle states and severity policies. - Custom handlers can be plugged in per group via `set_handler`, avoiding mandatory program termination if telemetry or structured crash-reporting is required.
---
[01:07:45](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4065s) Re-evaluating Null: Enforcing Non-Null Pointers in Cpp2
Herb transitions from bounds safety to lifetime and memory safety. While the C++ Core Guidelines define a comprehensive lifetime profile based on static analysis, Herb has not yet implemented that full engine in cppfront. Instead, he chose to run a targeted "experiment within an experiment" centered on null pointers. He questions whether general-purpose code genuinely requires null pointers at all, asking what programming would feel like if pointers were inherently non-null by default in Cpp2. Because Cpp2 interacts directly with Cpp1 code, null pointers entering from legacy APIs must still be handled, but within pure Cpp2, Herb seeks to eliminate optional nullability from raw pointers.
He laments how historical defaults in C and C++ set programmers up for failure: “In fact, null is the worst value for a pointer, and it's the default value. Life is just so hard sometimes.” He references Kate Gregory’s celebrated talk, *"What You Say When You Say Nothing at All,"* noting that omitting an explicit initializer on a pointer either leaves it completely uninitialized (if it is a local variable) or zero-initialized to `nullptr` (if it is static/global)—neither of which provides a valid, dereferenceable target. To break this cycle, Herb demonstrates what happens in Cpp2 when attempting to create a pointer variable and assign it `nullptr` or zero: the compiler rejects the declaration with an explicit compilation error: `Pointer cannot be initialized to null or int`.
- The Cpp2 pointer model fundamentally disallows assigning `nullptr` or integral `0` during pointer initialization. - By banishing null as the default pointer state, Cpp2 aims to eradicate null-dereference bugs at compile time while reserving nullable semantics for dedicated optional/nullable wrapper types.
[01:10:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4200s) Banning Null and Enforcing Initialization Before Use
Herb Sutter demonstrates what happens when a programmer tries to cheat the compiler into accepting a null pointer. Attempting to assign `nullptr`, `0`, or even `42` fails immediately. Furthermore, trying to write the old C-style macro `NULL` triggers a unique diagnostic. As Sutter explains to the laughing audience: “You can't even say null anywhere in CPP2. That's not because it's pointer initialization. That's because it's a bad word.” In Cpp2, local variables are uninitialized by default if declared without an explicit assignment, but the compiler strictly guarantees initialization before use. Merely declaring a variable allocates space and defers construction until a value is supplied.
When Sutter writes code that declares an uninitialized pointer `p` to a string and immediately attempts to dereference it, the Cppfront compiler halts compilation with a hard error: `Local variable p is used before it was initialized. Line 14:25, program violates initialization safety guarantee.` To demonstrate branch analysis, he wraps the initialization inside an `if (std::rand() % 2)` coin-flip block, leaving the path uninitialized whenever the condition evaluates to false. The compiler flags the uninitialized use down the missing path. Sutter asks the room for a round of applause if they would like their current C++ compilers to provide diagnostics like that today. When the room claps, he quips: “The reason I asked for applause was not ego, but so that I can see your hands, is so that the compiler implementers watching this video can hear you.” Hearing Dietmar Kühl heckle from the front row, Sutter jokes that he accidentally stole Dietmar's line. Once he adds the balancing `else` branch—initializing `p` to the first word on one branch and the last word on the other—the code passes the safety checks cleanly and executes without error.
- Assigning `nullptr`, integer literals (`0`, `42`), or the literal keyword/macro `NULL` is prohibited for pointers in Cpp2. - Uninitialized local variables allocate storage without executing default constructors until explicit initialization occurs. - The Cppfront compiler tracks control flow to verify that variables are definitely initialized along all paths before any dereference or read.
```mermaid flowchart TD accTitle: Initialization Safety Branch Checking accDescr: Flowchart showing how Cppfront analyzes conditional branches to ensure a variable is initialized on all execution paths.
subgraph BranchCheck ["Branch Analysis: if (rand() % 2)"] Cond{"Condition Check"} ThenPath["'then' branch:<br/>p = &first_word"] ElsePath["'else' branch:<br/>Missing initialization"] end
Cond -->|"true"| ThenPath Cond -->|"false"| ElsePath ThenPath --> MergeNode{"Merge Point"} ElsePath --> MergeNode
MergeNode -->|"p is read / dereferenced"| Result["Compile Error:<br/>'p is used before it was initialized'"] ```
---
[01:14:35](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4475s) Essential vs. Accidental Complexity: The 600-Rule Spreadsheet
Sutter transitions from raw pointer safety to general initialization safety. Two years prior, he gave a talk emphasizing Fred Brooks’ distinction between essential complexity (problems inherent to the domain, such as needing polymorphic dispatch) and accidental complexity (the cumbersome ceremony required by a specific language design). To quantify this distinction, Sutter spent months compiling a massive spreadsheet cataloging over 600 specific rules and recommendations drawn from foundational C++ literature, including Scott Meyers’ *Effective C++* series, Sutter and Andrei Alexandrescu’s *C++ Coding Standards*, *High Integrity C++*, and Google's Abseil guidelines.
He reveals for the first time the hidden criterion behind that project: “What I'll now tell you is, and I also cataloged which ones... I did this by saying which ones would be fixed by CPP2.” Rather than acting as an armchair critic, he only marked a rule as accidental and improvable if he had a concrete technical design to eliminate it. Across the entire corpus of best-practice literature, nearly one-quarter of all published rules were devoted strictly to parameter passing and initialization safety, bloated by the sheer volume of repetitive guidance required to keep programmers safe from C++ defaults.
- The spreadsheet contains over 600 rows detailing specific rules, sub-rules, and advice from major C++ style guides and textbooks. - Literature analyzed includes works by Scott Meyers, Herb Sutter, Andrei Alexandrescu, High Integrity C++, and Abseil. - Initialization safety and parameter passing account for almost 25% of all rules in the surveyed C++ guidelines literature.
---
[01:16:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4590s) Definite First and Last Use Analysis
Sutter revisits the formal concepts of *definite first use* and *definite last use*, which form the backbone of Cpp2's safety analysis. A definite first use is an operation that is guaranteed to be the initial access to a variable on every execution path entering that point. Similarly, a definite last use guarantees that control flowing through that operation will never touch the variable again before exiting the scope. While languages like C# and Ada apply comparable data-flow analysis, Cpp2 applies it strictly to guarantee memory and lifetime safety without runtime overhead. Loops are treated conservatively: because a loop body might execute zero times, an initialization inside a loop body cannot satisfy a definite first use requirement for code following the loop.
To demonstrate, Sutter switches from pointers to a non-trivial type, `std::string x`. Leaving `x` uninitialized and attempting to access it immediately triggers the expected compiler error. When initializing inside conditional code, Sutter emphasizes the recursive nature of the rule: “You either initialize on both branches or neither branch. It's a delightfully recursive rule once you think about it.” While running live tests, he runs into a temporary tooling glitch with MSVC modules where importing standard library modules fails to expose `<chrono>` / `time`, forcing him to swap back to `rand() % 2` rather than alternating based on the system clock. Once both branches are covered, Cppfront compiles the code cleanly.
- Definite first use guarantees that an uninitialized variable receives a valid value across every incoming branch path before it can be read. - Loops do not count toward definite first use because loop conditions may evaluate to false on entry. - Branch analysis applies recursively across arbitrary levels of nested `if`/`else` structures.
---
[01:19:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4740s) Under the Hood: `cpp2::deferred_init` and `out` Parameters
Sutter opens the generated C++1 source side-by-side with the Cpp2 code to reveal the underlying lowering mechanisms. When a local variable is declared without an immediate initializer, Cppfront emits a helper template called `cpp2::deferred_init<T>`. This wrapper reserves properly aligned, uninitialized storage suitable for `T` on the stack without invoking any default constructor. When the user assigns to the variable later in the flow using the `=` operator, the compiler transforms that assignment into an in-place constructor call on the deferred storage.
Furthermore, Sutter shows how initialization interoperates with function calls. Instead of requiring functions to return objects by value or relying on raw pointers and references, Cpp2 supports explicit `out` parameter semantics. In the generated C++1 code, an `out` parameter is realized as a `cpp2::out<T>` wrapper, which accepts an uninitialized `cpp2::deferred_init<T>` storage location and guarantees that the callee constructs the object before returning.
- Uninitialized declarations in Cpp2 lower to `cpp2::deferred_init<T>`, allocating aligned raw storage without constructing an instance. - Subsequent `=` assignments down valid branches translate directly to explicit in-place constructor invocations. - Out-parameters are implemented via `cpp2::out<T>`, allowing functions to directly initialize deferred storage passed in from the caller scope.
[01:20:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4800s) Composable Initialization Safety and the Power of Out Parameters
Herb Sutter highlights the underlying mechanics of `cpp2::out`: the compiler tracks whether an out parameter is constructed with a fully realized value or with deferred initialization. Inside the function body, assigning to that variable triggers `construct`—which either initializes uninitialized storage on its first assignment or acts as a normal assignment if the variable is already constructed. Sutter emphasizes how critical this design is for composable initialization safety in real-world systems programming. Developers frequently allocate a stack buffer or a `std::array` of bytes and immediately hand it off to an operation like `memset`, `memcpy`, or a database reader. In standard C++, programmers are forced to write dead zero-initializations to satisfy safety tools or avoid undefined behavior, even though that memory will be instantly overwritten. Compilers struggle to eliminate these redundant dead writes. In Sutter's model, a unified set of initialization rules governs everything—pointers, strings, integers, large buffers, and plain old data (POD) structures—making safe initialization fully composable across parameter boundaries.
```mermaid flowchart TD accTitle: Composable Initialization Flow via Out Parameters accDescr: Flowchart illustrating how cpp2 out parameters act as delegated constructors without dummy writes.
subgraph CallerScope["Caller Scope"] A["Uninitialized Storage<br>(Stack Buffer / POD)"] B["Call: fill(out buffer)"] end
subgraph CalleeScope["Callee Scope: fill()"] C{"Static Analysis:<br>Is parameter constructed?"} D["construct: In-place initialization<br>(Zero dead writes)"] E["Normal assignment / mutation"] end
A --> B B --> C C -- "First assignment (deferred)" --> D C -- "Subsequent assignment" --> E ```
Addressing audience skepticism, Sutter remarks that whenever he discusses parameter-passing semantics with peers, people often say they love the system except for `out` parameters, questioning their true necessity. Sutter insists that `in` and `out` are actually tied for being the most crucial parameter modes of all six options. Unlike dummy initialization patterns—where developers defensively write placeholder values that accidentally mask uninitialized memory bugs from sanitizers—`out` parameters ensure objects receive programmatically meaningful values with compile-time guarantees. He observes: “Any function that has an out parameter can be a constructor.” By delegating initialization to an external function while having the compiler statically verify that dynamic construction is executed on every code path, Cpp2 generalizes construction into a composable concept.
- Compilers are notoriously bad at optimizing away dead writes inserted purely to satisfy zero-initialization idioms. - Dummy placeholder values hide uninitialized use bugs from runtime sanitizers like MemorySanitizer (MSan). - Functions taking `out` parameters conceptually act as delegated constructors, verified by compile-time definite-initialization analysis.
---
[01:22:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4950s) Named Multiple Return Values Interoperating with C++1
Sutter transitions to a live demonstration showcasing mixed C++1 (today's C++) and C++2 code. After scrolling past traditional header includes, he introduces a Cpp2 function `f` that takes no arguments and returns two named values: an `int` named `i` and a `std::string` named `s`. When asked how many developers have wished for this capability in standard C++ over the years, a large portion of the audience raises their hands. Sutter demonstrates that Cpp2 generates a normal C++ return structure decorated with leading double underscores (e.g., `__f_return`). Because implementers are reserved double-underscore identifiers, this synthesized return type does not pollute the user's namespace. In standard C++, writing such helpers manually forces developers to define a separate `struct` declaration immediately before the function definition, cluttering the enclosing scope.
```mermaid flowchart LR accTitle: Multiple Named Returns Lowering and Interoperability accDescr: Diagram showing Cpp2 named return values compiling to a decorated struct consumed by Cpp1 structured bindings.
subgraph CPP2["Cpp2 Function Declaration"] F["f: () -> (i: int, s: std::string)"] L["Local variables 'i' and 's'<br>Constructed on first assignment"] end
subgraph GeneratedCPP1["Generated C++1 AST"] S["struct __f_return { int i; std::string s; }"] M["std::move on return"] end
subgraph Consumer["Consumer: C++1 Caller"] B["auto [val, text] = f();<br>(Structured Binding)"] end
F --> L L --> S S --> M M --> B ```
Inside the function body, the return elements exist as regular local variables governed by standard definite-assignment rules: they must be assigned before use, and returning from the function automatically generates `std::move` from those locals. The developer merely writes `return;` without repeating the variable names or writing extra semicolons, because the names are already bound in scope. Running the compiled executable, Sutter highlights that the caller is an ordinary C++1 `main` function using modern structured bindings:
```cpp auto [i, s] = f(); ```
The C++1 caller unpacks the returned struct directly without friction. Sutter points out that consumers can also access the fields by their emitted names, making this drastically superior to anonymous `std::tuple` returns or boilerplate-heavy custom types.
- Multiple return values lower into a reserved `__` helper struct to prevent namespace pollution. - Local return variables are subject to identical initialization analysis and automatically moved upon return. - Functions with multiple returns are 100% ABI-compatible with C++17 structured bindings.
---
[01:25:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5100s) The Six Parameter Modes in Cpp2
Sutter moves from `out` parameters to the remaining five parameter passing conventions in Cpp2: `in` (the default), `copy`, `inout`, `move`, and `forward`. Inspecting the C++ code emitted by the Cpp2 compiler, he walks through how each mode is realized:
| Parameter Mode | Cpp2 Syntax | Emitted C++ Semantics | Behavioral Details | |:--- |:--- |:--- |:--- | | **`in`** | `x: in T` (or default) | `cpp2::in<T>` | Immutable const; passes by value if trivially copyable and $\le 2$ pointers in size, otherwise by `const&`. | | **`copy`** | `x: copy T` | By value (`T`) | Caller passes a copy; the parameter is automatically moved from its definite last use if valid. | | **`inout`** | `x: inout T` | `T&` | Explicitly documents the intent to mutate the caller's argument in-place. | | **`move`** | `x: move T` | `T` (via move) | Implicitly moved from on definite last use; call sites must explicitly prefix arguments with `move`. | | **`forward`** | `x: forward T` | `auto&&` + `requires` | Concept-constrained universal reference enabling perfect forwarding for concrete types. | | **`out`** | `x: out T` | `cpp2::out<T>` | Uninitialized target; compiler mandates definite assignment before completion. |
Examining `in`, Sutter points out that using `cpp2::in` completely eliminates the classic C++ dilemmas over whether to pass `T` versus `const T&`. If a type is trivially copyable and at most the size of two pointers, the compiler passes it by value; otherwise, it passes it by reference to `const`. For `copy` parameters, Sutter’s code generator inspects the function body to automatically apply `std::move` to the definite last use of the copy, provided taking an rvalue is valid. For instance, the compiler intentionally avoids inserting a move if the variable's address is taken (`&b`) or if increment/decrement operators are invoked, as that would cause compiler diagnostics. Sutter admits with a smile that he added these exceptions after his early generator unconditionally emitted moves that failed to compile.
Moving to `move` parameters, Sutter explains that the compiler requires the caller to opt in by writing `move arg` at the call site, generating the underlying move automatically. However, calling `std::move` directly inside Cpp2 source code is explicitly made illegal. Sutter reflects on the relief this brings to teaching modern C++:
> “I never again, I hope, have to teach: Why does `std::move` not move? Well, it does now. Why shouldn't I say `return std::move`? Well, no, you can't, so I don't have to teach that. That's the kind of world I want to live in through my C++ code.”
Finally, Sutter analyzes the `forward` parameter. In the generated C++, forwarding a concrete type generates an `auto&&` parameter paired with a C++20 `requires std::same_as<...>` concept constraint. While standard C++ perfect forwarding is almost exclusively restricted to generic template parameters, this idiom makes perfect forwarding just as effortless for concrete types like `std::string`. The compiler then automatically invokes `std::forward` on the parameter's definite last use. Concluding the section, Sutter notes the unified syntax: in Cpp2, there is only one universal syntax for defining functions, whether they appear as named declarations or as inline expressions and lambdas passed directly as arguments.
[01:30:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5400s) Unifying Function Expressions, Loops, and Captures
Herb Sutter explains that in Cpp2, constructs traditionally treated as separate grammar productions—such as lambdas passed to `std::ranges::for_each` or the body of a range-for loop—are conceptually and syntactically identical. In his compiler, they are simply function expressions that flow through the exact same parser logic. A range-for loop body is fundamentally a function: it is the primary construct in the language designed to repeatedly invoke a block of code with arguments that change on each iteration.
Anticipating an obvious objection from the audience after spending an hour and a half claiming all declaration syntax is uniform, Sutter addresses lambda capture. People often assume that needing lambda capture forces a language to provide a dedicated, distinct syntax. Crediting Epic Games founder Tim Sweeney, Sutter shares an insight from a conversation in Sweeney's office years earlier:
> “And he said, well, for Lambda, why don't you just always capture in the body? And by the way, always capture by value. If you want a pointer, take the address and capture that.”
Because Cpp2 already enforces pointer safety and initialization safety, Sweeney’s proposal works seamlessly. Rather than introducing a dedicated capture block before the parameter list, captures are written directly inside the expression body. If code requires a variable's value later when the lambda is evaluated, it captures that value explicitly where needed.
```mermaid flowchart TD accTitle: Unified Capture Model in Cpp2 accDescr: Diagram showing how Cpp2 uses identical capture-by-value syntax across lambdas, postconditions, and string interpolation.
subgraph CoreSyntax["Unified Capture Grammar: capture $name"] direction TB C["Capture by value inside body"] end
subgraph UseCases["Applied Scenarios"] direction TB L["Function Expressions / Lambdas<br/>(evaluate on invocation)"] P["Contract Postconditions<br/>(capture on entry, check on exit)"] S["String Interpolation<br/>(evaluate expressions into text)"] end
CoreSyntax --> L CoreSyntax --> P CoreSyntax --> S ```
Sutter asks the audience where else in current or proposed C++ a programmer captures a state now to execute or check it later. When someone suggests coroutines, Sutter agrees, but highlights another major application that already works in Cpp2: contract postconditions.
When specifying a postcondition on a mutating operation (such as `push_back`), one writes the contract at the top of the function—conceptually at entry—but it executes on return. To assert that the new size equals the previous size plus one, the function captures the starting size upon entry using the identical capture syntax. Furthermore, string interpolation in Cpp2 reuses this exact same mechanism. Sutter stresses the power of this syntactic economy:
> “And I think it's really important that there's one way to capture, there is one way to declare functions, there is one way to declare anything, because variables, types, and functions are all declared the same way.”
[01:33:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5580s) Familiar Vocabulary and the Implementation Roadmap
Taking a step back, Sutter observes that over the entire presentation, he has managed to avoid alienating jargon:
> “I have not said the word monad once.”
The audience laughs and applauds. Sutter emphasizes that none of the concepts introduced in Cpp2 are exotic or imported haphazardly from foreign programming paradigms. Instead, they reflect the way C++ programmers already think, talk, and reason about systems. His goal is not to reinvent software development, but to make those familiar daily idioms dramatically simpler and nicer to use.
Sutter outlines the remaining roadmap of features he must still implement, sorted roughly in ascending order of difficulty: - **Explicit Parameter Lists:** Refining the handling of parameter list definitions. - **Unified Classes, Constructors, and Assignment:** Implementing the unified object model proposed in his paper P0708 (referenced as D708), where constructors and assignment operators are unified through `out` parameters. With `out` parameters already functioning, Sutter hopes to tackle this over the upcoming Christmas break. - **Reflection, Generation, and Metaclasses:** Generating new code directly from the parse tree in a structured, disciplined way, avoiding raw token/textual substitution. - **Deterministic Lightweight Exceptions:** The most challenging task on the roadmap. It requires deep integration with stack-unwinding machinery, with the ambition of delivering deterministic-time `throw` and `catch` paths in collaboration with compiler vendors.
[01:35:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5700s) Call for Community Collaborators
Sutter invites the community to contribute to several exploratory projects surrounding the Cpp2 ecosystem:
- **Editor and Syntax Support:** Writing syntax highlighting for VS Code proved unexpectedly intractable. Sutter reached out to the maintainer of Microsoft's default C++ VS Code grammar to ask how to highlight additional keywords via regular expressions, only to be told that the underlying TextMate/regex engine is notoriously difficult and to seek help in specialized discussion forums. Sutter welcomes any developer with expertise in syntax highlighters to step in. - **Universal Function Call Syntax (UFCS) Autocomplete:** Designing editor tooling that can discover non-member functions and surface them through dot-autocomplete (`my_object.`). - **Compiler Explorer (Godbolt) Integration:** Hosting the transpiler on Compiler Explorer, including the ability to select the backend second-stage C++ compiler. - **Garbage-Collected Arenas:** Sutter notes that in Cpp2, all dynamic memory allocation occurs within explicit arenas. While general usage relies on deterministic arenas, an opt-in, zero-overhead-if-unused tracing garbage-collected arena remains an active design goal. Referencing his six-year-old `GCPP` proof of concept, Sutter jokes: > “I wrote a prototype implementation, but I am not a garbage collection expert, so it don't scale. But it's a proof of concept. If someone who knows what they're doing would like to collaborate, please send me mail.” - **`cpp2util` Minimal Drawing Library (`cpp2draw`):** Building a 21st-century, header-only equivalent to `curses` or `<conio.h>` providing a basic canvas, text, and keyboard input API. - **Source Migration Tooling (`fromcpp`):** In the longer term, hooking into an existing C++ frontend's AST pretty-printer to automatically analyze legacy C++ (Cpp1), detect recurring idioms, and translate them directly into clean Cpp2 syntax.
[01:37:30](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=5850s) A Directed Evolution for C++
Sutter brings his talk to a conclusion by posing a fundamental question about the future of the language:
> “What if we could do C++ feels like a new language again, like we did in C++11? It feels like it, but it is still C++. But this time do it broadly across the whole language.”
He clarifies that Cpp2 is an experiment that could fail, but it exists to start a constructive industry conversation. Rather than fracturing the ecosystem or attempting to compete with the ISO C++ standard, Cpp2 is designed as a *directed evolution* that enthusiastically embraces modern standards like C++20, C++23, C++26, and modules (treating `import std;` as the default). Compiling down to standard C++ keeps the project completely honest. When ideas are proven effective, they can be upstreamed to the ISO C++ committee, which continues to own and define what C++ is.
Reviewing what developers would gain, Sutter highlights the massive cognitive burden that completely evaporates:
| Legacy C++ (Cpp1) Pain Points | Cpp2 Solution / Resolution | |:--- |:--- | | **Preprocessor & Headers** | Entirely gone. No `#include`, no tracking standard header placement, no declaration ordering dependencies. | | **Parsing Ambiguities** | Single declaration syntax eliminates the Most Vexing Parse, inside-out declarations, and East-versus-West `const` debates. | | **Function Signatures** | Eradicates disparate syntaxes between free functions, member functions, operator overloads, and lambdas. | | **Parameter Passing** | Replaces the agonizing choice between `T`, `const T&`, and `T&&` with explicit intent modifiers (`in`, `copy`, `inout`, `out`, `move`). |
[01:40:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6000s) Cutting C++ Complexity and Testing Bjarne Stroustrup's Conjecture
Herb Sutter rapidly enumerates the vast catalog of subtle rules, caveats, and syntactic traps in modern C++ that could be eliminated in an evolved syntax. He targets references, arguing that while they were originally added solely for parameter passing, they were unfortunately threaded across the entire type system, creating continuous conceptual baggage even in contexts where they should not be needed. He moves through the minefield of move semantics and forwarding: `std::move` and why it does not actually move data; why it is frequently overused; why returning `std::move` disables optimizations; why `&&` on a template parameter type is actually a forwarding reference rather than an rvalue reference; how to spell perfect forwarding with `std::forward`; and the bizarre acrobatics required to forward a non-template type. He points out that his proposed named return values make Named Return Value Optimization (NRVO) fall out automatically—because returning a consistently named return object means developers do not have to be taught how to coax the compiler into applying NRVO, nor choose between an anonymous tuple or polluting the namespace with a struct.
The list of pain points continues to mount: raw `new` and `delete`, owning raw pointers, memory leaks, `0` acting as an integer except when treated as a pointer, null pointer dereferences, pointer arithmetic running out of bounds, extra parentheses disambiguating prefix versus postfix expressions, diverse type queries, two whole paragraphs of type conversion categories, and disparate lambda capture syntaxes. Sutter polls the audience on whether these concepts are intimately familiar to them, receiving widespread hand raises, and then asks if they want an experimental language where they retain 100% of the expressiveness and performance of C++ without writing any of these error-prone patterns on the right-hand side of the board. The room responds with a sea of raised hands.
Sutter connects this directly to Bjarne Stroustrup's long-standing belief in fundamental language simplification, declaring: “Bjarne Stroustrup conjectured famously that C++ could be 10x simpler and safer. My thesis is that Bjarne is right, that he was right all along, and I'm giving it a go to see if I can prove it by actually implementing it, because I love C++.” Sutter reiterates that C++ remains the absolute best language for him to accomplish his daily work, but he wants to write it cleanly. He challenges the audience to envision where this experiment—or an alternative inspired by it—could lead the ecosystem over the next five to ten years: writing C++ with far more certainty, less teaching overhead, greater simplicity, and the modern tooling enjoyed by newer languages.
- Language friction points targeted for removal: - References throughout the general type system outside parameter passing. - `std::move`, `std::forward`, forwarding references (`&&` on template types), and move anti-patterns. - Manual optimization enabling (e.g., NRVO) versus language-automated copy elision. - Raw dynamic allocation (`new`/`delete`), owning raw pointers, and manual memory management. - Pointer/integer ambiguity around `0` and `NULL`. - Intricate type query, cast, and lambda capture permutations.
```mermaid flowchart TD accTitle: Cpp2 Complexity Elimination accDescr: Diagram contrasting legacy Cpp1 complexity burdens with the simplified model in Cpp2.
subgraph LegacyCpp["Legacy C++ (Cpp1 Complexity)"] A["Explicit std::move / std::forward"] B["Manual NRVO Gymnastics"] C["Owning Raw Pointers & new/delete"] D["Reference Leaks in Type System"] end
subgraph EvolvedCpp["Experimental Direction (Cpp2)"] E["Automatic Value Category Passing"] F["Named Return Values (Automatic NRVO)"] G["Default Safe Lifetime Management"] H["Simplified Parameter Semantics"] end
A -.->|"Eliminated by"| E B -.->|"Replaced by"| F C -.->|"Automated by"| G D -.->|"Constrained to"| H ```
---
[01:43:08](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6188s) Compiler Explorer Announcement and the Zero-Overhead Principle
As Sutter opens the floor for questions, an attendee approaches the microphone not to pose a question, but to announce breaking news: Matt Godbolt has just added official support for Sutter's `cppfront` compiler to Compiler Explorer. Sutter enthusiastically thanks Matt, calling him a personal hero for years of enabling the C++ community.
The first technical question delves into C++'s core tenet: the zero-overhead abstraction principle. The audience member observes that some features introduced in Cpp2—such as deferred initialization, which may track state using a behind-the-scenes boolean flag even for primitive types like integers—introduce runtime overhead. Sutter responds by clarifying the true formulation of the zero-overhead principle: “So the zero-overhead principle isn't zero cost, so you don't pay for what you don't use.” Sutter stresses that around 90% of the time, developers supply an initial value directly at the variable declaration site, resulting in absolute zero overhead. Only when a developer explicitly chooses deferred initialization (such as executing divergent constructor calls or complex branch-dependent logic) does the tracking boolean come into play. Because this is an experiment, Sutter notes that real-world implementation will uncover whether the trade-off is justified, but the baseline design strictly adheres to paying cost only when invoking the specific feature.
The attendee follows up by asking about replacing low-level constructs like C-style unions with `std::variant`, questioning whether forcing safe alternatives strips control away from developers demanding raw performance. Sutter points out that modern best practice already teaches developers to prefer `std::variant` over raw `union`. More fundamentally, Cpp2 provides total backward source compatibility:
- Full Cpp1 syntax remains valid and supported inside a Cpp2 translation unit. - If raw memory union semantics are genuinely required for extreme micro-optimizations, developers can explicitly write standard Cpp1 `union` syntax directly in their code.
---
[01:46:17](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6377s) Safe Defaults, Preprocessor Elimination, and Constraining Complexity
The Q&A shifts to language defaults and compiler flags. An attendee asks why `-p` (pure Cpp2 mode) is an opt-in switch rather than the default compiler behavior if the overarching philosophy is making bad code difficult to write. Sutter explains that `-p` forbids `#include`, macros, and any legacy syntax; keeping it opt-in is essential so developers can seamlessly write mixed Cpp1 and Cpp2 code during the transition. Expanding to other opt-in flags, Sutter notes that bounds checking for subscripts and null-dereference checks are currently placed behind compiler flags. While he conjectures modern branch predictors and memory architectures make these runtime checks cheap, they are left opt-in for now to collect hard benchmark data on whether their overhead is negligible or non-trivial.
A question from the online audience, asked by Alexei, touches on eliminating the C preprocessor. Alexei asks how developers can achieve logging or exception context without macros, noting that while C++23 introduces `std::source_location`, macros are historically used to capture line numbers (`__LINE__`), files (`__FILE__`), and function names (`__func__`). Sutter explains that C++ is methodically chipping away at the macro preprocessor:
1. **C++20 Modules** replace header inclusions and textual macro proliferation. 2. **`constexpr` extensions** replace compile-time macro calculations and code generation tricks. 3. Remaining compiler bookkeeping needs (like `#line` directives, which `cppfront` itself currently generates to map compiler errors back to source files) will be phased out. 4. Future standard **static reflection and code generation** represent the crucial leap that should eliminate the last major justifications for writing macros.
A final attendee asks whether the simplification drive should establish uniform file extensions, code formatting, and strict variable naming conventions to eliminate instructional friction. Sutter acknowledges that while he loves constraints—recalling the adage that constraints liberate by focusing human ingenuity where it actually matters—he remains unconvinced that styling or naming dictates move the needle on software quality. Sutter sets a rigorous bar for justifying new constraints: “If you can convince me that a naming convention for variables would get rid of 5% of the things that we currently teach people, now you've got my attention, but I would need to be able to prove that and measure it.” Without empirical evidence that a stylistic restriction eliminates a measurable percentage of Common Vulnerabilities and Exposures (CVEs) or cuts down chapters in coding standard manuals, he declines to mandate them.
[01:50:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6600s) Context-Free Parsing and Tooling Heuristics
An audience member asks about the tooling ecosystem, noting that formatters and static analysis tools frequently rely on fuzzy heuristics because they cannot definitively deduce intent—such as guessing whether an identifier should be `const` based merely on naming conventions. Herb agrees and explains that the primary reason existing C++ tools are forced to depend so heavily on fragile heuristics is simply that the language is notoriously difficult to parse.
In response, Herb highlights the parsing model he built into the `cppfront` compiler repository. To solve this foundational problem, he has implemented a standalone, context-free, and order-independent parser. While it is currently only a partial grammar, his goal is to grow it until it matches the full expressiveness of current C++ syntax while remaining cleanly reusable by other tooling authors. Once tooling can rely on an unambiguous, context-free grammar, formatters and analyzers will no longer need to lean on guesswork to understand user code.
- **Parser Design in `cppfront`**: A standalone, context-free, and order-independent grammar that eliminates the ambiguity that plagues C++ parsing. - Herb Sutter's view on parser difficulty: “One of the reasons tools need those heuristics is because it's so hard to write a C++ parser.” - **Reusability**: By designing the parser to be easily modularized and reused, external linters and formatters can process Cpp2 code reliably without heuristic workarounds.
---
[01:50:47](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6647s) Fixing C++ Pedagogy: The Power of Naming "Cpp2"
```mermaid flowchart TD accTitle: Cpp1 Compatibility Trap versus Cpp2 Clean Slate accDescr: Shows how backward source compatibility in Cpp1 enables outdated teaching habits, whereas Cpp2 enforces modern defaults by omission.
subgraph LegacyCpp ["Legacy C++ (Cpp1) Backward Compatibility"] A["Backward source compatibility mandatory"] --> B["'They teach it because they can'"] B --> C["fprintf, NULL macro, 0-as-pointer, raw owning new"] end
subgraph ModernCpp2 ["Clean-Slate Syntax (Cpp2)"] D["Distinct noun: 'Cpp2'"] --> E["Pure Cpp2 grammar omits obsolete constructs"] E --> F["Forces modern defaults, uniform initialization, and safe memory idioms"] end ```
Herb uses the tooling question as a springboard to address a persistent frustration shared by himself, Bjarne Stroustrup, and many modern developers: educators consistently teaching C++ by starting with C. Herb points out that this teaching habit is a direct artifact of C++'s unwavering commitment to backward source compatibility. Instructors introduce `fprintf` early in university curricula simply because the compiler allows it and the legacy code still compiles. Bjarne Stroustrup wrote *A Tour of C++* and authored dedicated programming textbooks precisely to combat this, begging educators to adopt modern C++ idioms rather than defaulting to C-style basics or obsolete C++98 patterns. Yet universities continually resist, replying that they stick with legacy practices simply because that is what they are accustomed to doing.
This pedagogical failure explains why Herb intentionally chose the distinct name "Cpp2" rather than referring to it abstractly as "syntax 2." By establishing a new, distinct noun, it creates an enforceable standard for education. An instructor teaching a course titled "Cpp2" cannot start the syllabus with `fprintf`, `NULL`, `0` used as a null pointer constant, or naked owning `new` pointers that leak memory by default, because pure Cpp2 simply does not include those constructs. While legacy functions can still be invoked through unified member-function call syntax for compatibility, the outdated syntax and unsafe defaults are completely absent from the pure language.
Reflecting on the need for radical improvement, Herb argues that on the current trajectory, the community would have already fixed C++ education if conventional incremental means were sufficient. Cpp2 serves as a deliberate lever to force courses to advance by a factor of 10x. Acknowledging that the project may face long odds, Herb concludes with cautious optimism before thanking the audience, wishing everyone safe travels, and inviting them back for next year's CppCon.
- Herb Sutter on university teaching habits: “One of the things that really bugs Bjarne and me and others is people teaching C++ starting with C.” - Herb Sutter on the reason legacy code is taught: “They do it because they can. Because that code works.” - Herb Sutter on the purpose of establishing a distinct name: “One of the advantages of having a name for a syntax, so one of the reasons I say not just syntax 2, but I call it CPP2, because if it succeeds, and it will probably fail, but if it succeeds, it also gives you a noun where nobody will be able to ever teach a CPP2 course and start with fprintf because that's not in pure CPP2.” - Herb Sutter on why an external lever is needed: “If we would have brought C++ courses significantly 10x forward, which is part of making teaching and learning 10x better, on the current path, we would have done it by now.” - **Constructs Banned in Pure Cpp2**: - The `NULL` macro. - Using literal `0` as a pointer. - Raw owning pointers paired with naked `new` and default leaks. - Traditional non-member `fprintf` invocation (which must be called using unified member call syntax if used at all).
## Notable quotes > [00:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=0s) To me, safer, 50x safer means 98% fewer CVEs, vulnerability exploits, and bugs in those categories. 10x simpler means I can get rid of 90% of the paper of the books I teach today. — Herb Sutter
> [40:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=2400s) Call me paranoid, but when a government department starts telling you to do work and move to other languages, we should start to listen. — Herb Sutter
> [25:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=1500s) The ugliness of generated code is directly proportional to the impedance mismatch. If your source is still C++, then you can make it beautiful. — Herb Sutter
> [01:50:47](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=6647s) One of the things that really bugs Bjarne and me and others is people teaching C++ starting with C. — Herb Sutter
> [01:20:00](https://www.youtube.com/watch?v=ELeZAKCN4tY&t=4800s) Any function that has an out parameter can be a constructor. — Herb Sutter
## Mentioned Herb Sutter, Bjarne Stroustrup, Fred Brooks, Anders Hejlsberg, Niklaus Wirth, Scott Meyers, Andrei Alexandrescu, Tim Sweeney, Matt Godbolt, Joe Bialek, Joe Biden, Dave Abrahams, Kate Gregory, Dietmar Kühl, Brian Kernighan, Dennis Ritchie, Alexei, Microsoft, ISO C++ Standards Committee, Standard C++ Foundation, CppCon, United States Department of Commerce, MITRE, NIST, Windows, Google, Epic Games, Cfront, cppfront, Cpp2, Cpp1, Clang, GCC, MSVC, Windows Subsystem for Linux (WSL), Ubuntu, Compiler Explorer, Microsoft Visual Studio Code, GCPP, Rust, TypeScript, Python, The Mythical Man-Month, Effective C++, High Integrity C++, C++ Coding Standards, A Tour of C++, C++ Core Guidelines, P0708
## Video description https://cppcon.org/ https://github.com/CppCon/CppCon2022 ---
Can C++ be 10x Simpler & Safer? (Simplifying C++ #9 of N) - Herb Sutter - CppCon 2022
Since CppCon 2015, all of Herb’s talks have been about ways to evolve C++ to make it simpler, safer, and more toolable. Every release of ISO C++ has already been making regular incremental “10%” improvements in these areas. But what are the fundamental factors that limit our rate of improvement, and what would it take to make greater progress? Like every year, Herb’s talk will explore selected current pain points and describe experimental ideas to address them that might someday contribute toward C++’s long-term evolution. ---
Herb Sutter
Herb is an author, designer of several Standard C++ features, and chair of the ISO C++ committee and the Standard C++ Foundation. His current interest is simplifying C++. ---
Work at Hudson River Trading (HRT): https://tinyurl.com/safxfctf ---
Videos Filmed & Edited by Bash Films: http://www.BashFilms.com YouTube Channel Managed by Digital Medium Ltd https://events.digital-medium.co.uk
#cppcon #programming #coding
[Source](https://www.youtube.com/watch?v=ELeZAKCN4tY)