|
| 1 | +# Declaring entities |
| 2 | + |
| 3 | +<!-- |
| 4 | +Part of the Carbon Language project, under the Apache License v2.0 with LLVM |
| 5 | +Exceptions. See /LICENSE for license information. |
| 6 | +SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | +--> |
| 8 | + |
| 9 | +<!-- toc --> |
| 10 | + |
| 11 | +## Table of contents |
| 12 | + |
| 13 | +- [Overview](#overview) |
| 14 | +- [Matching redeclarations of an entity](#matching-redeclarations-of-an-entity) |
| 15 | + - [Details](#details) |
| 16 | +- [`extern` and `extern library`](#extern-and-extern-library) |
| 17 | + - [Valid scopes for `extern`](#valid-scopes-for-extern) |
| 18 | + - [Effect on indirect imports](#effect-on-indirect-imports) |
| 19 | +- [Alternatives considered](#alternatives-considered) |
| 20 | +- [References](#references) |
| 21 | + |
| 22 | +<!-- tocstop --> |
| 23 | + |
| 24 | +## Overview |
| 25 | + |
| 26 | +Entities may have up to three declarations: |
| 27 | + |
| 28 | +- An optional, owning forward declaration. |
| 29 | + - For example, `class MyClass;`. |
| 30 | + - This must come before the definition. The API file is considered to be |
| 31 | + before the implementation file. |
| 32 | +- A required, owning definition. |
| 33 | + - For example, `class MyClass { ... }`. |
| 34 | + - The definition might be the _only_ declaration. |
| 35 | +- An optional, non-owning `extern library "<owning_library>"` declaration. |
| 36 | + - For example, `extern library "OtherLibrary" class MyClass;`. |
| 37 | + - It must be in a separate library from the definition. |
| 38 | + - The owning library's API file must import the `extern` declaration, and |
| 39 | + must also contain a declaration. |
| 40 | + - The owning library's declarations must have the `extern` modifier |
| 41 | + (without `library`). |
| 42 | + - For example, `extern class MyClass;`. |
| 43 | + |
| 44 | +For example, a library can have a forward declaration of an entity in the API |
| 45 | +file, and use the implementation file for the entity's definition. Putting the |
| 46 | +definition in an implementation file this way can reduce the dependencies for |
| 47 | +API file evaluation, improving compile time. This is commonly done with |
| 48 | +functions. For example: |
| 49 | + |
| 50 | +``` |
| 51 | +library "MyLibrary"; |
| 52 | +
|
| 53 | +fn DoSomething(); |
| 54 | +``` |
| 55 | + |
| 56 | +``` |
| 57 | +impl library "MyLibrary"; |
| 58 | +
|
| 59 | +fn DoSomething() { |
| 60 | + ... |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +## Matching redeclarations of an entity |
| 65 | + |
| 66 | +In order to determine whether two redeclarations refer to the same entity, we |
| 67 | +apply the rules: |
| 68 | + |
| 69 | +- Two named declarations _declare the same entity_ if they have the same scope |
| 70 | + and the same name. This includes imported declarations. |
| 71 | +- When two named declarations declare the same entity, the second is said to |
| 72 | + be a _redeclaration_. |
| 73 | +- Two owned declarations _differ_ if they don't syntactically match. |
| 74 | + - Otherwise, if one is a non-owned `extern library` declaration, |
| 75 | + declarations differ if they don't match semantically. |
| 76 | +- The program is invalid if it contains two declarations of the same entity |
| 77 | + that differ. |
| 78 | + |
| 79 | +```carbon |
| 80 | +class A { |
| 81 | + // This function will be redeclared in order to provide a definition. |
| 82 | + fn F(n: i32); |
| 83 | +} |
| 84 | +
|
| 85 | +// ✅ Valid: The declaration matches syntactically. |
| 86 | +fn A.F(n: i32) {} |
| 87 | +
|
| 88 | +// ❌ Invalid: The parameter name differs. |
| 89 | +fn A.F(m: i32) {} |
| 90 | +
|
| 91 | +// ❌ Invalid: The parameter type differs syntactically. |
| 92 | +fn A.F(n: (i32)) {} |
| 93 | +``` |
| 94 | + |
| 95 | +### Details |
| 96 | + |
| 97 | +TODO: Figure out what details to pull from |
| 98 | +[#3762](https://github.com/carbon-language/carbon-lang/pull/3762) and |
| 99 | +[#3763](https://github.com/carbon-language/carbon-lang/pull/3763). |
| 100 | + |
| 101 | +## `extern` and `extern library` |
| 102 | + |
| 103 | +There are two forms of the `extern` modifier: |
| 104 | + |
| 105 | +- On an owning declaration, `extern` limits access to the definition. |
| 106 | + - The entity must be directly imported in order to use of the definition. |
| 107 | + - An `extern library` declaration is optional. |
| 108 | +- On a non-owning declaration, `extern library` allows references to an entity |
| 109 | + without depending on the owning library. |
| 110 | + - The library name indicates where the entity is defined. |
| 111 | + - This can be used to improve build performance, such as by splitting out |
| 112 | + a declaration in order to reduce a library's dependencies. |
| 113 | + |
| 114 | +For example, a use of both might look like: |
| 115 | + |
| 116 | +``` |
| 117 | +library "owner"; |
| 118 | +
|
| 119 | +// This `import` is required due to the `extern library`, but we also make use |
| 120 | +// of `MyClassFactory` below. This is a circular use of `MyClass` that we |
| 121 | +// couldn't split between libraries without `extern`. |
| 122 | +import library "factory"; |
| 123 | +
|
| 124 | +extern class MyClass { |
| 125 | + fn Make() -> MyClass* { |
| 126 | + return MyClassFactory(); |
| 127 | + } |
| 128 | +
|
| 129 | + var val: i32 = 0; |
| 130 | +} |
| 131 | +``` |
| 132 | + |
| 133 | +``` |
| 134 | +library "factory"; |
| 135 | +
|
| 136 | +// Declares `MyClass` so that `MyClassFactory` can return it. |
| 137 | +extern library "owner" class MyClass; |
| 138 | +
|
| 139 | +fn MyClassFactory(val: i32) -> MyClass*; |
| 140 | +``` |
| 141 | + |
| 142 | +``` |
| 143 | +impl library "factory"; |
| 144 | +
|
| 145 | +// Imports the definition of `MyClass`. |
| 146 | +import library "owner"; |
| 147 | +
|
| 148 | +extern fn MyClassFactory(val: i32) -> MyClass* { |
| 149 | + var c: MyClass* = new MyClass(); |
| 150 | + c->val = val; |
| 151 | + return c; |
| 152 | +} |
| 153 | +``` |
| 154 | + |
| 155 | +### Valid scopes for `extern` |
| 156 | + |
| 157 | +The `extern` modifier is only valid on namespace-scoped entities, including in |
| 158 | +the file scope. In other words, `class C { extern fn F(); }` is invalid. |
| 159 | + |
| 160 | +### Effect on indirect imports |
| 161 | + |
| 162 | +Indirect imports won't see the definition of an `extern` entity. We expect this |
| 163 | +to primarily affect return types of functions. If an incomplete type is |
| 164 | +encountered this way, it can be resolved by directly importing the definition. |
| 165 | +For example: |
| 166 | + |
| 167 | +``` |
| 168 | +library "type"; |
| 169 | +
|
| 170 | +// Because this is `extern`, the definition must be directly imported. |
| 171 | +extern class MyType { var x: i32 } |
| 172 | +``` |
| 173 | + |
| 174 | +``` |
| 175 | +library "make_type"; |
| 176 | +
|
| 177 | +import library "type"; |
| 178 | +
|
| 179 | +// Here we have a function which returns the type. |
| 180 | +fn MakeMyType() -> MyType*; |
| 181 | +``` |
| 182 | + |
| 183 | +``` |
| 184 | +library "invalid_use"; |
| 185 | +
|
| 186 | +import library "make_type"; |
| 187 | +
|
| 188 | +fn InvalidUse() -> i32 { |
| 189 | + // ❌ Invalid: `MyType` is incomplete because it's `extern` and not directly |
| 190 | + // imported. `x` cannot be accessed. |
| 191 | + return MakeMyType()->x; |
| 192 | +} |
| 193 | +``` |
| 194 | + |
| 195 | +``` |
| 196 | +library "valid_use"; |
| 197 | +
|
| 198 | +import library "make_type"; |
| 199 | +
|
| 200 | +// ✅ Valid: By directly importing the definition, we can now access `x`. |
| 201 | +import library "type"; |
| 202 | +
|
| 203 | +fn ValidUse() -> i32 { |
| 204 | + return MakeMyType()->x; |
| 205 | +} |
| 206 | +``` |
| 207 | + |
| 208 | +## Alternatives considered |
| 209 | + |
| 210 | +- [Other modifier keyword merging approaches](/proposals/p3762.md#other-modifier-keyword-merging-approaches) |
| 211 | +- [No `extern` keyword](/proposals/p3762.md#no-extern-keyword) |
| 212 | +- [Looser restrictions on declarations](/proposals/p3762.md#looser-restrictions-on-declarations) |
| 213 | +- [`extern` naming](/proposals/p3762.md#extern-naming) |
| 214 | +- [Default `extern` to private](/proposals/p3762.md#default-extern-to-private) |
| 215 | +- [Opaque types](/proposals/p3762.md#opaque-types) |
| 216 | +- [Require a library provide its own `extern` declarations](/proposals/p3762.md#require-a-library-provide-its-own-extern-declarations) |
| 217 | +- [Allow cross-package `extern` declarations](/proposals/p3762.md#allow-cross-package-extern-declarations) |
| 218 | +- [Use a partially or fully semantic rule](/proposals/p3763.md#use-a-partially-or-fully-semantic-rule) |
| 219 | +- [Use package-wide name poisoning](/proposals/p3763.md#use-package-wide-name-poisoning) |
| 220 | +- [Allow shadowing in implementation file after use in API file](/proposals/p3763.md#allow-shadowing-in-implementation-file-after-use-in-api-file) |
| 221 | +- [Allow multiple non-owning declarations, remove the import requirement, or both](/proposals/p3980.md#allow-multiple-non-owning-declarations-remove-the-import-requirement-or-both) |
| 222 | +- [Total number of allowed declarations (owning and non-owning)](/proposals/p3980.md#total-number-of-allowed-declarations-owning-and-non-owning) |
| 223 | + - [Do not restrict the number of forward declarations](/proposals/p3980.md#do-not-restrict-the-number-of-forward-declarations) |
| 224 | + - [Allow up to two declarations total](/proposals/p3980.md#allow-up-to-two-declarations-total) |
| 225 | + - [Allow up to four declarations total](/proposals/p3980.md#allow-up-to-four-declarations-total) |
| 226 | +- [Don't require a modifier on the owning declarations](/proposals/p3980.md#dont-require-a-modifier-on-the-owning-declarations) |
| 227 | +- [Only require `extern` on the first owning declaration](/proposals/p3980.md#only-require-extern-on-the-first-owning-declaration) |
| 228 | +- [Separate require-direct-import from non-owning declarations](/proposals/p3980.md#separate-require-direct-import-from-non-owning-declarations) |
| 229 | +- [Other `extern` syntaxes](/proposals/p3980.md#other-extern-syntaxes) |
| 230 | +- [Have types with `extern` members re-export them](/proposals/p3980.md#have-types-with-extern-members-re-export-them) |
| 231 | +- [Require syntactic matching for `extern library` declarations](/proposals/p3980.md#require-syntactic-matching-for-extern-library-declarations) |
| 232 | + |
| 233 | +## References |
| 234 | + |
| 235 | +- Proposal |
| 236 | + [#3762: Merging forward declarations](https://github.com/carbon-language/carbon-lang/pull/3762) |
| 237 | +- Proposal |
| 238 | + [#3763: Matching redeclarations](https://github.com/carbon-language/carbon-lang/pull/3763) |
| 239 | +- Proposal |
| 240 | + [#3980: Singular `extern` declarations](https://github.com/carbon-language/carbon-lang/pull/3980) |
0 commit comments