Support external impl in class and adapter scopes. (#905)

This commit is contained in:
josh11b
2021-10-26 09:25:30 -07:00
committed by GitHub
parent 8d051e2b6b
commit b08e3fedeb
+61 -4
View File
@@ -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