-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Carbon <-> C/C++ interoperability #80
Changes from 43 commits
2ae6b6f
5bba3a8
98562a6
a05e9c3
dfe42cb
3931951
43cfde9
b489c23
5b10b4d
6ce0f97
16e6242
5a9c853
38e73de
4310965
3b49e31
218df9f
5c33fbf
e4223f4
471df44
21097a8
116edd6
7be07be
72a3382
69ba0aa
bb4678b
93dd8b8
b8e6432
6eb02c7
e3be8d5
46e1943
f935369
338703a
e828a28
e2270a4
05430cc
7e44750
90f798c
74861eb
5f94ba9
0d7735c
acaf391
b43d0b3
9da1904
4a4dea6
521d0f0
14ead29
0c03ae4
8178a87
80c8698
38ce17f
394f723
46aaff3
b7bdcb0
bedd467
891fb23
525f503
7101c2e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,335 @@ | ||||||
# Carbon <-> C/C++ interoperability | ||||||
|
||||||
<!-- | ||||||
Part of the Carbon Language project, under the Apache License v2.0 with LLVM | ||||||
Exceptions. See /LICENSE for license information. | ||||||
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||
--> | ||||||
|
||||||
## Table of contents | ||||||
|
||||||
<!-- toc --> | ||||||
|
||||||
- [Overview](#overview) | ||||||
- [Goals](#goals) | ||||||
- [Philosophy of interoperability layer](#philosophy-of-interoperability-layer) | ||||||
- [Interoperability syntax elements](#interoperability-syntax-elements) | ||||||
- [Details](#details) | ||||||
- [Bridge code in Carbon files](#bridge-code-in-carbon-files) | ||||||
- [Name mapping](#name-mapping) | ||||||
- [Type mapping](#type-mapping) | ||||||
- [Primitive types](#primitive-types) | ||||||
- [User-defined types](#user-defined-types) | ||||||
- [Vocabulary types](#vocabulary-types) | ||||||
- [Enums](#enums) | ||||||
- [Templates and generics](#templates-and-generics) | ||||||
- [Using C++ templates from Carbon](#using-c-templates-from-carbon) | ||||||
- [Using Carbon templates from C++](#using-carbon-templates-from-c) | ||||||
- [Using Carbon generics from C++](#using-carbon-generics-from-c) | ||||||
- [Functions and overload sets](#functions-and-overload-sets) | ||||||
- [Other syntax](#other-syntax) | ||||||
- [Migration examples](#migration-examples) | ||||||
|
||||||
<!-- tocstop --> | ||||||
|
||||||
## Overview | ||||||
|
||||||
It's critical that Carbon can both access C++ interfaces and export C++ | ||||||
interfaces. Supporting C++ interoperability is a | ||||||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
[key requirement for Carbon's goals](/docs/project/goals.md) and is expected to | ||||||
influence the design of Carbon itself. | ||||||
|
||||||
## Goals | ||||||
|
||||||
The goals of Carbon's interoperability layer are heavily influenced by the | ||||||
[language-level goals](/docs/project/goals.md). Notably, we prioritize | ||||||
performance, and making any performance overhead visible and opt-in. | ||||||
|
||||||
Goals: | ||||||
|
||||||
- The majority of simple C/C++ interfaces should be usable from Carbon without | ||||||
any custom bridge code and without any runtime overhead. | ||||||
- There should be support for most idiomatic usage of advanced C++ features: | ||||||
templates, overload sets, ADL. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought at Google we were moving to no use of ADL in C++. If that is a widespread best practice, or not necessary for interop, it seems we might not support ADL as part of Carbon/C++ interop. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My impression is it's not really a widespread best practice, but even if it were, aren't there parts of stl that rely on it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're moving to no accidental use in ADL in Google code. The problem with ADL isn't that it's a bad practice, it's that as a language feature, it's extremely prone to accidental use in ways that constrain API evolution. There are enough legitimate and widespread uses (e.g. AbslHashValue) that Carbon will need some kind of story for how to support them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to be explicit: I consider this thread resolved, without changes. |
||||||
- It should be possible to map types across languages. | ||||||
- Primitive types should have unsurprising mappings. | ||||||
- There should be transparent, automatic translation between C++ and Carbon | ||||||
non-owning vocabulary types, such as pointers and references, without | ||||||
runtime overhead. | ||||||
- It should be possible to expose other C++ vocabulary types with reasonable, | ||||||
but potentially non-zero-cost, conversions available to map into Carbon | ||||||
vocabulary types. | ||||||
- Mappings should be easy to maintain. | ||||||
- We should provide a syntax for transparently, automatically exposing a | ||||||
subset of Carbon types and interfaces to C++ code without custom bridge | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is referring to Carbon interfaces, not C++. ("Carbon types and interfaces to C++ code") Even with your "base type" comments, I assume that's still distinct from "abstract base class", which sounds C++-y. I'm assuming you read that backwards, but not sure how to phrase better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you really mean Carbon interfaces or just Carbon APIs in general, including free functions and constants that are not nested within a type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I think it's fine to change this to APIs |
||||||
code, including instantiating templates. | ||||||
|
||||||
Non-goals: | ||||||
|
||||||
- We will not make Carbon -> C++ migrations as easy as C++ -> Carbon migrations. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like you meant "interop" instead of "migration". I don't think we are designing any support for Carbon -> C++ migration (so I find it surprising to even mention it here), but calling Carbon from C++ is necessary for C++ -> Carbon migration. So to avoid confusion I'd say "We prioritize calling C++ from Carbon. Calling Carbon from C++ will not be necessarily as easy." There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, roughly. |
||||||
- Automatically exposing all Carbon code would impose language and API | ||||||
constraints; we want to limit these constraints to where users need it. | ||||||
- We do not expect to support all C/C++ corner cases: the complexity of | ||||||
supporting any given construct must be balanced by the real world need for | ||||||
that support. | ||||||
- We may target C++17, and not keep adding interoperability support for later | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notably, this means we would not support modular C++ code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noted: |
||||||
C++ features. | ||||||
- There may be interest in supporting some C++20 features, particularly | ||||||
modules. However, exhaustive support should not be assumed. | ||||||
- For example, we might not prioritize support for non-idiomatic code, | ||||||
interfaces, or patterns outside of those in widespread open source libraries | ||||||
and used by key contributors. | ||||||
- For example, we might not support low-level C ABIs outside of modern 64-bit | ||||||
ABIs: Linux, POSIX, and a small subset of Windows' calling conventions. | ||||||
- We may choose not to use the existing ABI for the C++ language or standard | ||||||
library. | ||||||
- It might be reasonable to eventually support these with added runtime | ||||||
overhead. | ||||||
- We may choose not to provide exact matches between Carbon and C++ vocabulary | ||||||
types. | ||||||
- We may choose not to provide full support for unwinding exceptions across | ||||||
Carbon and C/C++ boundaries. | ||||||
|
||||||
## Philosophy of interoperability layer | ||||||
|
||||||
The design for interoperation between Carbon and C++ hinges on: | ||||||
|
||||||
1. A focus on types, and simple overload sets built from those types. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what "a focus on types" means. Does it mean that interop for free functions would be not as good as interop for structs? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure either. :) How about:
|
||||||
2. A willingness to expose the idioms of C++ into Carbon code, and vice versa, | ||||||
when necessary to maximize performance. | ||||||
3. The use of wrappers, generic programming, and templates to minimize or | ||||||
eliminate runtime overhead. | ||||||
|
||||||
These things come together when looking at how custom data structures in C++ are | ||||||
exposed into Carbon or vice versa. In both languages, it is reasonable and even | ||||||
common to have customized low-level data structures such as associative | ||||||
containers. Even today, there are numerous data structures for mapping from a | ||||||
key to a value that might be "best": hash table, linked hash table, sorted | ||||||
vector, and btree to name a few. Experience with C++ tells us that we should | ||||||
also expect slow but meaningful evolution even in implementation strategies that | ||||||
cause divergence. | ||||||
|
||||||
The result is that it is often reasonable to directly expose a data structure | ||||||
from C++ to Carbon without converting it to a "native" or "idiomatic" Carbon | ||||||
data structure. For many data structures, code will reasonably support multiple | ||||||
different implementations, even if there is an extremely good default. We can | ||||||
expose C++ data structures as another implementation and then focus on wrapping | ||||||
it to match whatever idioms Carbon expects of that kind of data structure. | ||||||
|
||||||
The reverse is also true. C++ code will often not care, or can be enhanced to | ||||||
not care, what specific data structure is used. Carbon data structures can be | ||||||
exposed as yet another implementation in C++, and wrapped in C++ code to match | ||||||
C++ idioms and be usable within templated contexts. | ||||||
|
||||||
Another fundamental philosophy of interoperability between Carbon and C++, and | ||||||
generally between any two languages, is that it requires expressing one language | ||||||
as a subset of another. The approach proposed is to do this in two directions: | ||||||
take specific, restricted C++ APIs and make them available using restricted | ||||||
Carbon APIs, and also take specific, restricted Carbon APIs and make them | ||||||
available as restricted C++ APIs. In both languages, the API restrictions on | ||||||
exported interfaces and imported interfaces can be intersected. These | ||||||
intersections define the interoperability layer and constrain the expressivity | ||||||
of Carbon/C++ interoperability. Our goal is that these expressivity constraints | ||||||
are wide enough to make the amount of bridge code sustainable and the overhead | ||||||
of wrappers manageable. | ||||||
|
||||||
## Interoperability syntax elements | ||||||
|
||||||
> References: [Name mapping](name_mapping.md). | ||||||
|
||||||
An `import` will be sufficient for Carbon to call most C++ APIs, with no changes | ||||||
to the C++ code. However, special interoperability syntax elements will be | ||||||
required when exposing Carbon code to C++. | ||||||
|
||||||
Notable elements are: | ||||||
|
||||||
- `$extern("Cpp")`: Indicates that Carbon code should be exposed for C++. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it's a placeholder text, but is there some technical reason we couldn't have the string be "C++" instead of "Cpp"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From reading ahead a bit, it looks like that string becomes a Carbon package, which seems to be required to have a valid identifier as its name? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adding a brief sentence: We use the name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be a consequence of the decision to make
Have we considered a more orthogonal design, where the language and namespace are specified separately, e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added more of a discussion of options to name_mapping.md, trying to capture what you're saying - it may help to move conversation there. I agree with your point that the current syntax may just be poor (I wonder about switching away from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you proposing concrete syntax here, or is this just a placeholder? If it's concrete syntax, I find it a bit strange: what is a prefix |
||||||
Similarly, `$extern("Swift")` might be used to indicate exposure for Swift at | ||||||
some point in the future. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This description wasn't enough for me to infer what this syntax means or where it would appear. From reading ahead, it appears the intent is that this is an annotation attached to individual Carbon declarations, and that it causes the C++ wrapper header to provide a corresponding declaration to C++ code that matches the Carbon declaration. Does this in any way change the meaning of the Carbon declaration, or only expose it? For example, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My hope would be that the Carbon declaration doesn't change meaning from within Carbon code. Instead, any semantic differences should be only in the exposed form of the API as it is accessed from that language. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 to @chandlerc. I also think it is better to make any necessary calling convention changes only in symbols usable from C++, while leaving symbols used by Carbon unchanged. That can mean that a function might have two entry points, one with the Carbon calling convention, one with the C++ calling convention. |
||||||
- `namespace` and `name` parameters are provided to override default choices, | ||||||
geoffromer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
particularly to assist migration of C++ APIs to Carbon. | ||||||
- Externs may be #included using `.6c.h` files. | ||||||
geoffromer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
- `import Cpp "path"`: Imports API calls from a C++ header file. | ||||||
jonmeow marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
We use the name `Cpp` because `import` needs a valid identifier. | ||||||
|
||||||
## Details | ||||||
|
||||||
### Bridge code in Carbon files | ||||||
|
||||||
> TODO: We should allow writing bridge C++ code in Carbon files to ease | ||||||
> maintenance of compatibility layers. Syntax needs to be proposed. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also some guardrails are needed for ensuring that people don't abuse this feature to just write arbitrary C++ in Carbon source files, effectively treating Carbon as a superset of C++. For example, the C++ bridge code written in a Carbon file shouldn't be callable from Carbon code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would interpret part of the point here to be calling C++ bridge code from Carbon. e.g., if there's some C++ API that isn't being exposed to Carbon well enough to call automatically, or if it's code that you don't own, and would need some markup for correct interpretation, having a bridge in the Carbon file seems like the right spot. While I'd agree at a basic level that inserting tons of C++ in a Carbon file wouldn't be great, I'm not sure it's something that we need to actively prevent. It's already going to get a little awkward mixing file extensions. I'd hope the added friction dissuades users. Regardless, noted. |
||||||
|
||||||
### Name mapping | ||||||
|
||||||
> References: [Name mapping](name_mapping.md). | ||||||
> | ||||||
> TODO: Add a reference for incomplete types when one is created. | ||||||
|
||||||
C/C++ names are mapped into the `Cpp` Carbon package. C++ namespaces work the | ||||||
same fundamental way as Carbon namespaces within the `Cpp` package name. Dotted | ||||||
names are used when referencing these names from Carbon code. For example, | ||||||
`std::exit` becomes `Cpp.std.exit`. | ||||||
|
||||||
C++ incomplete types will be mirrored into Carbon's incomplete type behavior. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a document outlining what this behavior is? If so, a link might be appropriate here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, added a TODO There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think Carbon may have much stricter requirements on incomplete types than C++ does. For example, exporting incomplete types might be illegal in Carbon. Or every Carbon incomplete type might have to have a definition in the same file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @josh11b I'm not sure if you'd intended for changes, so I want to be explicit, I think the TODO resolves this comment thread (that there is no doc). |
||||||
Users wanting to avoid differences in incomplete type behaviors should fully | ||||||
define the C++ types using repeated imports. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what the word "repeated" means here. (It can't mean importing the same header multiple times, because that won't make the imported type complete, but I can't think of another interpretation.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dropped "repeated" |
||||||
|
||||||
Carbon names which are mapped into C++ will use a top-level namespace of | ||||||
geoffromer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
`Carbon` by default, with the package name and namespaces represented as | ||||||
namespaces below that. For example, the `Widget` Carbon package with a namespace | ||||||
`Foo` would become `::Carbon::Widget::Foo` in C++. This may be renamed for | ||||||
backwards compatibility for C++ callers when migrating code, for example | ||||||
`$extern("Cpp", namespace="widget")` for `::widget`. | ||||||
Comment on lines
+87
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you imagine this as declaring the entity in namespace |
||||||
|
||||||
### Type mapping | ||||||
geoffromer marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
Carbon and C/C++ will have a number of types with direct mappings between the | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does the word "direct" mean here? |
||||||
languages. | ||||||
|
||||||
The behavior of mapped types will not always be identical; they need only be | ||||||
similar. For example, we expect Carbon's `UInt32` to map to C++'s `uint32_t`. | ||||||
gribozavr marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
While behavior is mostly equivalent, where C++ would use modulo wrapping, Carbon | ||||||
will instead have trapping behavior. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ("will") seems definitive but I don't think we've agreed that. Maybe "may"? |
||||||
|
||||||
In some cases, there are multiple C/C++ types that map to a single Carbon type. | ||||||
This is expected to generally be transparent to users, but may impose important | ||||||
constraints around overload resolution and other C++ features that would "just | ||||||
work" with 1:1 mappings. | ||||||
|
||||||
#### Primitive types | ||||||
|
||||||
> References: [Primitive types](primitive_types.md). | ||||||
|
||||||
We'll have a simple mapping for C++ primitive types. Conversion methods will | ||||||
exist for cross-platform 32-bit/64-bit compatibility. | ||||||
|
||||||
#### User-defined types | ||||||
|
||||||
> TODO: Handling of user-defined types should be addressed. | ||||||
|
||||||
#### Vocabulary types | ||||||
|
||||||
> References: [Vocabulary types](vocabulary_types.md). | ||||||
|
||||||
There are several cases of vocabulary types that are important to consider: | ||||||
|
||||||
- Non-owning types passed by reference or pointer, such as `std::vector<T> &&`. | ||||||
- C++ references map to Carbon non-null pointers, or `T*`. | ||||||
- C++ pointers map to Carbon nullable pointers, or `T*?`. | ||||||
- Non-owning types passed by value, such as `std::string_view` or `std::span`. | ||||||
gribozavr marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
- We copy these to Carbon types with similar semantics. These should have | ||||||
trivial construction costs. | ||||||
- Owning types signaling a move of ownership, such as `std::unique_ptr`. | ||||||
- We will try to transfer ownership to a Carbon type where possible, but may | ||||||
need to copy to the Carbon type in complex cases. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would this "copy" option entail? |
||||||
- Owning types signaling a copy of data, such as `std::vector<T>`. | ||||||
- Copying overhead should be expected and normal, even for a Carbon type. | ||||||
|
||||||
### Enums | ||||||
|
||||||
> References: [Enums](enums.md). | ||||||
|
||||||
C++ enums will generally translate nautrally to Carbon, whether using `enum` or | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
`enum class`. In the other direction, we expect Carbon enums to always use | ||||||
`enum class`. | ||||||
Comment on lines
+144
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sort of presupposes a design for Carbon enums (which AFAIK we don't have, even in PR #83), and assumes that design will be basically isomorphic to C++ enums, which I don't think is a safe assumption. I would expect Carbon enums to be degenerate cases of variant types (as they are in Haskell, and pretty much every other language that has built-in variant types); at the very least, I think that's a strong possibility. I'd suggest just dropping this section; it won't be difficult to recreate it if we adopt an enum design that works with this approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for the input. I'd like to hear from others if they agree. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While Carbon will certainly have some enum facility, how exactly far away it will be from C++ enums is yet to be decided. For example, ergonomics of some C++ APIs relies on the fact that C++ enums are integer-like, and that they implicitly convert to integers rather eagerly. Ergonomics of some other APIs relies on the fact that C++ enums are not namespaced (for example, they already incorporate a prefix), so adding another prefix would be seen as redundant and non-ergonomic. Another issue is that Carbon enums can be more strict than C++ enums on the low level. For example, C++ enums allow all bit patterns at runtime to be passed through (even ones that are not listed in enumerators). Carbon might decide to steal unused bit patterns for bitpacking, or for optional's "none" representation, or just ensure that unused bit patterns are not used through the means of a sanitizer. We could special case C++ enums here, but then such enums are not really Carbon enums, they are C++ enums with special case Carbon syntax and semantics that mostly looks like Carbon enums except where it doesn't. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gribozavr, for clarity, would you voice in support of leaving this for now pending further enum design, or would you prefer it be removed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the "In the other direction" part, I think the narrow thing that this part of the document is saying -- that when exporting a Carbon enumeration to C++ code, the names of enumerators do not leak out into the enclosing scope -- should be expected to be true for any design of Carbon enumerations. We want the names in the C++ scope in namespace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, I do have lots fo qusetions around what enums will actually end up looking like in Carbon -- I'd not want to really speculate too far about that. But I think @zygoloid hits on a nice point that we can telegraph meaningfully -- we don't intend to have the name leakage by default, whatever it is that ends up forming the basis of mapped-to-enums. |
||||||
|
||||||
For example, here is a C++ and Carbon version of a `Direction` enum, both of | ||||||
which will be equivalent in either language: | ||||||
|
||||||
```cc | ||||||
enum class Direction { | ||||||
East, | ||||||
West, | ||||||
North, | ||||||
South, | ||||||
}; | ||||||
``` | ||||||
|
||||||
```carbon | ||||||
$extern("Cpp") enum Direction { | ||||||
East = 0, | ||||||
West = 1, | ||||||
North = 2, | ||||||
South = 3, | ||||||
} | ||||||
``` | ||||||
|
||||||
### Templates and generics | ||||||
|
||||||
### Using C++ templates from Carbon | ||||||
|
||||||
> References: [Templates and generics](templates_and_generics.md). | ||||||
|
||||||
Simple C++ class templates are directly made available as Carbon templates. For | ||||||
example, ignoring allocators and their associated complexity, `std::vector<T>` | ||||||
in C++ would be available as `Cpp.std.vector(T)` in Carbon. More complex C++ | ||||||
templates may need explicit bridge code. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Up to this point we've been talking about interoperability as if we generated C++ code from Carbon code on one side of the divide, and generated Carbon code from C++ code on the other side. But that seems to fall down now. Presumably we're not going to machine-translate the entire I think that's actually all OK, and it's the right thing to be doing, but it doesn't seem to match the remapping-by-code-generation model described in this document. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huge plus one, but I wonder if there is an effective way to basically telegraph this, and come in with a revision that specifically tries to address this? I think this is one of the most complex aspects of interop and it might be helpful to have a focused discussion just around that. Thoughts? |
||||||
|
||||||
gribozavr marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
### Using Carbon templates from C++ | ||||||
|
||||||
> References: [Templates and generics](templates_and_generics.md). | ||||||
|
||||||
Carbon templates should be usable from C++. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly to the above, we should not expect to be able to machine-translate Carbon templates into C++ code. So our C++ compiler will also need to link against enough of a Carbon compiler to be able to instantiate Carbon templates. We may be in a better position here if we don't allow exporting Carbon templates to C++, and only allow exporting Carbon generics. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should really dig into this strategy question you raised... Going to do that in a separate thread -- in particular, I think it might make sense to pop that discussion out to its own Discourse thread: |
||||||
|
||||||
### Using Carbon generics from C++ | ||||||
|
||||||
> References: [Templates and generics](templates_and_generics.md). | ||||||
|
||||||
Carbon generics will require bridge code that hides the generic. This bridge | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure why -- is there some implementation difficulty that you foresee? Exposing a Carbon generic as a C++ template should be rather doable even if Carbon generics are compiled separately. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not clear that's that straightforward, given how generics are done. But maybe a template could be auto-generated? I haven't really thought that through. Added an open question to templates_and_generics.md There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, it seems substantially harder to expose Carbon templates than to expose Carbon generics. This makes me wonder whether "template" and "generic" somehow got reversed in these two sections, and what we mean is that Carbon templates must be wrapped in a Carbon generic before they can be exposed? |
||||||
code may be written using a Carbon template, changing compatibility constraints | ||||||
to match. | ||||||
|
||||||
For example, given the Carbon code: | ||||||
|
||||||
```carbon | ||||||
fn GenericAPI[Foo:$ T](T*: x) { ... } | ||||||
|
||||||
fn TemplateAPI[Foo:$$ T](T*: x) { GenericAPI(x); } | ||||||
``` | ||||||
|
||||||
We could have C++ code that uses the template wrapper to use the generic: | ||||||
|
||||||
```cc | ||||||
CppType y; | ||||||
::Carbon::TemplateAPI(&y); | ||||||
``` | ||||||
|
||||||
### Functions and overload sets | ||||||
|
||||||
> References: [Functions and overload sets](functions_and_overload_sets.md). | ||||||
|
||||||
Non-overloaded functions may be trivially mapped between Carbon and C++, so long | ||||||
as their parameter and return types have suitable mappings. If the names are | ||||||
made available, then they can be called. | ||||||
Comment on lines
+212
to
+214
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We've talked about Carbon having different defaults for various calling-convention questions than C++. One that sticks out is the assumption that pointer parameters to functions are assumed to not be captured by default. How would that play into this? Would C++ code that's exposed to Carbon pick up the Carbon assumption, or not (presumably with some attribute to request the nocapture behavior)? |
||||||
|
||||||
However, function overloading is supported in both languages, and presents a | ||||||
much more complex surface to translate. Carbon's overloading is designed to be | ||||||
largely compatible with C++ so that this can be done reasonably well, but it | ||||||
isn't expected to be precisely identical. Carbon formalizes the idea of overload | ||||||
resolution into pattern matching. C++ already works in an extremely similar way, | ||||||
although without the formalization. We expect to be able to mirror most function | ||||||
Comment on lines
+220
to
+221
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "extremely similar" seems like a stretch to me. C++ overload resolution has at its heart the ranking of implicit conversion sequences, and pattern matching (whether we're thinking about doing it with types or values) isn't really about conversions at all. I think it would be entirely reasonable for Carbon to look for an argument of type I think the thing that makes the most sense is to say: when calling C++ from Carbon, we use the C++ overload resolution rules. And when calling Carbon from C++, we use the Carbon pattern matching rules. If we're intending to deviate from that, then I think we need an exploration of the consequences of said deviation, particularly to the more interesting overload sets in C++ (for an example case study, we could look at overloaded functions in the interfaces of containers such as |
||||||
overloads between the two approaches. | ||||||
Comment on lines
+216
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The hard part here is that to call some C++ facilities with a value of a particular type, the C++ code expects some function or type in a specific C++ namespace to be overloaded to support that type. Are you proposing being able to overload a C++ name with a Carbon implementation? The reverse case is a little different, since Carbon isn't going to use open overloading. The equivalent Carbon extension mechanism is interface implementation. That is, we will need some way to write bridge code to implement a Carbon interface for a C++ type. Carbon look up rules currently would require those implementation to be defined either with the interface or the implementing type, but we may need another place to look for C++ bridge code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A lot of this is Chandler's original text, so I'm somewhat interpreting, but I think the answer is "yes". The exported API needs to walk and talk like a C++ API in order to be called by C++, regardless of whether the implementation is in C++ or Carbon. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, I wrote this before we had really explored interfaces as the primary extension point mechanism. I think it might be worthwhile to revisit much of this and think about whether there is a better way to bridge C++ overloads (at least those intending to be extension points) and Carbon interfaces. |
||||||
|
||||||
### Other syntax | ||||||
|
||||||
> References: [Other syntax](other_syntax.md). | ||||||
|
||||||
Beyond the above in-depth discussions, a few key syntax details to be aware of | ||||||
are: | ||||||
|
||||||
- C typedefs are generally mapped to Carbon aliases. | ||||||
- C/C++ macros that are defined as constants will be imported as constants. | ||||||
Otherwise, macros will be unavailable in Carbon. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This approach seems reasonable to me. For the macros that we do convert to aliases, what scope do we put them into on the Carbon side? Does it depend on whether the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just my two cents, but I wouldn't try to overly infer semantics or structure here. They aren't namespaced in C++ and so I'd expect them to be named in a way that copes with that. |
||||||
|
||||||
### Migration examples | ||||||
|
||||||
Large-scale migrations need to be done piecemeal. The goal of migration examples | ||||||
is to use interoperability in order to produce small migration steps which can | ||||||
be performed independently to a large codebase, without breaking surrounding | ||||||
code. | ||||||
|
||||||
Examples: | ||||||
|
||||||
- [Incremental migration of APIs](example_incremental.md) | ||||||
- [Framework API migration](example_framework.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the role of the README file -- is it supposed to repeat and/or summarize the information from other files? If so, I'd rather not include such duplication at this stage of development, because different copies of information will very likely go out of sync. Any unique information (like goals and philosophy) would be more discoverable in a file with a name that describes the contents.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is trying to echo the BLUF style, so I think it's better to keep, even though it can get out of date. The intent is to summarize, and help people get a picture in their head before they delve into details (if they even choose to).
I can move the goals and philosophy out, though.