mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Support external impl in class and adapter scopes. (#905)
This commit is contained in:
@@ -449,7 +449,49 @@ external impl Point3 as Vector {
|
||||
|
||||
With this definition, `Point3` includes `Add` in its API but not `Scale`, while
|
||||
`Point3 as Vector` includes both. This maintains the property that you can
|
||||
determine the API of a type by looking at its definition.
|
||||
determine the API of a type by looking at its definition. In this case, the
|
||||
`external impl` may be defined lexically inside the scope of the class.
|
||||
|
||||
```
|
||||
class Point3 {
|
||||
var x: Double;
|
||||
var y: Double;
|
||||
fn Add[me: Self](b: Self) -> Self {
|
||||
return {.x = a.x + b.x, .y = a.y + b.y};
|
||||
}
|
||||
// Type before `as` is optional and defaults to the current class.
|
||||
external impl as Vector {
|
||||
alias Add = Point3.Add; // Syntax TBD
|
||||
fn Scale[me: Self](v: Double) -> Self {
|
||||
return {.x = a.x * v, .y = a.y * v};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OR:
|
||||
|
||||
class Point3 {
|
||||
var x: Double;
|
||||
var y: Double;
|
||||
external impl as Vector {
|
||||
fn Add[me: Self](b: Self) -> Self {
|
||||
return {.x = a.x + b.x, .y = a.y + b.y};
|
||||
}
|
||||
fn Scale[me: Self](v: Double) -> Self {
|
||||
return {.x = a.x * v, .y = a.y * v};
|
||||
}
|
||||
}
|
||||
alias Add = Vector.Add; // Syntax TBD
|
||||
}
|
||||
```
|
||||
|
||||
Being defined lexically inside the class means that implementation is available
|
||||
to other members defined in the class. For example, it would allow implementing
|
||||
another interface or method that requires this interface to be implemented.
|
||||
|
||||
**Open question:** Do implementations need to be defined lexically inside the
|
||||
class to get access to private members, or is it sufficient to be defined in the
|
||||
same library as the class?
|
||||
|
||||
**Rejected alternative:** We could allow types to have different APIs in
|
||||
different files based on explicit configuration in that file. For example, we
|
||||
@@ -1632,9 +1674,24 @@ Unlike the similar `class B extends A` notation, `adaptor B extends A` is
|
||||
permitted even if `A` is a final class. Also, there is no implicit conversion
|
||||
from `B` to `A`, matching `adapter`...`for` but unlike class extension.
|
||||
|
||||
**Future work:** We may need additional mechanisms for changing the API in the
|
||||
adapter. For example, to resolve conflicts we might want to be able to move the
|
||||
implementation of a specific interface into an [external impl](#external-impl).
|
||||
To avoid or resolve name conflicts between interfaces, an `impl` may be declared
|
||||
[`external`](#external-impl). The names in that interface may then be pulled in
|
||||
individually or renamed using `alias` declarations.
|
||||
|
||||
```
|
||||
adapter SongRenderToPrintDriver extends Song {
|
||||
// Add a new `Print()` member function.
|
||||
fn Print[me: Self]() { ... }
|
||||
|
||||
// Avoid name conflict with new `Print` function by making
|
||||
// the implementation of the `Printable` interface external.
|
||||
external impl as Printable = Song as Printable;
|
||||
|
||||
// Make the `Print` function from `Printable` available
|
||||
// under the name `PrintToScreen`.
|
||||
alias PrintToScreen = Printable.Print;
|
||||
}
|
||||
```
|
||||
|
||||
### Use case: Using independent libraries together
|
||||
|
||||
|
||||
Reference in New Issue
Block a user