浏览代码

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

josh11b 4 年之前
父节点
当前提交
b08e3fedeb
共有 1 个文件被更改,包括 61 次插入4 次删除
  1. 61 4
      docs/design/generics/details.md

+ 61 - 4
docs/design/generics/details.md

@@ -449,7 +449,49 @@ external impl Point3 as Vector {
 
 
 With this definition, `Point3` includes `Add` in its API but not `Scale`, while
 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
 `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
 **Rejected alternative:** We could allow types to have different APIs in
 different files based on explicit configuration in that file. For example, we
 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
 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.
 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
 ### Use case: Using independent libraries together