-
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 54 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,244 @@ | ||||||
# 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) | ||||||
- [Interoperability syntax elements](#interoperability-syntax-elements) | ||||||
- [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++ APIs and export C++ APIs. | ||||||
Supporting C++ interoperability is a | ||||||
[key requirement for Carbon's goals](/docs/project/goals.md) and is expected to | ||||||
influence the design of Carbon itself. The interoperability layer also has its | ||||||
own [goals and philosophy](goals_and_philosophy.md) which guide the design of | ||||||
individual features. | ||||||
|
||||||
## 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. For example, | ||||||
`$extern("Cpp", namespace="myproject")`. | ||||||
- The Carbon toolchain will translate externed declarations to C++, and they | ||||||
will be available to C++ code through `.6c.h` header files. | ||||||
- `import Cpp "path"`: Imports APIs from a C++ header file. | ||||||
|
||||||
We use the name `Cpp` because `import` needs a valid identifier. | ||||||
|
||||||
## 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, and guard | ||||||
> rails to prevent overuse/misuse should be considered. | ||||||
|
||||||
## 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 imports. | ||||||
|
||||||
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 | ||||||
|
||||||
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. | ||||||
|
||||||
Where performance is critical, such as primitive types, mappings are required to | ||||||
have identical memory layout between C++ and Carbon. This is necessary to | ||||||
provide inteoperability calls without a conversion cost. | ||||||
|
||||||
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). | ||||||
|
||||||
C++ class templates are directly made available in Carbon. For example, ignoring | ||||||
allocators and their associated complexity, `std::vector<T>` in C++ would be | ||||||
available as `Cpp.std.vector(T)` in Carbon. | ||||||
|
||||||
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) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
# Type mapping | ||
|
||
<!-- | ||
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 --> | ||
|
||
- [C/C++ enums in Carbon](#cc-enums-in-carbon) | ||
- [Carbon enums in C/C++](#carbon-enums-in-cc) | ||
|
||
<!-- tocstop --> | ||
|
||
We expect enums can be represented directly in the other language. All values in | ||
the copy should be assumed to be explicit, to prevent any possible issues in | ||
Comment on lines
+25
to
+26
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 "All values in the copy should be assumed to be explicit" mean? |
||
enum semantics. | ||
geoffromer marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## C/C++ enums in Carbon | ||
|
||
C++ enums will generally translate naturally 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. It would be good to mention the cases that don't fall into the general pattern. C and C++ APIs sometimes (how often? IDK) rely on enums being implicitly convertible to integers. Ignoring this issue will lead to some APIs being non-ergonomic so it is OK to punt on it being ergonomic, but we should provide a technical ability for C++ enums specifically. It might be the case that by default Carbon enums will not be convertible to integers at all to avoid even a remote possibility of anyone relying on numeric values (I'd certainly argue for it). C and C++ APIs also sometimes cast arbitrary bit patterns into enum values, which Carbon enums might decide to prohibit. Ignoring this issue will lead to miscompiles, so I think we have to think about it. Maybe the Carbon enums imported from C++ should not be assumed to have free bit patterns. 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 open questions to cover this. Is that sufficient for now? |
||
`enum class`. Attributes may be used if renaming is desired to reach | ||
conventional Carbon naming. | ||
|
||
Given a C++ enum: | ||
|
||
```cc | ||
enum Direction { | ||
East, | ||
West = 20, | ||
North, | ||
South, | ||
}; | ||
``` | ||
|
||
We would expect to generate equivalent Carbon code: | ||
|
||
```carbon | ||
enum Direction { | ||
East = 0, | ||
West = 20, | ||
North = 21, | ||
South = 22, | ||
} | ||
Comment on lines
+49
to
+54
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 expect to by default also generate
In general I think we should aim that the |
||
|
||
// Calling semantic: | ||
var Direction: x = Direction.East; | ||
``` | ||
|
||
Sometimes enum names may repeat the enum identifier; for example, | ||
`DIRECTION_EAST` instead of `East`. To help with this case, we may want to | ||
support renaming of enum entries. For example, to rename in a way that results | ||
in a match to the above Carbon calling convention, we add `carbon_enum`: | ||
|
||
```cc | ||
enum Direction { | ||
DIRECTION_EAST, | ||
DIRECTION_WEST, | ||
DIRECTION_NORTH, | ||
DIRECTION_SOUTH, | ||
} __attribute__((carbon_enum("East:West:North:South")); | ||
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. In Swift we instead strip a common prefix from enumerators. 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. Good point, added a note. |
||
``` | ||
|
||
If using enum class, we'd expect similar behavior: | ||
|
||
```cc | ||
enum class Direction : char { | ||
East = 'E', | ||
West = 'W', | ||
North = 'N', | ||
South = 'S', | ||
}; | ||
``` | ||
|
||
With Carbon code: | ||
|
||
```carbon | ||
enum(Byte) Direction { | ||
East = 'E', | ||
West = 'W', | ||
North = 'N', | ||
South = 'S', | ||
}; | ||
``` | ||
|
||
## Carbon enums in C/C++ | ||
|
||
Carbon enums should be expected to translate to `enum class`. | ||
|
||
For example, given a Carbon enum: | ||
|
||
```carbon | ||
$extern("Cpp") enum Direction { | ||
East, | ||
West = 20, | ||
North, | ||
South, | ||
} | ||
``` | ||
|
||
We would expect to generate equivalent 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. The C++ code will likely need an attribute to specify the size of the enum ( 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. BTW, I'd really like this proposal to introduce some terms around bridging, specifically: (1) a term that denotes zero-cost bridging of types that have identical memory layout in C++ and 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. Is the attribute something that exists? For now, I've added an open question. Although, would setting appropriate types on enum classes actually solve it? For terms, any suggestions for a glossary? Does Swift have such terms? |
||
|
||
```cc | ||
enum class Direction { | ||
East = 0, | ||
West = 20, | ||
North = 21, | ||
South = 22, | ||
}; | ||
``` |
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.