# Bidirectional interoperability with C and C++ ## Table of contents - [Philosophy and goals](#philosophy-and-goals) - [Overview](#overview) - [C++ interoperability model: introduction and principles](#c-interoperability-model-introduction-and-principles) - [The successor language mandate](#the-successor-language-mandate) - [The C++ interop type](#the-c-interop-type) - [Importing C++ APIs into Carbon](#importing-c-apis-into-carbon) - [Importing C++ libraries (header-based)](#importing-c-libraries-header-based) - [TODO: Importing C++ code (inline)](#todo-importing-c-code-inline) - [Accessing built-in C++ entities (file-less)](#accessing-built-in-c-entities-file-less) - [The `Cpp` package](#the-cpp-package) - [TODO: Importing C++ macros](#todo-importing-c-macros) - [Calling C++ code from Carbon](#calling-c-code-from-carbon) - [Function call syntax and semantics](#function-call-syntax-and-semantics) - [TODO: Overload resolution](#todo-overload-resolution) - [TODO: Constructors](#todo-constructors) - [TODO: Struct literals](#todo-struct-literals) - [TODO: Accessing C++ classes, structs, and members](#todo-accessing-c-classes-structs-and-members) - [TODO: Accessing global variables](#todo-accessing-global-variables) - [TODO: Bi-directional type mapping: primitives and core types](#todo-bi-directional-type-mapping-primitives-and-core-types) - [TODO: Advanced type mapping: pointers, references, and `const`](#todo-advanced-type-mapping-pointers-references-and-const) - [TODO: Bi-directional type mapping: standard library types](#todo-bi-directional-type-mapping-standard-library-types) - [TODO: The operator interoperability model](#todo-the-operator-interoperability-model) ## Philosophy and goals The C++ interoperability layer of Carbon allows a subset of C++ APIs to be accessed from Carbon code, and similarly a subset of Carbon APIs to be accessed from C++ code. This requires expressing one language as a subset of the other. Bridge code may be needed to map some APIs into the relevant subset, but the constraints on expressivity should be loose enough to keep the amount of such bridge code sustainable. The [interoperability philosophy and goals](philosophy_and_goals.md) provide more detail. ## Overview Carbon's bidirectional interoperability with C++ is [a cornerstone of its design](/docs/project/goals.md#interoperability-with-and-migration-from-existing-c-code), enabling a gradual transition from existing C++ codebases. The goal is not just a foreign function interface (FFI), but a seamless, high-fidelity integration that supports advanced C++ features, from templates to class hierarchies. C++ APIs are imported into Carbon using an `import Cpp` directive, which makes C++ declarations available within a dedicated `Cpp` package in Carbon. This prevents name collisions and makes the origin of symbols explicit. Carbon code can then call C++ functions, instantiate C++ classes, and use C++ types, while respecting C++'s semantics, including its complex overload resolution rules and preserving the nominal distinctions between C++ types like `long` and `long long`, or `T*` and `T&`, which is critical for correct overload resolution and template instantiation. Similarly, Carbon APIs can be designed to be callable from C++. The interoperability layer is designed to be zero-cost, avoiding unnecessary allocations or copies when calling between the two languages. ## C++ interoperability model: introduction and principles ### The successor language mandate The design of Carbon's C++ interoperability is governed by its foundational goal: [to be a successor language](/README.md), not merely a language with a foreign function interface (FFI). This mandate dictates a design that moves beyond the C-style FFI adopted by most modern languages and instead provides seamless, bidirectional interoperability. The objective is to support deep integration with existing C++ code, encompassing its most complex features, from inheritance to templates. This goal has profound implications for the Carbon compiler and language semantics. It requires that C++ is not treated as a foreign entity. Instead, Carbon's semantic model must be _co-designed_ to understand, map, and interact with C++'s semantic constructs—including templates, class hierarchies, and complex overload resolution—with high fidelity. The interoperability layer must, therefore, operate at the semantic analysis level, not just at the linking (ABI) level. This document specifies the design of this semantic contract. ### The C++ interop type A core mechanism in this design is the C++ interop type. This concept defines the "trigger" that activates C++-specific semantic rules within the Carbon compiler. Any operation involving a type that is designated as a C++ interop type could invoke the specialized interoperability logic, such as C++ overload resolution or operator overload resolution that involves both Carbon and C++ operator overloads. A type is considered a C++ interop type if its definition involves an imported C++ type in any of the following ways: 1. A C++ imported type (for example, `Cpp.Widget`). 2. A pointer to a C++ interop type (for example, `Cpp.Widget*`). 3. A Carbon generic type parameterized with a C++ interop type (for example, `MyCarbonVector(Cpp.Widget)`). More generally, a C++ interop type is any type for which Carbon's [orphan rule](https://docs.carbon-lang.dev/docs/design/generics/details.html#orphan-rule) would allow an impl to be provided by a library in `package Cpp`. This "pervasive" model of C++-awareness is a fundamental design choice. The C++ semantics are not confined to a specific `unsafe` or `extern "C++"` block; they affect any Carbon type that composes them. For example, when the Carbon compiler instantiates a _Carbon_ generic type like `MyCarbonVector(Cpp.Widget)`, its type system must be aware that the `Cpp.Widget` parameter carries C++-specific rules. This mandates that Carbon's own generic system, struct layout logic, overload resolution and operator lookup must query the type system for the presence of a C++ interop type. If present, Carbon must consider C++ rules when operating over C++ interop types. This design prioritizes the goal of a seamless and intuitive user experience. ## Importing C++ APIs into Carbon ### Importing C++ libraries (header-based) The primary mechanism for importing existing, user-defined C++ code is through header file inclusion. Carbon must be able to parse and analyze C++ header files to make their declarations available within Carbon. **Syntax:** The syntax for this operation is `import Cpp library "header_name"`. This syntax is used for both standard library headers and user-defined headers: - **Standard Library:** ```carbon import Cpp library ""; ``` This import makes entities like `putchar` available. - **C++ User-Defined Header:** ```carbon import Cpp library "circle.h"; ``` This import makes user-defined declarations and definitions available. ### TODO: Importing C++ code (inline) ### Accessing built-in C++ entities (file-less) Some C++ entities, particularly built-in primitive types, are not defined in any header file. They are "intrinsic" to the C++ language. These entities are available in Carbon without an explicit `import` declaration. ### The `Cpp` package A critical design choice for managing C++ imports is the mandatory use of a containing package, `Cpp`. All imported C++ named entities (functions, types, namespaces) are contained in the `Cpp` package. - **Functions:** `Cpp.putchar(...)` - **Classes/Types:** `Cpp.Circle`, `Cpp.Point` - **Constructors:** `Cpp.Circle.Circle()` The `Cpp.` prefix makes the _origin_ of every symbol explicit and unambiguous. It ensures that C++ entities cannot collide with Carbon code. ### TODO: Importing C++ macros ## Calling C++ code from Carbon ### Function call syntax and semantics Once imported, C++ functions are invoked using standard Carbon function call syntax, prefixed with the `Cpp` name. The Carbon compiler is responsible for mapping the Carbon arguments to the types expected by the C++ function's signature. This often requires explicit casting on the Carbon side, using the `as` keyword, to satisfy the C++ function's parameter types. **Example:** The following example imports `cstdio` and calls the C function `putchar`. The Carbon `Core.Char` variable `n` must be cast first to `u8` and then to `i32` to match the `int` parameter expected by `putchar`. ```carbon import Cpp library ""; fn Run() { let hello: array(Core.Char, 6) = ('H', 'e', 'l', 'l', 'o', '!'); for (n: Core.Char in hello) { // Carbon 'as' casting is used to match the C++ signature Cpp.putchar((n as u8) as i32); } } ``` ### TODO: Overload resolution ### TODO: Constructors ### TODO: Struct literals ## TODO: Accessing C++ classes, structs, and members ## TODO: Accessing global variables ## TODO: Bi-directional type mapping: primitives and core types ## TODO: Advanced type mapping: pointers, references, and `const` ## TODO: Bi-directional type mapping: standard library types ## TODO: The operator interoperability model