## File: README.md

# Carbon Language:  An experimental successor to C++





**See our [announcement video](https://youtu.be/omrY53kbVoA) from
[CppNorth](https://cppnorth.ca/).** Note that Carbon is
[not ready for use](#project-status).

<a href="docs/images/snippets.md#quicksort">


</a>




**Fast and works with C++**

-   Performance matching C++ using LLVM, with low-level access to bits and
    addresses
-   Interoperate with your existing C++ code, from inheritance to templates
-   Fast and scalable builds that work with your existing C++ build systems

**Modern and evolving**

-   Solid language foundations that are easy to learn, especially if you have
    used C++
-   Easy, tool-based upgrades between Carbon versions
-   Safer fundamentals, and an incremental path towards a memory-safe subset

**Welcoming open-source community**

-   Clear goals and priorities with robust governance
-   Community that works to be welcoming, inclusive, and friendly
-   Batteries-included approach: compiler, libraries, docs, tools, package
    manager, and more

## Why build Carbon?

C++ remains the dominant programming language for performance-critical software,
with massive and growing codebases and investments. However, it is struggling to
improve and meet developers' needs, as outlined above, in no small part due to
accumulating decades of technical debt. Incrementally improving C++ is
[extremely difficult](/docs/project/difficulties_improving_cpp.md), both due to
the technical debt itself and challenges with its evolution process. The best
way to address these problems is to avoid inheriting the legacy of C or C++
directly, and instead start with solid language foundations like
[modern generics system](#generics), modular code organization, and consistent,
simple syntax.

Existing modern languages already provide an excellent developer experience: Go,
Swift, Kotlin, Rust, and many more. **Developers that _can_ use one of these
existing languages _should_.** Unfortunately, the designs of these languages
present significant barriers to adoption and migration from C++. These barriers
range from changes in the idiomatic design of software to performance overhead.

Carbon is fundamentally **a successor language approach**, rather than an
attempt to incrementally evolve C++. It is designed around interoperability with
C++ as well as large-scale adoption and migration for existing C++ codebases and
developers. A successor language for C++ requires:

-   **Performance matching C++**, an essential property for our developers.
-   **Seamless, bidirectional interoperability with C++**, such that a library
    anywhere in an existing C++ stack can adopt Carbon without porting the rest.
-   **A gentle learning curve** with reasonable familiarity for C++ developers.
-   **Comparable expressivity** and support for existing software's design and
    architecture.
-   **Scalable migration**, with some level of source-to-source translation for
    idiomatic C++ code.

With this approach, we can build on top of C++'s existing ecosystem, and bring
along existing investments, codebases, and developer populations. There are a
few languages that have followed this model for other ecosystems, and Carbon
aims to fill an analogous role for C++:

-   JavaScript → TypeScript
-   Java → Kotlin
-   C++ → **_Carbon_**

## Language Goals

We are designing Carbon to support:

-   Performance-critical software
-   Software and language evolution
-   Code that is easy to read, understand, and write
-   Practical safety and testing mechanisms
-   Fast and scalable development
-   Modern OS platforms, hardware architectures, and environments
-   Interoperability with and migration from existing C++ code

While many languages share subsets of these goals, what distinguishes Carbon is
their combination.

We also have explicit _non-goals_ for Carbon, notably including:

-   A stable
    [application binary interface](https://en.wikipedia.org/wiki/Application_binary_interface)
    (ABI) for the entire language and library
-   Perfect backwards or forwards compatibility

Our detailed [goals](/docs/project/goals.md) document fleshes out these ideas
and provides a deeper view into our goals for the Carbon project and language.

## Project status

Carbon Language is currently an experimental project. We are hard at work on a
toolchain implementation with compiler and linker. You can try out the current
state at [compiler-explorer.com](http://carbon.compiler-explorer.com/).

We want to better understand whether we can build a language that meets our
successor language criteria, and whether the resulting language can gather a
critical mass of interest within the larger C++ industry and community.

Currently, we have fleshed out several core aspects of both Carbon the project
and the language:

-   The strategy of the Carbon Language and project.
-   An open-source project structure, governance model, and evolution process.
-   Critical and foundational aspects of the language design informed by our
    experience with C++ and the most difficult challenges we anticipate. This
    includes designs for:
    -   Generics
    -   Class types
    -   Inheritance
    -   Operator overloading
    -   Lexical and syntactic structure
    -   Code organization and modular structure
-   An under-development [compiler and toolchain](/toolchain/) that will compile
    Carbon (and eventually C++ code as well) into standard executable code. This
    is where most of our current implementation efforts are directed.
    -   Historically, there was also a prototype
        [explorer](https://github.com/carbon-language/explorer) interpreter that
        implemented an older version of the Carbon language design, but is no
        longer under development and has been archived.

If you're interested in contributing, we're currently focused on developing the
Carbon toolchain until it can
[support Carbon ↔ C++ interop](/docs/project/roadmap.md#access-most-non-template-c-apis-in-carbon).
Beyond that, we plan to continue developing the design and toolchain until we
can ship the
[0.1 language](/docs/project/milestones.md#milestone-01-a-minimum-viable-product-mvp-for-evaluation)
and support evaluating Carbon in more detail.

You can see our [full roadmap](/docs/project/roadmap.md) for more details.

## Carbon and C++

If you're already a C++ developer, Carbon should have a gentle learning curve.
It is built out of a consistent set of language constructs that should feel
familiar and be easy to read and understand.

The Carbon code here is hypothetical and meant to show the look and feel of the
language.

C++ code like this:

<a href="docs/images/snippets.md#c">


</a>

corresponds to this Carbon code:

<a href="docs/images/snippets.md#carbon">


</a>

You can call Carbon from C++ without overhead and the other way around. This
means you migrate a single C++ library to Carbon within an application, or write
new Carbon on top of your existing C++ investment. For example:

<a href="docs/images/snippets.md#mixed">


</a>

Read more about
[C++ interop in Carbon](/docs/design/interoperability/philosophy_and_goals.md).

Beyond interoperability between Carbon and C++, we're also planning to support
migration tools that will mechanically translate idiomatic C++ code into Carbon
code to help you switch an existing C++ codebase to Carbon.

## Generics

Carbon provides a
**[modern generics system](/docs/design/generics/overview.md#what-are-generics)**
with checked definitions, while still **supporting opt-in
[templates](/docs/design/templates.md) for seamless C++ interop**. Checked
generics provide several advantages compared to C++ templates:

-   **Generic definitions are fully type-checked**, removing the need to
    instantiate to check for errors and giving greater confidence in code.
    -   Avoids the compile-time cost of re-checking the definition for every
        instantiation.
    -   When using a definition-checked generic, usage error messages are
        clearer, directly showing which requirements are not met.
-   **Enables automatic, opt-in type erasure and dynamic dispatch** without a
    separate implementation. This can reduce the binary size and enables
    constructs like heterogeneous containers.
-   **Strong, checked interfaces** mean fewer accidental dependencies on
    implementation details and a clearer contract for consumers.

Without sacrificing these advantages, **Carbon generics support
specialization**, ensuring it can fully address performance-critical use cases
of C++ templates. For more details about Carbon's generics, see their
[design](/docs/design/generics).

In addition to easy and powerful interop with C++, Carbon templates can be
constrained and incrementally migrated to checked generics at a fine granularity
and with a smooth evolutionary path.

## Memory safety

Safety, and especially
[memory safety](https://en.wikipedia.org/wiki/Memory_safety), remains a key
challenge for C++ and something a successor language needs to address.

We plan to support a two step migration process:

1.  Highly automated, minimal supervision migration from C++ to a dialect of
    Carbon designed for C++ interop and migration.
2.  Incremental refactoring of the Carbon code to adopt memory-safe designs,
    patterns, and APIs.

We also want to address important, low-hanging fruit in the safety space
immediately when migrating into Carbon:

-   Tracking uninitialized states better, increased enforcement of
    initialization, and hardening against initialization bugs when needed.
-   Designing fundamental APIs and idioms to support dynamic bounds checking.
-   Switching from undefined behavior to erroneous behavior wherever possible,
    and marking the remaining undefined behavior with visible `unsafe` syntax.
-   Having a default debug build mode that has less runtime overhead while being
    more comprehensive than existing C++ debug build modes combined with
    [Address Sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer).

For more details, see our [safety design](/docs/design/safety).

## Getting started

To try out Carbon immediately in your browser, you can use the toolchain at:
[carbon.compiler-explorer.com](http://carbon.compiler-explorer.com/).

We are developing a traditional toolchain for Carbon that can compile and link
programs. However, Carbon is still an early, experimental project, and so we
only have very experimental nightly releases of the Carbon toolchain available
to download, and only on limited platforms. If you are using a recent Ubuntu
Linux or similar (Debian, WSL, etc.), you can try these out by going to our
[releases](https://github.com/carbon-language/carbon-lang/releases) page and
download the latest nightly toolchain tar file:
`carbon_toolchain-0.0.0-0.nightly.YYYY.MM.DD.tar.gz`. Then you can try it out:

```shell
# A variable with the nightly version from yesterday:
VERSION="$(date -d yesterday +0.0.0-0.nightly.%Y.%m.%d)"

# Get the release
wget https://github.com/carbon-language/carbon-lang/releases/download/v${VERSION}/carbon_toolchain-${VERSION}.tar.gz

# Unpack the toolchain:
tar -xvf carbon_toolchain-${VERSION}.tar.gz

# Create a simple Carbon source file:
echo "import Core library \"io\"; fn Run() { Core.Print(42); }" > forty_two.carbon

# Compile to an object file:
./carbon_toolchain-${VERSION}/bin/carbon compile \
  --output=forty_two.o forty_two.carbon

# Install minimal system libraries used for linking. Note that installing `gcc`
# or `g++` for compiling C/C++ code with GCC will also be sufficient, these are
# just the specific system libraries Carbon linking still uses.
sudo apt install libgcc-11-dev

# Link to an executable:
./carbon_toolchain-${VERSION}/bin/carbon link \
  --output=forty_two forty_two.o

# Run it:
./forty_two
```

As a reminder, the toolchain is still very early and many things don't yet work.
Please hold off on filing lots of bugs: we know many parts of this don't work
yet or may not work on all systems. We expect to have releases that are much
more robust and reliable that you can try out when we reach our
[0.1 milestone](/docs/project/milestones.md#milestone-01-a-minimum-viable-product-mvp-for-evaluation).

If you want to build Carbon's toolchain yourself or are thinking about
contributing fixes or improvements to Carbon, you'll need to install our
[build dependencies](/docs/project/contribution_tools.md#setup-commands) (Clang,
LLD, libc++) and check out the Carbon repository. For example, on Debian or
Ubuntu:

```shell
# Update apt.
sudo apt update

# Install tools.
sudo apt install \
  clang \
  libc++-dev \
  libc++abi-dev \
  lld

# Download Carbon's code.
$ git clone https://github.com/carbon-language/carbon-lang
$ cd carbon-lang
```

Then you can try out our toolchain which has a very early-stage compiler for
Carbon:

```shell
# Build and run the toolchain's help to get documentation on the command line.
$ ./scripts/run_bazelisk.py run //toolchain -- help
```

For complete instructions, including installing dependencies on various
different platforms, see our
[contribution tools documentation](/docs/project/contribution_tools.md).

Learn more about the Carbon project:

-   [Project goals](/docs/project/goals.md)
-   [Language design overview](/docs/design)
-   [Carbon Toolchain](/toolchain)
-   [FAQ](/docs/project/faq.md)

## Conference talks

Carbon focused talks from the community:

### 2026

-   Carbon memory safety: a first deep dive (July 10,
    [video](https://drive.google.com/file/d/1tQlzpnbWZfn2WtTFMoJgF93QteByBBwm/view?usp=sharing),
    [transcript](https://docs.google.com/document/d/1JB9H3KzVixAPC5WIytS4AMyrvjwzC7TXqp596veLT34/edit?usp=sharing),
    [slides](https://chandlerc.blog/slides/2026-memory-safety-deep-3/))
-   Benchmarking and optimizing the Carbon compiler, NDC {Toronto} (May 5-8)
    ([video](https://www.youtube.com/watch?v=hN6KcAKfTN0),
    [slides](https://chandlerc.blog/slides/2026-ndc-toronto-carbon-benchmarking))
-   Carbon: graduating from the experiment, NDC {Toronto} (May 5-8)
    ([video](https://www.youtube.com/watch?v=WJl4ftb5Fxg),
    [slides](https://chandlerc.blog/slides/2026-ndc-toronto-carbon-update/))

### 2025

-   Carbon: from C++ to Memory Safety, REBASE - ICFP/SPLASH
    ([slides](https://chandlerc.blog/slides/2025-rebase-carbon))
-   Memory safety everywhere with both Carbon and Rust, RustConf
    ([video](https://youtu.be/FYLuom6gg_s),
    [slides](https://chandlerc.blog/slides/2025-rustconf-memory-safety-everywhere))

### 2024

-   Generic implementation strategies in Carbon and Clang, LLVM Developers'
    Meeting ([video](https://youtu.be/j0BL52NdjAU),
    [slides](https://chandlerc.blog/slides/2024-llvm-generic-implementation/#/))
-   The Carbon Language: Road to 0.1, NDC {TechTown}
    ([video](https://youtu.be/bBvLmDJrzvI),
    [slides](https://chandlerc.blog/slides/2024-ndc-techtown-carbon-road-to-0-dot-1))
-   How designing Carbon with C++ interop taught me about C++ variadics and
    overloads, CppNorth ([video](https://youtu.be/8SGMy9ENGz8),
    [slides](https://chandlerc.blog/slides/2024-cppnorth-design-stories))
-   Generic Arity: Definition-Checked Variadics in Carbon, C++Now
    ([video](https://youtu.be/Y_px536l_80),
    [slides](https://docs.google.com/presentation/d/10aM1mFMN6Cd5ZkE4OfeiZtSnkVNbo33N-V0et21umww/edit))
-   Carbon: An experiment in different tradeoffs, panel session, EuroLLVM
    ([video](https://youtu.be/Za_KWj5RMR8),
    [slides](https://llvm.org/devmtg/2024-04/slides/LightningTalks/Smith-Carbons-high-level-semanticIR.pdf))
    -   [Alex Bradbury's notes](https://muxup.com/2024q2/notes-from-the-carbon-panel-session-at-eurollvm)
-   Carbon's high-level semantic IR lightning talk, EuroLLVM
    ([video](https://youtu.be/vIWT4RhUcyw))

### 2023

-   Carbon’s Successor Strategy: From C++ interop to memory safety, C++Now
    ([video](https://youtu.be/1ZTJ9omXOQ0),
    [slides](https://chandlerc.blog/slides/2023-cppnow-carbon-strategy/index.html#/))
-   Definition-Checked Generics, C++Now
    -   Part 1 ([video](https://youtu.be/FKC8WACSMP0),
        [slides](https://chandlerc.blog/slides/2023-cppnow-generics-1/#/))
    -   Part 2 ([video](https://youtu.be/VxQ3PwxiSzk),
        [slides](https://chandlerc.blog/slides/2023-cppnow-generics-2/#/))
-   Modernizing Compiler Design for Carbon’s Toolchain, C++Now
    ([video](https://youtu.be/ZI198eFghJk),
    [slides](https://chandlerc.blog/slides/2023-cppnow-compiler/index.html#/))

### 2022

-   Carbon Language: Syntax and trade-offs, Core C++
    ([video](https://youtu.be/9Y2ivB8VaIs),
    [slides](https://docs.google.com/presentation/d/1znvL12xCuEfcsP6tpPdrQPnh-UoPFOLnC_RVXZteYaM/edit))
-   Carbon Language: An experimental successor to C++, CppNorth
    ([video](https://youtu.be/omrY53kbVoA),
    [slides](https://chandlerc.blog/slides/2022-07-19-cppnorth-keynote/#/))

### Other videos

We additionally have [toolchain videos](/toolchain/docs/README.md#videos).

## Join us

We'd love to have folks join us and contribute to the project. Carbon is
committed to a welcoming and inclusive environment where everyone can
contribute.

-   Most of Carbon's design discussions occur on
    [Discord](https://discord.gg/ZjVdShJDAs).
-   To watch for major release announcements, subscribe to our
    [Carbon release post on GitHub](https://github.com/carbon-language/carbon-lang/discussions/1020)
    and [star carbon-lang](https://github.com/carbon-language/carbon-lang).
-   See our [code of conduct](CODE_OF_CONDUCT.md) and
    [contributing guidelines](CONTRIBUTING.md) for information about the Carbon
    development community.

### Contributing

You can also directly:

-   [Contribute to the language design](CONTRIBUTING.md#contributing-to-the-language-design):
    feedback on design, new design proposal
-   [Contribute to the language implementation](CONTRIBUTING.md#contributing-to-the-language-implementation)
    -   [Carbon Toolchain](/toolchain/), and project infrastructure

You can **check out some
["good first issues"](https://github.com/carbon-language/carbon-lang/labels/good%20first%20issue)**,
or join the `#contributing-help` channel on
[Discord](https://discord.gg/ZjVdShJDAs). See our full
[`CONTRIBUTING`](CONTRIBUTING.md) documentation for more details.

---

## File: docs/project/principles/error_handling.md

# Principle: Errors are values





## Table of contents

-   [Background](#background)
-   [Principle](#principle)
-   [Applications of these principles](#applications-of-these-principles)



## Background

Most nontrivial programs contain functions that can _fail_, meaning that even if
all their preconditions are met, they may not be able to perform their primary
behavior. For example, a function that reads data from a remote server may fail
if the server is unreachable, and a function that parses a string to return an
integer may fail if the input string is not a properly-formatted integer.

In many cases, the function author wants these failures to be _recoverable_,
meaning that a direct or transitive caller can respond to the failure in some
way that enables the program to continue running.

## Principle

A Carbon function that needs to report recoverable failures should return a sum
type whose alternatives represent the success case and failure cases, such as
`Optional(T)`, `Result(T, Error)`, or `bool`. The function's successful return
value, and any metadata about the failure, should be embedded in the
alternatives of the sum type, rather than reported by way of output parameters
or other side channels. Carbon's design will prioritize making this form of
error handling efficient and ergonomic.

## Applications of these principles

Carbon errors, unlike exceptions in C++ and similar languages, will not be
propagated implicitly. Instead, Carbon will very likely need to provide some
explicit but syntactically lightweight means of propagating errors, such as
Rust's `?` operator, so that error-propagation boilerplate doesn't make it hard
for readers to follow the logic of the success path.

Carbon will not have a special syntax for specifying what kind of errors a
function can emit, such as `noexcept` or
[dynamic exception specifications](https://en.cppreference.com/w/cpp/language/except_spec)
in C++, or `throws` in Java, because that information will be embedded in the
function's return type. Similarly, Carbon errors will be statically typed,
because Carbon return values are statically typed.

---

## File: docs/project/principles/information_accumulation.md

# Principle: Information accumulation





## Table of contents

-   [Background](#background)
-   [Principle](#principle)
-   [Applications of this principle](#applications-of-this-principle)
-   [Exceptions](#exceptions)
-   [Alternatives considered](#alternatives-considered)



## Background

There are many different sources of information in a program, and a tool or a
human interpreting code will not in general have full information, but will
still want to draw conclusions about the code.

Different languages take different approaches to this problem. For example:

-   In C, information is accumulated linearly in each source file independently,
    and only information from earlier in the same file is available. A program
    can observe that information is incomplete at one point and complete at
    another.
-   In C++, the behavior is largely similar to C, except:
    -   Within certain contexts in a class, information from later in the class
        definition is available.
    -   With C++20 modules, information from other source files can be made
        available.
    -   It is easier to observe -- perhaps even accidentally -- that information
        is accumulated incrementally.
-   In Rust, all information from the entire crate is available everywhere
    within that crate, with exceptions for constructs like proc macros that can
    see the state of the program being incrementally built.
-   In Swift, all information from the entire source file is available within
    that source file.

## Principle

In Carbon, information is accumulated incrementally within each source file.
Carbon programs are invalid if they would have a different meaning if more
information were available.

Carbon source files can be interpreted top-down, without referring to
information that appears substantially later in a file. Source files are
expected to be organized into a topological order where that makes sense, with
forward declarations used to introduce names before they are first referenced
when necessary.

If a program attempts to use information that has not yet been provided, the
program is invalid. There are multiple options for how this can be reported:

-   The program can be rejected as soon as it tries to use information that
    might not be known yet.
-   For the case where the information can only be provided in the same source
    file, an assumption about the information can be made at the point where it
    is needed, and the program can be rejected only if that assumption turns out
    to be incorrect.

Disallowing programs from changing meaning in the context of more information
ensures that the program is interpreted consistently or is rejected. This is
especially important to the coherence of generics and templates.

## Applications of this principle

-   As in C++, and unlike in Rust and Swift, name lookup only finds names
    declared earlier.
-   Classes are incomplete until the end of their definition. Unlike in C++, any
    attempt to observe a property of an incomplete class that is not known until
    the class is complete renders the program invalid.
-   When an `impl` needs to be resolved, only those `impl` declarations that
    appear earlier are considered. However, if a later `impl` declaration would
    change the result of any earlier `impl` lookup, the program is invalid.
-   Declarations in an API file that are insufficient for use by clients that
    import the library require a definition in the API file.
    -   Where possible, we should make declarations sufficient, so a definition
        is not required.

## Exceptions

Because a class is not complete until its definition has been fully parsed,
applying this rule would make it impossible to define most member functions
within the class definition. In order to still provide the convenience of
defining class member functions inline, such member function bodies are deferred
and processed as if they appeared immediately after the end of the outermost
enclosing class, like in C++.

## Alternatives considered

-   Allow information to be used before it is provided
    [globally](/proposals/p000875-principle-information-accumulation.md#strict-global-consistency),
    [within a file](/proposals/p000875-principle-information-accumulation.md#context-sensitive-local-consistency),
    or
    [within a top-level declaration](/proposals/p000875-principle-information-accumulation.md#top-down-with-minimally-deferred-type-checking).
-   [Do not allow inline method bodies to use members before they are declared](/proposals/p000875-principle-information-accumulation.md#strict-top-down)
-   [Do not allow separate declaration and definition](/proposals/p000875-principle-information-accumulation.md#disallow-separate-declaration-and-definition)

---

## File: docs/project/principles/library_apis_only.md

# Principle: All APIs are library APIs





## Table of contents

-   [Background](#background)
-   [Principle](#principle)
-   [Applications of this principle](#applications-of-this-principle)
-   [Exceptions](#exceptions)
-   [Alternatives considered](#alternatives-considered)



## Background

Every major modern programming language comes with a standard library, which
consists of APIs that are not part of the core language, but instead are written
in the language (although their implementations may not be). However, different
languages draw the boundary between language and library in different places.
For example, Go's `map` type is built into the core language, whereas the C++
equivalent, `std::unordered_map`, is part of the standard library. In Swift,
even fundamental types like integers and pointers are part of the standard
library; there are no truly "built in" types.

These decisions can have important consequences for the design of the language.
For example, many important features of C++, such as move semantics, variadics,
and coroutines, were motivated largely by their anticipated uses in a small set
of standard library types. In a language with a different design philosophy,
those types could have been built into the core language. This would probably
have substantially simplified the language, and made those types available
faster. However, that would have come at the cost of less flexibility for users
outside the common case.

## Principle

In Carbon, every public function is declared in some Carbon API file, and every
public `interface`, `impl`, and first-class type is defined in some Carbon API
file. In some cases, the bodies of public functions will not be defined as
Carbon code, or will be defined as hybrid Carbon code using intrinsics that
aren't available to ordinary Carbon code. However, we will try to minimize those
situations.

Thus, even "built-in" APIs can be used like user-defined APIs, by importing the
appropriate library and using qualified names from that library, relying on the
ordinary semantic rules for Carbon APIs.

## Applications of this principle

We expect Carbon to have a special "prelude" library that is implicitly imported
by all Carbon source files, and there might be a special name lookup rule to
allow the names in the prelude to be used unqualified. However, in accordance
with this principle, they will remain available to ordinary qualified name
lookup as well.

According to the resolutions of
[#543](https://github.com/carbon-language/carbon-lang/issues/543) and
[#750](https://github.com/carbon-language/carbon-lang/issues/750), Carbon will
have a substantial number of type keywords, such as `i32`, `f64`, and `bool`.
However, these keywords will all be aliases for ordinary type names, such as
`Carbon.Int(32)`, `Carbon.Float(64)`, and `Carbon.Bool`. Furthermore, all
arithmetic and logical operators will be overloadable, so that those types can
be defined as class types. The member function bodies for these types will be
probably not be implemented in Carbon, but this principle applies only to
function declarations, not function definitions.

Similarly, a pointer type such as `Foo*` will be an alias for some library class
type, for example `Carbon.Ptr(Foo)`. As a result, Carbon will support
overloading pointer operations like `->` and unary `*`.

All Carbon operations that use function-style syntax, such as `sizeof()` and
`decltype()` in C++, will be standard library functions. As above, in some cases
we may choose to alias those functions with keywords, and the function bodies
may not be defined in Carbon.

## Exceptions

This principle applies to types only if they are _first-class_, meaning that
they can be the types of run-time variables, function parameters, and return
values. Carbon's type system will probably also include some types whose usage
is more restricted, and this principle will not apply to them. Most importantly,
function types might not be first-class types, in which case they need not be
library types.

Some types (such as tuples, structs, and certain integer types) will have
built-in literal syntaxes for creating values of those types. Furthermore, in
some cases (such as tuples and structs) the type's literal syntax will also be
usable as a pattern syntax. The logic for performing those operations is
arguably part of those types' public API, but will not be part of those types'
class definitions.

## Alternatives considered

-   [Built-in primitive types](/proposals/p001280-principle-all-apis-are-library-apis.md#built-in-primitive-types)

---

## File: docs/project/principles/low_context_sensitivity.md

# Principle: Low context-sensitivity





## Table of contents

-   [Principle](#principle)
    -   [Mitigations of context-sensitive costs](#mitigations-of-context-sensitive-costs)
        -   [Visual aids](#visual-aids)
        -   [Contextual _validity_ rather than _meaning_](#contextual-validity-rather-than-meaning)
        -   [Reduced cost of mistakes](#reduced-cost-of-mistakes)
            -   [Compiler-checked context](#compiler-checked-context)
-   [Applications of the principle](#applications-of-the-principle)
    -   [Imports and namespaces](#imports-and-namespaces)
    -   [Name shadowing](#name-shadowing)
    -   [Flow-sensitive typing](#flow-sensitive-typing)
    -   [Coherence of names and generics](#coherence-of-names-and-generics)
    -   [Performance](#performance)



## Principle

Carbon should favor designs and mechanisms that are not sensitive to context.
Instead, we should favor constructs that are not ambiguous so that they don't
need context for disambiguation. This is in service to the goal that
[Carbon code is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write).
In particular, this is about prioritizing reading and understanding over
writing. We should be willing to trade off conciseness, which still benefits
reading as well as writing, for a sufficiently impactful reduction in the amount
of context needed to read and understand code.

Context can be expensive in different ways, for example:

-   It can be _large_: it might require looking through a lot of lines of code
    to find all of the relevant contextual information.
-   It can be _distant_: the further away from the current declaration or
    definition, the more expensive it is to find contextual information. This
    can scale from a separate definition in the same file, to a separate file,
    or even to a separate package.
-   It can be _unpredictable_: it might require careful searching of large
    bodies of code to locate the contextual information if its location cannot
    be predicted.
-   It can be _subtle_: the contextual clues might be easily missed or mistaken.

Code that isn't context sensitive is easier to copy or move between contexts,
like files or functions. It is code that needs fewer changes when it is
refactored, in support of
[software evolution](/docs/project/goals.md#software-and-language-evolution).

In general, we should start with more restrictive constructs that limit
ambiguity and see if we can make them work. If we find those restrictions are
burdensome, we will then have more information to inform the next step. Ideally
we would address those use cases with simple tools that solve multiple problems.
The goal is to make a bunch of orthogonal mechanisms, each of which are easily
understood and act in unsurprising ways.

If that next step is to loosen restrictions, that is generally easier to do
while maintaining compatibility with existing code than adding new restrictions.

### Mitigations of context-sensitive costs

There are several ways that the potential costs of context-sensitive code can be
mitigated. These techniques can and should be leveraged to help minimize and
mitigate the contextual costs of Carbon features, and in some cases may provide
a path to a feature that would otherwise be prohibitively costly.

#### Visual aids

A direct way to reduce contextual costs is through lexical and syntactic
structures that form visual aids. These can both reinforce what the context is
and aid the reader in the expensive aspect of navigating the context. For
example, representing contexts with indentation, or IDE highlighting of matching
parentheses and braces. These visual hints make it easier for developers to
notice contextual elements.

#### Contextual _validity_ rather than _meaning_

When the context only affects the _validity_ of code, but not its meaning, the
costs are significantly reduced. In that case, understanding the meaning or
behavior of the code doesn't require context, and a developer can easily rely on
the compiler to check the validity. A simple example of this is contextually
valid syntax, which is relatively common and inexpensive. However, reusing the
same syntax with different contexts _with different meanings_ shifts the
contextual information from simple validity to impacting the meaning of code.

#### Reduced cost of mistakes

Another mitigation for the costs of context-sensitive code is when the cost of a
mistake due to the context is low. Some simple examples:

-   Context-sensitivity in comments is less expensive in general than in code.
-   In places where the general meaning is clear, developers can safely and
    reliably work with that general understanding, and the context only provides
    a minor refinement.

##### Compiler-checked context

Another way the costs of mistakes can be reduced is when the compiler can
reliably detect them. This is the fundamental idea behind statically
type-checked languages: the compiler enforcement reduces the contextual cost of
knowing what the types are. How early and effectively the compiler can detect
the mistakes also plays a role in reducing this cost, which is part of the value
proposition for
[definition-checked](/docs/design/generics/terminology.md#definition-checking)
generics.

An example of this situation in Rust is that the same syntax is used for a move
and a copy of the value in a variable. Those cases are distinguished by whether
the type implements a specific trait, which may not be readily ascertained. The
compiler verifies that the code never uses a variable that is no longer valid
due to having been moved from, which is expected to catch the problems that
could arise from this difference. Otherwise the semantic difference between a
move and a copy is considered in Rust to be low-enough stakes for there to be no
need to signal that difference in the code.

However, the reasoning that makes this example a good design on balance for Rust
doesn't necessarily apply to Carbon. The compiler is checking to prevent
_errors_, but it can't reliably check for unpredictable _performance_. Given
Carbon's priorities, that might make this level of contextual information still
too expensive.

More background on this area of Rust specifically is presented in
[their blog post on language ergonomics](https://blog.rust-lang.org/2017/03/02/lang-ergonomics.html).

## Applications of the principle

There are many parts of Carbon that could potentially be analyzed through this
lens, and we can't enumerate them all here. This section focuses on several
examples to help illustrate how the principle is likely to be relevant to
Carbon. They focus on either cases that showcase the principle in effect or
cases which make challenging tradeoffs of the costs in the principle.

### Imports and namespaces

There are several parts of the way
[imports](/docs/design/code_and_name_organization/#imports) and
[namespaces](/docs/design/code_and_name_organization/#namespaces) are designed
in Carbon that reflect applications of this principle:

-   Adding an import or reordering imports should never change behavior of
    existing code. This means the reader doesn't have to look through all the
    imports to understand how code behaves. This is also important for tooling,
    which should not have to worry about unwanted side effects when adding or
    sorting imports.

-   Carbon doesn't provide an analogy to C++'s
    [`using namespace`](https://en.cppreference.com/w/cpp/language/namespace#Using-directives)
    or a
    ["wildcard imports" mechanisms](/proposals/p000107-code-and-name-organization.md#broader-imports-either-all-names-or-arbitrary-code)
    that merge the names from one namespace into another. Either would introduce
    ambiguity in where a name is coming from, making the code more
    context-sensitive.

-   Carbon doesn't support large blocks of code
    [inside a namespace declaration](/proposals/p000107-code-and-name-organization.md#scoped-namespaces),
    where the reader would have to search for the beginning of the block to see
    what namespace applies.

### Name shadowing

We should limit how names can be reused with shadowing rules, so the meaning of
a name doesn't change in surprising ways between scopes. Further, if you find a
matching declaration you don't have to keep searching to see if there is another
that hides the one you found. This both expands the context you have to
consider, and is an opportunity to make a mistake identifying the correct
context, potentially leading to misunderstanding of the code.

### Flow-sensitive typing

This principle is an argument against
[flow-sensitive typing](https://en.wikipedia.org/wiki/Flow-sensitive_typing),
where the type of a name can change depending on control flow. For example,
[Midori used this for optional types](http://joeduffyblog.com/2016/02/07/the-error-model/#the-syntax).
If we were to support this in Carbon, you could unwrap an optional value by
testing it against `None`.

```
var x: Optional(Int) = ...;
if (x != None) {
  // x has type Int.
  PrintInt(x);
}
// x is back to type Optional(Int).
```

This can be taken farther, this example has `x` taking on three different types:

```
var x: Optional(Optional(Int)) = ...;
if (x != None) {
  // x has type Optional(Int).
  if (x != None) {
    // x has type Int.
    PrintInt(x);
  }
  // x has type Optional(Int).
}
// x has type Optional(Optional(Int)).
```

The concern here is that the context is very subtle. The type of `x` is affected
by otherwise ordinary-looking `if` statements and closing braces (`}`).

While we might not want to completely eliminate the possibility of
flow-sensitive typing in Carbon, it would have to overcome a large hurdle. We
would only want a flow-sensitive feature if it delivered sufficiently large
usability, consistency, or expressivity gains.

### Coherence of names and generics

Carbon [packages](/docs/design/code_and_name_organization/#packages) are
designed to ensure all declared names belong to exactly one package and the
compiler can enforce Carbon's equivalent
[one-definition rule (ODR)](https://en.wikipedia.org/wiki/One_Definition_Rule).
This avoids an issue in C++ where the ODR is not reliably checked by the
compiler, which can leave the correctness of programs dependent on both distant
and subtle contextual information.

Similarly, Carbon generics should have
[coherence, like Rust](https://github.com/Ixrec/rust-orphan-rules#what-is-coherence),
where types have a single implementation of an interface. And this should be
enforced by the compiler, using rules like
[Rust's orphan rules](https://github.com/Ixrec/rust-orphan-rules#what-are-the-orphan-rules).

### Performance

Since
[Carbon's number one goal is performance](/docs/project/goals.md#performance-critical-software),
it is important that the performance characteristics of code be predictable and
readily determined by readers. This argues that those characteristics should not
depend on expensive context. For example, Carbon should not provide a
`dynamic_cast` facility with the same capabilities of C++'s where distant
aspects of the inheritance structure can cause surprising performance
differences. Similarly, Carbon should try to ensure normal looking method calls
and data member access don't have the surprising performance costs caused by
virtual inheritance in C++.

More generally, Carbon should avoid features with hidden costs, particularly
when they scale based on subtle aspects of the context where those features are
used.

---

## File: docs/project/principles/namespace_cleanliness.md

# Principle: Namespace cleanliness





## Table of contents

-   [Background](#background)
-   [Principle](#principle)
-   [Applications of this principle](#applications-of-this-principle)
-   [Exceptions](#exceptions)
-   [Alternatives considered](#alternatives-considered)



## Background

Names and entities in a program can come from multiple sources -- from a local
declaration, from an import, from the standard library, or from the prelude.
Names can be imported from Carbon code or imported or derived from code written
in another language such as C++ or an interface description language such as
that of Protobuf, MIDL, or CORBA. Names can be selected for use in a program
that language designers later decide they want to use as keywords. And in order
to use a library, it is sometimes necessary to redeclare the same name that that
library chose.

This puts a lot of pressure on the language to support a free choice of naming
for entities. Different languages make different choices in this space:

-   Many languages have a set of keywords that are not usable as identifiers,
    with no workaround. If this set collides with a name needed by user code,
    the user is left to solve this problem, often by rewriting the identifier in
    some way (`klass` or `class_`), which sometimes conflicts with the general
    naming convention used by the code. And conversely, suboptimal choices are
    made for new language keywords to avoid causing problems for existing code.
-   C and C++ reserve a family of identifiers, such as those beginning with an
    underscore and a capital letter. However, it's not clear which audiences the
    reserved identifiers are for, and this leads to collisions between standard
    library vendors and compiler authors, as well as between implementation
    extensions and language extensions.
    -   MSVC provides a `__identifier(keyword)` extension that allows using a
        keyword as an identifier. This extension is also implemented by Clang in
        `-fms-extensions` mode.
    -   GCC provides an `__asm__(symbol)` extension that allows a specific
        symbol to be assigned to an object or function, which provides ABI
        compatibility but not source compatibility with code that uses a keyword
        as a symbol name. This extension is also implemented by Clang.
-   Python reserves some identifiers but still allows them to be freely
    overwritten (such as `bool`) and reserves some identifiers but rejects
    assignment to them (such as `True`).
-   Rust provides a raw identifier syntax to allow most identifiers with
    reserved meaning to be used by a program, but
    [not all](https://internals.rust-lang.org/t/raw-identifiers-dont-work-for-all-identifiers/9094):
    `self`, `Self`, `super`, `extern`, and `crate` cannot be used as raw
    identifiers. Rust also predeclares a large number of library names in every
    file, but allows them to be shadowed by user declarations with the same
    name.
-   Swift provides a raw identifier syntax using backticks: `` `class` ``, and
    is
    [considering](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0451-escaped-identifiers.md)
    extending this to allow arbitrary non-word-shaped character sequences
    between the `` ` ``s.

Carbon provides
[raw identifier syntax](/docs/design/lexical_conventions/words.md#raw-identifiers),
for example `r#for`, to allow using keywords as identifiers. Carbon also intends
to have strict shadowing rules that may make predeclared identifiers that are
_not_ keywords difficult or impossible to redeclare and use in inner scopes.

## Principle

In Carbon, the language does not encroach on the developer's namespace. There
are no predeclared or reserved identifiers. In cases where the language gives
special meaning to a word or to word-shaped syntax such as `i32`, that special
meaning can always be undone with raw identifier syntax, `r#`.

Conversely, when adding language keywords, we will not select an inferior
keyword merely to avoid the risk of breaking existing programs. We will still
take into account how often it is desirable to use the word as an identifier,
including in domain-specific contexts, because that is a factor in whether it
would make a good keyword, and will manage the rollout of new keywords to make
it straightforward to migrate existing uses to `r#` or a different name.

## Applications of this principle

-   Words like `final` and `base` that only have special meaning in a few
    contexts, and could otherwise be made available as identifiers, are keywords
    in Carbon. `{.base = ...}` and `{.r#base = ...}` specify different member
    names.
-   Words like `self` that are declared by the developer but nonetheless have
    special language-recognized meaning are keywords in Carbon. `(self)`
    introduces a self parameter; `(r#self: Self)` introduces a parameter with
    the name `self` as a raw identifier.
-   Words like `Self` that are implicitly declared by the language in some
    contexts are keywords, even though we could treat them as user-declared
    identifiers that are merely implicitly declared in some cases.
-   Words like `i32` that are treated as type literals rather than keywords can
    be used as identifiers with raw identifier syntax `r#i32`.
-   There are no predeclared identifiers imported from the prelude. If an entity
    is important enough to be available by default, we should add a keyword, and
    allow the name of the entity to be used for other purposes with `r#`.
-   The predeclared package name `Core` is a keyword. A package named `r#Core`
    is an unrelated package, and `Core.foo` always refers to members of the
    predeclared `Core` package.

## Exceptions

For now, we reserve the package names `Main` and `Cpp`. These names aren't
predeclared in any scope, and the name `Main` is not even usable from within
source files to refer to the main package. However, there is currently no way to
avoid collisions between the package name `Cpp` and a top-level entity named
`Cpp` if they are both used in the same source file.

## Alternatives considered

-   [Have both predeclared identifiers and keywords](/proposals/p004864-no-predeclared-identifiers-core-is-a-keyword.md#have-both-predeclared-identifiers-and-keywords)
-   [Reserve words with a certain spelling](/proposals/p004864-no-predeclared-identifiers-core-is-a-keyword.md#reserve-words-with-a-certain-spelling)

---

## File: docs/project/principles/one_way.md

# Principle: Prefer providing only one way to do a given thing





## Table of contents

-   [Background](#background)
-   [Principle](#principle)
-   [Applications of this principle](#applications-of-this-principle)
-   [Caveats](#caveats)
    -   [Specialized syntax](#specialized-syntax)
    -   [Non-obvious alternatives](#non-obvious-alternatives)
    -   [In evolution](#in-evolution)
-   [Alternatives considered](#alternatives-considered)



## Background

It's common in programming languages to provide multiple, similar ways of doing
the same thing. Sometimes this reflects the legacy of a language, and
difficulties in evolving in ways that would require changes to
developer-authored code, thereby retaining backwards compatibility. Other times
it reflects a desire to provide both verbose and concise versions of the same
syntax. We are concerned with both forms.

We also are cautious about creating alternatives that may give rise to a
[paradox of choice](https://en.wikipedia.org/wiki/The_Paradox_of_Choice),
wherein options are similar enough that developers actively spend time analyzing
trade-offs, and the time spent that way outweighs the potential benefits of a
correct choice.

Where multiple, similar implementation options exist, it can sometimes give rise
to style guidelines to indicate a preferential choice; sometimes because one
option is objectively better, but sometimes because making a choice is better
than not making one. Even with a style guide, developers may diverge in style by
accident or intent, choosing different coding patterns simply because either
option works. It can also become an issue as developers move between an
organization that they need to learn a new style guide, and relearn habits.

A couple examples of this in other languages are:

-   In Perl,
    ["There is more than one way to do it."](https://en.wikipedia.org/wiki/There%27s_more_than_one_way_to_do_it)
-   In Python,
    ["There should be one -- and preferably only one -- obvious way to do it."](https://www.python.org/dev/peps/pep-0020/)

## Principle

In Carbon, we will prefer providing only one way to do a given thing. That is,
given a syntax scenario where multiple design options are available, we will
tend to provide _one_ option rather than providing several and letting users
choose. This echoes Python's principle.

Minimizing choices serves several goals:

-   [Language tools](/docs/project/goals.md#language-tools-and-ecosystem) should
    be easier to write and maintain with the lower language complexity implied
    by less duplication of functionality.
-   [Software and language evolution](/docs/project/goals.md#software-and-language-evolution)
    processes should find it easier to both consider existing syntax and avoid
    creation of new syntax conflicts.
-   [Understandability of code](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write)
    should be promoted if developers have less syntax they need to understand.
    This can be expected to improve code quality and productivity so long as the
    resulting code structures aren't overly complicated.

By minimizing the overlap of language features, we hope to make work easier for
both Carbon's maintainers and developers.

## Applications of this principle

We can observe the application of this principle by comparing several language
features to C++. There, improving understandability is frequently the primary
motivation:

-   Where C++ allows logical operators to be written with either symbols (for
    example, `&&`) or text (for example, `and`), Carbon will only support one
    form (in this case, [text](/proposals/p000680-and-or-not.md)).
-   Where C++ allows hexadecimal numeric literals to be either lowercase
    (`0xaa`) or uppercase (`0xAA`), and with `x` optionally uppercase as well,
    Carbon will only allow the
    [`0xAA` casing](/proposals/p000143-numeric-literals.md).
-   Where C++ provides both `struct` and `class` with the only difference is
    access control defaults, Carbon will only provide one (`class`, albeit with
    default public visibility diverging from C++).

However, sometimes language tools are the primary motivation. For example, where
C++ allows braces to be omitted for single-statement control flow blocks, Carbon
will [require braces](/proposals/p000623-require-braces.md). This offers a
syntax simplification that should allow for better error detection.

## Caveats

### Specialized syntax

Sometimes overlap will occur because a specialized syntax offers particular
benefits, typically as a matter of convenience for either a common use-case or a
particularly complex and important use-case. Some examples of why and where this
occurs are:

-   For [performance](/docs/project/goals.md#performance-critical-software), it
    may at times be necessary to provide a specialized syntax that better
    supports optimization than a generic syntax.
-   For
    [understandability of code](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write),
    there may be times that a particular use-case is common enough that
    simplifying its syntax provides substantial benefit.
    -   For example, `for (var x: auto in list)` could typically be written with
        as a `while` loop, but range-based for loops are considered to improve
        understandability. However, C++'s `for (;;)` syntax is sufficiently
        close to `while` that we expect to use `while` to address the
        corresponding use-cases.
-   For
    [migration and interoperability](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code),
    it may be pragmatic to provide both an ideal way of doing things for new
    Carbon code, and a separate approach that is more C++-compatible for
    migration.
    -   For example, consider generics and templates: generics are considered to
        be the preferred form for new code, but templates are considered a
        necessity for migration of C++ code. This is not an evolution situation
        because we do not anticipate ever removing templates.

### Non-obvious alternatives

Echoing Python, there may be non-obvious alternative ways of doing a given
thing, such as using `while (condition) { DoSomething(); break; }` in place of
`if (condition) { DoSomething(); }`. As a more complex example, lambdas could be
implemented using other code constructs; this would require significantly more
code and hinder understandability.

This kind of overlap may exist, but will hopefully be considered sufficiently
non-idiomatic that examples won't be common in code. If a choice would not
likely be based mainly on coding styles, it's likely sufficiently distinct that
this principle won't apply.

### In evolution

For [evolution](/docs/project/goals.md#software-and-language-evolution), it will
often be necessary to temporarily provide an "old" and "new" way of doing things
simultaneously.

For example, if renaming a language feature, it may be appropriate to provide
the same functionality under two identifiers. However, one should be marked as
deprecated and eventually removed. We should be cautious of adding new,
overlapping features without a plan to remove the corresponding legacy version.

## Alternatives considered

-   [Provide multiple ways of doing a given thing](/proposals/p000829-one-way-principle.md#provide-multiple-ways-of-doing-a-given-thing)

---

## File: docs/project/principles/README.md

# Principles



Some language [goals](../goals.md) will have widely-applicable, high-impact, and
sometimes non-obvious corollaries. We collect concrete language design
principles in this directory as a way to document and clarify these. Principles
clarify, but do not supersede, goals and priorities. Principles should be used
as a tool in making decisions, and to clarify to contributors how decisions are
expected to be made.

A key difference between a principle and the design of a language feature is
that a principle should inform multiple designs, whereas a feature's design is
typically more focused on achieving a specific goal or set of goals. The
principle can help achieve consistency across those multiple designs.

Note that these principles seek to establish both the approaches the project
wants to pursue, as well as those we want to exclude.

-   [Errors are values](error_handling.md)
-   [Information accumulation](information_accumulation.md)
-   [Low context-sensitivity](low_context_sensitivity.md)
-   [Prefer providing only one way to do a given thing](one_way.md)
-   [One static open extension mechanism](static_open_extension.md)
-   [Success criteria](success_criteria.md)
-   [File concatenation](file_concatenation.md)

---

## File: docs/project/principles/safety_strategy.md

# Safety strategy





## Table of contents

-   [Background](#background)
    -   [What "safety" means in Carbon](#what-safety-means-in-carbon)
    -   [Safety guarantees versus hardening](#safety-guarantees-versus-hardening)
-   [Philosophy](#philosophy)
-   [Principles](#principles)
-   [Details](#details)
    -   [Incremental work when safety requires work](#incremental-work-when-safety-requires-work)
    -   [Using build modes to manage safety checks](#using-build-modes-to-manage-safety-checks)
        -   [Debug](#debug)
        -   [Performance](#performance)
        -   [Hardened](#hardened)
    -   [Managing bugs without compile-time safety](#managing-bugs-without-compile-time-safety)
-   [Caveats](#caveats)
    -   [Probabilistic techniques likely cannot stop attacks](#probabilistic-techniques-likely-cannot-stop-attacks)
-   [Alternatives considered](#alternatives-considered)
    -   [Guaranteed memory safety programming models](#guaranteed-memory-safety-programming-models)
        -   [Guaranteed compile-time memory safety using borrow checking](#guaranteed-compile-time-memory-safety-using-borrow-checking)
        -   [Guaranteed run-time memory safety using reference counting](#guaranteed-run-time-memory-safety-using-reference-counting)
        -   [Guaranteed run-time memory safety using garbage collection](#guaranteed-run-time-memory-safety-using-garbage-collection)
    -   [Build mode names](#build-mode-names)
    -   [Performance versus safety in the hardened build mode](#performance-versus-safety-in-the-hardened-build-mode)
    -   [Add more build modes](#add-more-build-modes)



## Background

Carbon's goal is to provide
[practical safety and testing mechanisms](../goals.md#practical-safety-and-testing-mechanisms).

### What "safety" means in Carbon

Safety is protection from software bugs, whether the protection is required by
the language or merely an implementation option. Application-specific logic
errors can be prevented by testing, but can lead to security vulnerabilities in
production. Safety categories will be referred to using names based on the type
of
[security vulnerability](<https://en.wikipedia.org/wiki/Vulnerability_(computing)#Software_vulnerabilities>)
they protect against.

A key subset of safety categories Carbon should address are:

-   [**Memory safety**](https://en.wikipedia.org/wiki/Memory_safety) protects
    against invalid memory accesses. Carbon uses
    [two main subcategories](https://onlinelibrary.wiley.com/doi/full/10.1002/spe.2105)
    for memory safety:

    -   _Spatial_ memory safety protects against accessing an address that's out
        of bounds for the source. This includes array boundaries, as well as
        dereferencing invalid pointers such as uninitialized pointers, `NULL` in
        C++, or manufactured pointer addresses.

    -   _Temporal_ memory safety protects against accessing an address that has
        been deallocated. This includes use-after-free for heap and
        use-after-return for stack addresses.

-   [**Type safety**](https://en.wikipedia.org/wiki/Type_safety) protects
    against accessing valid memory with an incorrect type, also known as "type
    confusion".

-   [**Data race safety**](https://en.wikipedia.org/wiki/Race_condition#Data_race)
    protects against racing memory access: when a thread accesses (read or
    write) a memory location concurrently with a different writing thread and
    without synchronizing.

### Safety guarantees versus hardening

In providing safety, the underlying goal is to prevent attacks from turning a
_logic error_ into a _security vulnerability_. The three ways of doing this can
be thought of in terms of how they prevent attacks:

-   **Safety guarantees** prevent bugs. They offer a strong requirement that a
    particular security vulnerability cannot exist. Compile-time safety checks
    are always a safety guarantee, but safety guarantees may also be done at
    runtime. For example:

    -   At compile-time, range-based for loops offer a spatial safety guarantee
        that out-of-bounds issues cannot exist in the absence of concurrent
        modification of the sequence.

    -   At runtime, garbage collected languages offer a temporal safety
        guarantee because objects cannot be freed while they're still
        accessible.

-   **Error detection** checks for common logic errors at runtime. For example:

    -   An array lookup function might offer spatial memory error detection by
        verifying that the passed index is in-bounds.

    -   A program can implement reference counting to detect a temporal memory
        error by checking whether any references remain when memory is freed.

-   **Safety hardening** mitigates bugs, typically by minimizing the feasibility
    of an attack. For example:

    -   [Control Flow Integrity (CFI)](https://en.wikipedia.org/wiki/Control-flow_integrity)
        monitors for behavior which can subvert the program's control flow. In
        [Clang](http://clang.llvm.org/docs/ControlFlowIntegrity.html), it is
        optimized for use in release builds. Typically CFI analysis will only
        detect a subset of attacks because it can't track each possible code
        path separately. It should still reduce the feasibility of both spatial
        memory, temporal memory, and type attacks.

    -   [Memory tagging](https://llvm.org/devmtg/2018-10/slides/Serebryany-Stepanov-Tsyrklevich-Memory-Tagging-Slides-LLVM-2018.pdf)
        makes each attempt at an invalid read or write operation have a high
        probability of trapping, while still not detecting the underlying bug in
        every case. Realistic attacks require many such operations, so memory
        tagging may stop attacks in some environments. Alternatively, the trap
        might be asynchronous, leaving only a tiny window of time prior to the
        attack being detected and program terminated. These are probabilistic
        hardening and reduces the feasibility of both spatial and temporal
        memory attacks.

Under both error detection and safety hardening, even if a safety is protected,
the underlying bugs will still exist and will need to be fixed. For example,
program termination could be used for a denial-of-service attack.

## Philosophy

Carbon's
[practical safety and testing mechanisms](../goals.md#practical-safety-and-testing-mechanisms)
will emphasize guaranteed safety where feasible without creating barriers to
Carbon's [other goals](../goals.md), particularly performance and
interoperability. This limits Carbon's options for guaranteed safety, and as a
result there will be more reliance upon error detection and safety hardening.
The language's design should incentivize safe programming, although it will not
be required.

When writing code, Carbon developers should expect to receive safety without
needing to add safety annotations. Carbon will have optional safety annotations
for purposes such as optimizing safety checks or providing information that
improves coverage of safety checks.

Carbon will favor compile-time safety checks because catching issues early will
make applications more reliable. Runtime checks, either error detection or
safety hardening, will be enabled where safety cannot be proven at compile-time.

There will be three high-level use cases or directions that Carbon addresses
through different build modes that prioritize safety checks differently:

-   A [debug](#debug) oriented build mode that prioritizes detecting bugs and
    reporting errors helpfully.
-   A [performance](#performance) oriented build mode that skips any dynamic
    safety checks to reduce overhead.
-   A [hardened](#hardened) oriented build mode that prioritizes ensuring
    sufficient safety to prevent security vulnerabilities, although it may not
    allow detecting all of the bugs.

These high level build modes may be tuned, either to select specific nuanced
approach for achieving the high level goal, or to configure orthogonal
constraints such as whether to prioritize binary size or execution speed.
However, there is a strong desire to avoid requiring more fundamental build
modes to achieve the necessary coverage of detecting bugs and shipping software.
These build modes are also not expected to be interchangeable or compatible with
each other within a single executable -- they must be a global selection.

Although expensive safety checks could be provided through additional build
modes, Carbon will favor safety checks that can be combined into these three
build modes rather than adding more.

Over time, safety should [evolve](../goals.md#software-and-language-evolution)
using a hybrid compile-time and runtime safety approach to eventually provide a
similar level of safety to a language that puts more emphasis on guaranteed
safety, such as
[Rust](#guaranteed-compile-time-memory-safety-using-borrow-checking). However,
while Carbon may _encourage_ developers to modify code in support of more
efficient safety checks, it will remain important to improve the safety of code
for developers who cannot invest into safety-specific code modifications.

## Principles

-   Safety must be
    [easy to ramp-up with](../goals.md#code-that-is-easy-to-read-understand-and-write),
    even if it means new developers don't receive the full safety that Carbon
    can offer.

    -   Developers should benefit from Carbon's safety without needing to learn
        and apply Carbon-specific design patterns. Some safety should be enabled
        by default, without safety-specific work, although some safety will
        require work to opt in. Developers concerned with performance should
        only need to disable safety in rare edge-cases.

    -   Where there is a choice between safety approaches, the safe option
        should be incentivized by making it equally easy or easier to use. If
        there is a default, it should be the safe option. It should be
        identifiable when the unsafe option is used. Incentives will prioritize,
        in order:

        1.  Guaranteed safety.
        2.  Error detection.
        3.  Safety hardening.
        4.  Unsafe and unmitigated code.

    -   Language design choices should favor more efficient implementations of
        safety checks. They should also allow favor automation of testing and
        fuzzing.

-   Safety in Carbon must work with
    [interoperable or migrated C++ code](../goals.md#interoperability-with-and-migration-from-existing-c-code),
    so that C++ developers can readily take advantage of Carbon's improvements.

    -   Safety mechanisms will ideally be designed to apply to automatically
        migrated C++ code. Providing immediate safety improvements to Carbon
        adopters will help motivate adoption.

    -   In the other direction, safety mechanisms must not force manual
        rewriting of C++ code in order to migrate, either by creating design
        incompatibilities or performance degradations. Automated migration of
        C++ code to Carbon must work for most developers, even if it forces
        Carbon's safety design to take a different approach.

    -   Carbon's safety should degrade gracefully when Carbon code calls C++
        code, although this may require use of the Carbon toolchain to compile
        the C++ code. Applications should be expected to use interoperability.
        Although some safety features will be Carbon-specific, safety should not
        stop at the language boundary.

-   The rules for determining whether code will pass compile-time safety
    checking should be articulable, documented, and easy to understand.

    -   Compile-time safety checks should not change significantly across
        different build modes. The purpose of the build modes is to determine
        code generation.

-   Each build mode will prioritize performance and safety differently:

    -   The [debug build mode](#debug) will produce development-focused binaries
        that prioritize fast iteration on code with safety checks that assist in
        identification and debugging of errors.

    -   The [performance build mode](#performance) will produce release-focused
        binaries that prioritize performance over safety.

    -   The [hardened build mode](#hardened) will produce release-focused
        binaries that prioritize safety that is resistant to attacks at the cost
        of performance.

-   Safety checks should try to be identical across build modes.

    -   There will be differences, typically due to performance overhead and
        detection rate trade-offs of safety check algorithms.

-   The number of build modes will be limited, and should be expected to remain
    at the named three.

    -   Most developers will use two build modes in their work: debug for
        development, and either performance or hardened for releases.

    -   It's important to focus on checks that are cheap enough to run as part
        of normal development. Users are not expected to want to run additional
        development build modes for additional sanitizers.

    -   Limiting the number of build modes simplifies support for both Carbon
        maintainers, who can focus on a more limited set of configurations, and
        Carbon developers, who can easily choose which is better for their
        use-case.

-   Each distinct safety-related build mode (debug, performance, and hardened)
    cannot be combined with others in the same binary.

    -   Cross-binary interfaces will exist in Carbon, and will need to be used
        by developers interested in combining libraries built under different
        build modes.

-   Although runtime safety checks should prevent logic errors from turning into
    security vulnerabilities, the underlying logic errors will still be bugs.
    For example, some safety checks would result in application termination;
    this prevents execution of unexpected code and still needs to be fixed.

-   Developers need a strong testing methodology to engineer correct software.
    Carbon will encourage testing and then leverage it with the checking build
    modes to find and fix bugs and vulnerabilities.

## Details

### Incremental work when safety requires work

Carbon is prioritizing usability of the language, particularly minimizing
retraining of C++ developers and easing migration of C++ codebases, over the
kind of provable safety that some other languages pursue, particularly Rust.

A key motivation of Carbon is to move C++ developers to a better, safer
language. However, if Carbon requires manually rewriting or redesigning C++ code
in order to maintain performance, it creates additional pressure on C++
developers to learn and spend time on safety. Safety will often not be the top
priority for developers; as a result, Carbon must be thoughtful about how and
when it forces developers to think about safety.

Relying on multiple build modes to provide safety should fit into normal
development workflows. Carbon can also have features to enable additional
safety, so long as developers can start using Carbon in their applications
_without_ learning new paradigms.

Where possible, safety checks shouldn't require work on the part of Carbon
developers. A safety check that requires no code edits or can be handled by
automated migration may be opt-out, as there is negligible cost to developers.
One which requires local code changes should be opt-in because costs will scale
with codebase size. Safety check approaches which would require substantial
redesign by developers will be disfavored based on adoption cost, even if the
alternative is a less-comprehensive approach.

### Using build modes to manage safety checks

Carbon will likely start in a state where most safety checks are done at
runtime. However, runtime detection of safety violations remains expensive. In
order to make as many safety checks as possible available to developers, Carbon
will adopt a strategy based on three build modes that target key use-cases.

#### Debug

The debug build mode targets developers who are iterating on code and running
tests. It will emphasize detection and debuggability, especially for safety
issues.

It needs to perform well enough to be run frequently by developers, but will
make performance sacrifices to catch more safety issues. This mode should have
runtime checks for the most common safety issues, but it can make trade-offs
that improve performance in exchange for less frequent, but still reliable,
detection. Developers should do most of their testing in this build mode.

The debug build mode will place a premium on the debuggability of safety
violations. Where safety checks rely on hardening instead of guaranteed safety,
violations should be detected with a high probability per single occurrence of
the bug. Detected bugs will be accompanied by a detailed diagnostic report to
ease classification and root cause identification.

#### Performance

The performance build mode targets the typical application that wants high
performance from Carbon code, where performance considers processing time,
memory, and disk space. Trade-offs will be made that maximize the performance.

Only safety techniques that don't measurably impact application hot path
performance will be enabled by default. This is a very high bar, but is crucial
for meeting Carbon's performance goals, as well as allowing migration of
existing C++ systems which may not have been designed with Carbon's safety
semantics in mind.

#### Hardened

The hardened build mode targets applications where developers want strong safety
against attacks in exchange for worse performance. It will work to prevent
attacks in ways that
[attackers cannot work around](#probabilistic-techniques-likely-cannot-stop-attacks),
even if it means using techniques that create significant performance costs.

### Managing bugs without compile-time safety

Carbon's reliance on runtime checks will allow developers to manage their
security risk. Developers will still need to reliably find and fix the
inevitable bugs, including both safety violations and regular business logic
bugs. The cornerstone of managing bugs will be strong testing methodologies,
with built-in support from Carbon.

Strong testing is more than good test coverage. It means a combination of:

-   Ensuring unsafe or risky operations and interfaces can easily be recognized
    by developers.

-   Using static analysis tools to detect common bugs, and ensuring they're
    integrated into build and code review workflows. These could be viewed as
    static testing of code.

-   Writing good test coverage, including unit, integration, and system tests.

-   Implementing coverage-directed fuzz testing to discover bugs outside of
    manually authored test coverage, especially for interfaces handling
    untrusted data. Fuzz testing is a robust way to catch bugs when APIs may be
    used in ways developers don't consider.

-   Running continuous integration, including automatic and continuous running
    of these tests. The checked development build mode should be validated, as
    well as any additional build modes necessary to cover different forms of
    behavior checking.

-   Easing automated testing and fuzzing through language features. For example,
    if the language encourages value types and pure functions of some sort, they
    can be automatically fuzzed.

These practices are necessary for reliable, large-scale software engineering.
Maintaining correctness of business logic over time requires continuous and
thorough testing. Without it, such software systems cannot be changed and
evolved over time reliably. Carbon will reuse these practices in conjunction
with checking build modes to mitigate the limitations of Carbon's safety
guarantees without imposing overhead on production systems.

When a developer chooses to use Carbon, adhering to this kind of testing
methodology is essential for maintaining safety. As a consequence, Carbon's
ecosystem, including the language, tools, and libraries, will need to directly
work to remove barriers and encourage the development of these methodologies.

The reliance on testing may make Carbon a poor choice in some environments; in
environments where such testing rigor is infeasible, a language with a greater
degree of static checking may be better suited.

## Caveats

### Probabilistic techniques likely cannot stop attacks

It's expected that probabilistic techniques that can be applied at the language
level are attackable through a variety of techniques:

-   The attacker might be able to attack repeatedly until it gets through.
-   The attacker may be able to determine when the attack would be detected and
    only run the attack when it would not be.
-   The attacker might be able control the test condition to make detection much
    less likely or avoid detection completely. For example, if detection is
    based on the last 4 bits of a memory address, an attacker may be able to
    generate memory allocations, viewing the address and only attacking when
    there's a collision.

Hardware vulnerabilities may make these attacks easier than they might otherwise
appear. Future hardware vulnerabilities are difficult to predict.

Note this statement focuses on what can be applied to the language level. Using
a secure hash algorithm, such as SHA256, may be used to offer probabilistic
defense in other situations. However, the overhead of a secure hash algorithm's
calculation is significant in the context of most things that Carbon may do at
the language level.

Combining these issues, although it may seem like a probabilistic safety check
could be proven to reliably detect attackers, it's likely infeasible to do so.
For the various build modes, this means:

-   The debug build mode will not typically be accessible to attackers, so where
    a probabilistic technique provides a better developer experience, it will be
    preferred.
-   The performance build mode will often avoid safety checks in order to reach
    peak performance. As a consequence, even the weak protection of a
    probabilistic safety check may be used in order to provide _some_
    protection.
-   The hardened build mode will prefer non-probabilistic techniques that
    _cannot_ be attacked.

## Alternatives considered

### Guaranteed memory safety programming models

Multiple approaches that would offer guaranteed memory safety have been
considered, mainly based on other languages which offer related approaches.
Carbon will likely rely more on error detection and hardening because of what
the models would mean for Carbon's performance and C++ migration language goals.

#### Guaranteed compile-time memory safety using borrow checking

Rust offers a good example of an approach for compile-time safety based on
borrow checking, which provides guaranteed safety. For code which can't
implement borrow checking, runtime safety using reference counting is available
and provides reliable error detection. This approach still allows for
[`unsafe` blocks](https://doc.rust-lang.org/rust-by-example/unsafe.html), as
well as types that offer runtime safety while wrapping `unsafe` interfaces.

Carbon could use a similar approach for guaranteed safety by default.

Advantages:

-   Guaranteed safety, including against data races, is provided for the
    binaries.
    -   The emphasis on compile-time safety limits the scope of the runtime
        memory safety costs.
    -   With Rust, there is early evidence that there's a significant impact in
        reducing bugs generally.
-   Imitating Rust's techniques would allow building on the huge work of the
    Rust community, reducing the risks of implementing similar in Carbon.
-   Careful use of narrow `unsafe` escape hatches can be effectively
    encapsulated behind otherwise safe APIs.

Disadvantages:

-   Rust's approach to compile-time safety requires use of
    [design patterns and idioms](https://github.com/rust-unofficial/patterns)
    that are substantially different from C++.
    -   Conversion of C++ code to Rust results in either rewrites of code, or
        use of runtime safety checks that impair performance.
    -   Requires fully modeling lifetime and exclusivity in the type system.
    -   Data structures must be redesigned to avoid sharing mutable state.
    -   Increases complexity of node and pointer based data structures, such as
        linked lists.
-   Imitating Rust's techniques may prove insufficient for achieving Carbon's
    [compiler performance goals](../goals.md#fast-and-scalable-development).
    Rust compilation performance suggests its borrow checking performance is
    slow, although it's difficult to determine how significant this is or
    whether it could be improved.
    -   The Rust compiler
        [is slow](https://pingcap.com/blog/rust-compilation-model-calamity),
        although
        [much has been done to improve it](https://blog.mozilla.org/nnethercote/2020/09/08/how-to-speed-up-the-rust-compiler-one-last-time/).
    -   Details of type checking, particularly requiring parsing of function
        bodies to type check signatures, as well as wide use of
        [monomorphization](https://doc.rust-lang.org/book/ch10-01-syntax.html)
        are likely significant contributors to Rust compilation performance.
    -   LLVM codegen is also a significant cost for Rust compilation
        performance.
    -   With
        [Fuchsia](https://fuchsia.dev/fuchsia-src/development/languages/rust) as
        an example, in December 2020, borrow checking and type checking combined
        account for around 10% of Rust compile CPU time, or 25% of end-to-end
        compile time. The current cost of borrow checking is obscured both
        because of the combination with type checking, and because Fuchsia
        disables some compiler parallelization due to build system
        incompatibility.
-   The complexity of using Rust's compile-time safety may incentivize
    unnecessary runtime checking of safety properties. For example, using
    [`RefCell`](https://doc.rust-lang.org/std/cell/struct.RefCell.html) or
    [`Rc`](https://doc.rust-lang.org/std/rc/struct.Rc.html) to avoid changing
    designs to fit compile-time safety models.
-   Some of the most essential safety tools that ease the ergonomic burden of
    the Rust-style lifetime model (`Rc`) introduce _semantic_ differences that
    cannot then be eliminated in a context where performance is the dominant
    priority.

It's possible to modify the Rust model several ways in order to reduce the
burden on C++ developers:

-   Don't offer safety guarantees for data races, eliminating `RefCell`.
    -   This would likely not avoid the need for `Rc` or `Arc`, and wouldn't
        substantially reduce the complexity.
-   Require manual destruction of `Rc`, allowing safety checks to be disabled in
    the performance build mode to eliminate overhead.
    -   This still requires redesigning C++ code to take advantage of `Rc`.
    -   The possibility of incorrect manual destruction means that the safety
        issue is being turned into a bug, which means it is hardening and no
        longer a safety guarantee.
    -   Carbon can provide equivalent hardening through techniques such as
        [MarkUs](https://www.cl.cam.ac.uk/~tmj32/papers/docs/ainsworth20-sp.pdf),
        which does not require redesigning C++ code.

Overall, Carbon is making a compromise around safety in order to give a path for
C++ to evolve. C++ developers must be comfortable migrating their codebases, and
able to do so in a largely automated manner. In order to achieve automated
migration, Carbon cannot require fundamental redesigns of migrated C++ code.
While a migration tool could in theory mark all migrated code as `unsafe`,
Carbon should use a safety strategy that degrades gracefully and offers
improvements for C++ code, whether migrated or not.

That does not mean Carbon will never adopt guaranteed safety by default, only
that performance and migration of C++ code takes priority, and any design will
need to be considered in the context of other goals. It should still be possible
to adopt guaranteed safety later, although it will require identifying a
migration path.

#### Guaranteed run-time memory safety using reference counting

[Reference counting](https://en.wikipedia.org/wiki/Reference_counting) is a
common memory safety model, with Swift as a popular example.

Advantages:

-   Simple model for safety, particularly as compared with Rust.
-   Safe for all of the most common and important classes of memory safety bugs.

Disadvantages:

-   Safety based on reference counting introduces significant performance costs,
    and tools for controlling these costs are difficult.
    -   Safety based on garbage collection has less direct performance overhead,
        but has a greater unpredictability of performance.
-   Significant design differences versus C++ still result, as the distinction
    between value types and "class types" becomes extremely important.
    -   Class types are held by a reference counted pointer and are thus
        lifetime safe.

In order to mitigate the performance overhead, Swift does have a proposal to add
an option for unique ownership, although the specifics are not designed yet. The
unique ownership approach is expected to require unowned and unsafe access, so
it would not considered to improve the safety trade-offs.

Swift was designated by Apple as the replacement for Objective-C. The safety
versus performance trade-offs that it makes fit Apple's priorities. Carbon's
performance goals should lead to different trade-off decisions with a higher
priority on peak performance, which effectively rules out broad use of reference
counting.

#### Guaranteed run-time memory safety using garbage collection

[Garbage collection](<https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)>)
is a common memory safety model, with Java as a popular example.

Advantages:

-   This approach is among the most robust and well studied models, with decades
    of practical usage and analysis for security properties.
-   Extremely suitable for efficient implementation on top of a virtual machine,
    such as the JVM.

Disadvantages:

-   Extremely high complexity to fully understand the implications of complex
    cases like data races.
-   Performance overhead is significant in terms of what Carbon would like to
    consider.
    -   Garbage collection remains a difficult performance problem, even for the
        JVM and its extensive optimizations.
    -   The complexity of the implementation makes it difficult to _predict_
        performance; for example, Java applications experience latency spikes
        when garbage collection runs.

Java is a good choice for many applications, but Carbon is working to focus on a
set of performance priorities that would be difficult to achieve with a garbage
collector.

### Build mode names

The build mode concepts are difficult to name. Other names that were evaluated,
and are ultimately similar, are:

-   "Debug" is a common term for the intended use of this build mode. Also,
    tooling including Visual Studio frequently uses the debug term for
    describing similar.

    -   "Development" was also considered, but this term is less specific and
        would be better for describing all non-release builds together. For
        example, a "fast build" mode might be added that disables safety checks
        to improve iteration time, like might be controlled by way of C++'s
        `NDEBUG` option.

-   "Performance" aligns with the phrasing of the language performance goal.

    -   "Optimized" implies that other modes would not be fully optimized, but
        hardened should be optimized.

    -   "Fast" would suggest that speed is the only aspect of performance being
        optimizing for, but "performance" also optimizes for memory usage and
        binary size.

-   "Hardened" is the choice for succinctly describing the additional safety
    measures that will be taken, and is a well-known term in the safety space.
    It could be incorrectly inferred that "performance" has no hardening, but
    the preference is to clearly indicate the priority of the "hardened" build
    mode.

    -   "Safe" implies something closer to guaranteed safety. However, safety
        bugs should be expected to result in program termination, which can
        still be used in other attacks, such as Denial-of-Service.

    -   "Mitigated" is an overloaded term, and it may not be succinctly clear
        that it's about security mitigations.

-   Some terms which were considered and don't fit well into the above groups
    are:

    -   "Release" is avoided because both "performance" and "hardened" could be
        considered to be "release" build modes.

The names "performance" and "hardened" may lead to misinterpretations, with some
developers who should use "hardened" using "performance" because they are
worried about giving up too much performance, and the other way around. The
terms try to balance the utility of well-known terminology with the succinctness
of a short phrase for build modes, and that limits the expressivity. Some
confusion is expected, and documentation as well as real-world experience (for
example, a developer who cares about latency benchmarking both builds) should be
expected to help mitigate mix-ups.

### Performance versus safety in the hardened build mode

The performance cost of safety techniques are expected to be non-linear with
respect to detection rates. For example, a particular vulnerability such as heap
use-after-free may be detectable with 99% accuracy at 20% performance cost, but
100% accuracy at 50% performance cost. At present, build modes should be
expected to evaluate such a scenario as:

-   The debug build mode would choose the 99% accurate approach.
    -   Detecting safety issues is valuable for debugging.
    -   The probabilistic detection rate won't meaningfully affect accuracy of
        tests.
    -   The lower performance cost improves developer velocity.
-   The performance build mode would decline detection.
    -   Safety checks with a measurable performance cost should be declined.
-   The hardened build mode would choose the 100% accurate approach.
    -   Safety must be non-probabilistic in order to reliably prevent attacks.
    -   Significant performance hits are acceptable.
    -   This means the hardened build mode may be slower than the debug build
        mode.

In order to achieve better performance, the hardened build mode could make
trade-offs closer to the debug build mode. Rather than relying on
non-probabilistic techniques, it could instead offer a probability-based chance
of detecting a given attack.

Advantages:

-   Probabilistic safety should come at lower performance cost (including CPU,
    memory, and disk space).
    -   This will sometimes be significant, and as a result of multiple checks,
        could result in the hardened build mode being 50% slower than the
        performance build mode instead of being 200% slower.

Disadvantages:

-   [Probabilistic techniques likely cannot stop attacks](#probabilistic-techniques-likely-cannot-stop-attacks).
    -   Attackers may be able to repeat attacks until they succeed.
    -   The variables upon which the probability is based, such as memory
        addresses, may be manipulable by the attacker. As a consequence, a
        determined attacker may be able to manipulate probabilities and not even
        be detected.

Although performance is
[Carbon's top goal](../goals.md#language-goals-and-priorities), the hardened
build mode exists to satisfy developers and environments that value safety more
than performance. The hardened build mode will rely on non-probabilistic safety
at significant performance cost because other approaches will be insufficient to
guard against determined attackers.

### Add more build modes

More build modes could be added to this principle, or the principle could
encourage the idea that specific designs may add more.

To explain why three build modes:

-   The concept of debug and release (sometimes called opt) are common. For
    example, in
    [Visual Studio](https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-debug-and-release-configurations?view=vs-2019).
    In Carbon, this could be considered to translate to the "debug" and
    "performance" build modes by default.

-   The hardened build mode is added in order to emphasize security. Although
    hardened could be implemented as a set of options passed to the standard
    release build mode, the preference is to focus on it as an important
    feature.

An example of why another build mode may be needed is
[ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html), which is
noted as having 5-15x slowdown and 5-10x memory overhead. This is infeasible for
normal use, but could be useful for some users in a separate build mode. A
trade-off that's possible for Carbon is instead using an approach similar to
[KCSAN](https://github.com/google/ktsan/wiki/KCSAN) which offers relatively
inexpensive but lower-probability race detection.

Although options to these build modes may be supported to customize deployments,
the preference is to focus on a small set and make them behave well. For
example, if a separate build mode is added for ThreadSanitizer, it should be
considered a temporary solution until it can be merged into the debug build
mode.

Advantages:

-   Grants more flexibility for using build modes as a solution to problems.
    -   With safety checks, this would allow providing safety checks that are
        high overhead but also high detection rate as separate build modes.
    -   With other systems, there could be non-safety performance versus
        behavior trade-offs.

Disadvantages:

-   Having standard modes simplifies validation of interactions between various
    safety checks.
    -   Safety is the only reason that's been considered for adding build modes.
-   As more build modes are added, the chance of developers being confused and
    choosing the wrong build mode for their application increases.

Any long-term additions to the set of build modes will need to update this
principle, raising the visibility and requiring more consideration of such an
addition. If build modes are added for non-safety-related reasons, this may lead
to moving build modes out of the safety strategy.

**Experiment**: This can be considered an experiment. Carbon may eventually add
more than the initial three build modes, although the reluctance to add more is
likely to remain.