소스 검색

Revise associated types and interface parameters in Generics terminology (#1972)

Previous text was not clear, see https://discord.com/channels/655572317891461132/941071822756143115/1004607504396861540 .

Co-authored-by: Thomas Heller <thom.heller@gmail.com>
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
josh11b 3 년 전
부모
커밋
90babcddc1
1개의 변경된 파일44개의 추가작업 그리고 49개의 파일을 삭제
  1. 44 49
      docs/design/generics/terminology.md

+ 44 - 49
docs/design/generics/terminology.md

@@ -637,60 +637,55 @@ conditions on the type argument. For example: `Array(T)` might implement
 
 ## Interface type parameters and associated types
 
-Imagine an interface defining a container. Different containers will contain
-different types of values, and the container API will have to refer to that
-"element type" when defining the signature of methods like "insert" or "find".
-If that element type is a parameter (input) to the interface type, we say it is
-an _interface type parameter_; if it is an output, we say it is an _associated
-type_. An associated type is a kind of [associated entity](#associated-entity).
-
-Interface type parameter example:
+_Interface type parameters_ and _associated types_ are both ways of allowing the
+types in function signatures in an interface to vary. For example, different
+[stacks](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>) will have
+different element types. That element type would be used as the parameter type
+of the `Push` function and the return type of the `Pop` function. As
+[in Rust](https://rust-lang.github.io/rfcs/0195-associated-items.html#clearer-trait-matching),
+we can distinguish these by whether they are input parameters or output
+parameters:
 
-```
-interface StackTP(ElementType:! Type)
-  fn Push[addr me: Self*](value: ElementType);
-  fn Pop[addr me: Self*]() -> ElementType;
-}
-```
+-   An interface type parameter is a parameter or input to the interface type.
+    That means they must be specified before an implementation of the interface
+    may be determined.
+-   In contrast, associated types are outputs. This means that they are
+    determined by the implementation, and need not be specified in a type
+    constraint.
 
-Associated type example:
+Functions using an interface as a constraint need not specify the value of its
+associated types. An associated type is a kind of
+[associated entity](#associated-entity).
 
 ```
-interface StackAT {
+// Stack using associated types
+interface Stack {
   let ElementType:! Type;
   fn Push[addr me: Self*](value: ElementType);
   fn Pop[addr me: Self*]() -> ElementType;
 }
-```
-
-Associated types are particularly called for when the implementation controls
-the type, not the caller. For example, the iterator type for a container is
-specific to the container and not something you would expect a user of the
-interface to specify.
 
-```
-interface Iterator { ... }
-interface Container {
-  // This does not make sense as an parameter to the container interface,
-  // since this type is determined from the container type.
-  let IteratorType:! Iterator;
-  ...
-  fn Insert[addr me: Self*](position: IteratorType, value: ElementType);
+// Works on any type implementing `Stack`. Return type
+// is determined by the type's implementation of `Stack`.
+fn PeekAtTopOfStack[T: Stack](s: T*) -> T.ElementType {
+  let ret: T.ElementType = s->Pop();
+  s->Push(ret);
+  return ret;
 }
-class ListIterator(ElementType:! Type) {
-  ...
-  impl as Iterator;
-}
-class List(ElementType:! Type) {
-  // Iterator type is determined by the container type.
-  impl as Container where .IteratorType = ListIterator(ElementType) {
-    fn Insert[addr me: Self*](position: IteratorType, value: ElementType) {
-      ...
-    }
-  }
+
+class Fruit;
+class FruitStack {
+  // Implement `Stack` for `FruitStack`
+  // with `ElementType` set to `Fruit`.
+  impl as Stack where .ElementType == Fruit { ... }
 }
 ```
 
+Associated types are particularly called for when the implementation of the
+interface determines the type, not the caller. For example, the iterator type
+for a container is specific to the container and not something you would expect
+a user of the interface to specify.
+
 If you have an interface with type parameters, a type can have multiple impls
 for different combinations of type parameters. As a result, type parameters may
 not be deduced in a function call. However, if the interface parameters are
@@ -701,7 +696,7 @@ For example, we might have an interface that says how to perform addition with
 another type:
 
 ```
-interface Addable(T:! Type) {
+interface AddWith(T:! Type) {
   let ResultType:! Type;
   fn Add[me: Self](rhs: T) -> ResultType;
 }
@@ -710,23 +705,23 @@ interface Addable(T:! Type) {
 An `i32` value might support addition with `i32`, `u16`, and `f64` values.
 
 ```
-impl i32 as Addable(i32) where .ResultType = i32 { ... }
-impl i32 as Addable(u16) where .ResultType = i32 { ... }
-impl i32 as Addable(f64) where .ResultType = f64 { ... }
+impl i32 as AddWith(i32) where .ResultType = i32 { ... }
+impl i32 as AddWith(u16) where .ResultType = i32 { ... }
+impl i32 as AddWith(f64) where .ResultType = f64 { ... }
 ```
 
-To write a generic function requiring a parameter to be `Addable`, there needs
+To write a generic function requiring a parameter to be `AddWith`, there needs
 to be some way to determine the type to add to:
 
 ```
 // ✅ This is allowed, since the value of `T` is determined by the
 // `y` parameter.
-fn DoAdd[T:! Type, U:! Addable(T)](x: U, y: T) -> U.ResultType {
+fn DoAdd[T:! Type, U:! AddWith(T)](x: U, y: T) -> U.ResultType {
   return x.Add(y);
 }
 
 // ❌ This is forbidden, can't uniquely determine `T`.
-fn CompileError[T:! Type, U:! Addable(T)](x: U) -> T;
+fn CompileError[T:! Type, U:! AddWith(T)](x: U) -> T;
 ```
 
 Once the interface parameter can be determined, that determines the values for
@@ -734,7 +729,7 @@ associated types, such as `ResultType` in the example. As always, calls with
 types for which no implementation exists will be rejected at the call site:
 
 ```
-// ❌ This is forbidden, no implementation of `Addable(Orange)`
+// ❌ This is forbidden, no implementation of `AddWith(Orange)`
 // for `Apple`.
 DoAdd(apple, orange);
 ```