Explorar o código

Generics details 2: adapters, associated types, parameterized interfaces (#731)

This proposal goes into the details for these features of generics:

- adapters: for creating new types compatible with existing types but with different interface implementations
- associated types: allowing an interface implementation to specify some types to use in method signatures
- interface parameters: creating a family of interfaces, where types can implement more than one

This is a continuation of #553 . It has been summarized in these presentations:

- adapters: [1](https://docs.google.com/presentation/d/1bg6q0Q9Sk4YpRbNA3D3H34xYtaEO8ScAUNUZK2UTi80/edit?resourcekey=0-6-Y6e1mfRUmHg-Zk65Gc5A#slide=id.gcf40df1c7b_0_37) and [2](https://docs.google.com/presentation/d/17KG0TeJ4OChMRdLJPS8TE_K6SoL4lFy1FUGr2CDzX-A/edit?resourcekey=0-kLnZqd5NrbGSwmbunTyB-A#slide=id.g7a37009490_0_0)
- [associated types and interface parameters](https://docs.google.com/presentation/d/19hPpUjxQ0H1lUSLy5QjS2910Cpc7UdNKpF580fFsCGw/edit?resourcekey=0-ky9XGRC1I8X0Ffw6eqh7WQ#slide=id.p)

Co-authored-by: Wolff Dobson <wolffg@users.noreply.github.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
josh11b %!s(int64=4) %!d(string=hai) anos
pai
achega
225eda7f49

+ 747 - 37
docs/design/generics/details.md

@@ -30,12 +30,20 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
         -   [Diamond dependency issue](#diamond-dependency-issue)
     -   [Use case: overload resolution](#use-case-overload-resolution)
 -   [Type compatibility](#type-compatibility)
+-   [Adapting types](#adapting-types)
+    -   [Adapter compatibility](#adapter-compatibility)
+    -   [Extending adapter](#extending-adapter)
+    -   [Use case: Using independent libraries together](#use-case-using-independent-libraries-together)
+    -   [Adapter with stricter invariants](#adapter-with-stricter-invariants)
+    -   [Application: Defining an impl for use by other types](#application-defining-an-impl-for-use-by-other-types)
+-   [Associated constants](#associated-constants)
+    -   [Associated class functions](#associated-class-functions)
+-   [Associated types](#associated-types)
+    -   [Model](#model-1)
+-   [Parameterized interfaces](#parameterized-interfaces)
+    -   [Impl lookup](#impl-lookup)
+    -   [Parameterized structural interfaces](#parameterized-structural-interfaces)
 -   [Future work](#future-work)
-    -   [Adapting types](#adapting-types)
-    -   [Associated constants](#associated-constants)
-    -   [Associated types](#associated-types)
-    -   [Parameterized interfaces](#parameterized-interfaces)
-        -   [Impl lookup](#impl-lookup)
     -   [Constraints](#constraints)
     -   [Conditional conformance](#conditional-conformance)
     -   [Parameterized impls](#parameterized-impls)
@@ -183,13 +191,11 @@ interface Vector {
 }
 ```
 
-The syntax here is to match how the same members would be defined in a type.
-Each declaration in the interface defines an _associated item_ (same
-[terminology as Rust](https://doc.rust-lang.org/reference/items/associated-items.html)).
-In this example, `Vector` has two associated methods, `Add` and `Scale`.
-
-**References:** Method syntax for types was decided in
-[question-for-leads issue #494](https://github.com/carbon-language/carbon-lang/issues/494).
+The syntax here is to match
+[how the same members would be defined in a type](/docs/design/classes.md#methods).
+Each declaration in the interface defines an
+[associated entity](terminology.md#associated-entity). In this example, `Vector`
+has two associated methods, `Add` and `Scale`.
 
 An interface defines a type-of-type, that is a type whose values are types. The
 values of an interface are specifically
@@ -203,7 +209,7 @@ interface.
 Carbon interfaces are ["nominal"](terminology.md#nominal-interfaces), which
 means that types explicitly describe how they implement interfaces. An
 ["impl"](terminology.md#impls-implementations-of-interfaces) defines how one
-interface is implemented for a type. Every associated item is given a
+interface is implemented for a type. Every associated entity is given a
 definition. Different types satisfying `Vector` can have different definitions
 for `Add` and `Scale`, so we say their definitions are _associated_ with what
 type is implementing `Vector`. The `impl` defines what is associated with the
@@ -327,7 +333,7 @@ class GameBoard {
     fn Draw[me: Self]() { ... }
   }
   impl as EndOfGame {
-    // Error: `GameBoard` has two methods named
+    // Error: `GameBoard` has two methods named
     // `Draw` with the same signature.
     fn Draw[me: Self]() { ... }
     fn Winner[me: Self](player: Int) { ... }
@@ -405,7 +411,7 @@ visible:
 ```
 var a: Point2 = (.x = 1.0, .y = 2.0);
 // `a` does *not* have `Add` and `Scale` methods:
-// Error: a.Add(a.Scale(2.0));
+// Error: a.Add(a.Scale(2.0));
 
 // Cast from Point2 implicitly
 var b: Point2 as Vector = a;
@@ -567,7 +573,7 @@ However, for another type implementing `Vector` but out-of-line using an
 
 ```
 fn AddAndScaleForPoint2(a: Point2, b: Point2, s: Double) -> Point2 {
-  // ERROR: `Point2` doesn't have `Add` or `Scale` methods.
+  // ERROR: `Point2` doesn't have `Add` or `Scale` methods.
   return a.Add(b).Scale(s);
 }
 ```
@@ -1144,7 +1150,7 @@ interface ConvertibleTo(T:! Type) { ... }
 
 // A type can only implement `PreferredConversion` once.
 interface PreferredConversion {
-  let AssociatedType: Type;
+  let AssociatedType:! Type;
   extends ConvertibleTo(AssociatedType);
 }
 ```
@@ -1422,38 +1428,742 @@ var m: HashMap(String, Int);
 PrintValue(m, "key");
 ```
 
-## Future work
-
-### Adapting types
+## Adapting types
 
 Since interfaces may only be implemented for a type once, and we limit where
 implementations may be added to a type, there is a need to allow the user to
-switch the type of a value to access different interface implementations. See
-["adapting a type" in the terminology document](terminology.md#adapting-a-type).
+switch the type of a value to access different interface implementations. We
+therefore provide a way to create new types
+[compatible with](terminology.md#compatible-types) existing types with different
+APIs, in particular with different interface implementations, by
+[adapting](terminology.md#adapting-a-type) them:
+
+```
+interface Printable {
+  fn Print[me: Self]();
+}
+interface Comparable {
+  fn Less[me: Self](that: Self) -> Bool;
+}
+class Song {
+  impl as Printable { fn Print[me: Self]() { ... } }
+}
+adapter SongByTitle for Song {
+  impl as Comparable {
+    fn Less[me: Self](that: Self) -> Bool { ... }
+  }
+}
+adapter FormattedSong for Song {
+  impl as Printable { fn Print[me: Self]() { ... } }
+}
+adapter FormattedSongByTitle for Song {
+  impl as Printable = FormattedSong as Printable;
+  impl as Comparable = SongByTitle as Comparable;
+}
+```
+
+This allows us to provide implementations of new interfaces (as in
+`SongByTitle`), provide different implementations of the same interface (as in
+`FormattedSong`), or mix and match implementations from other compatible types
+(as in `FormattedSongByTitle`). The rules are:
+
+-   You can add any declaration that you could add to a class except for
+    declarations that would change the representation of the type. This means
+    you can add functions, interface implementations, and aliases, but not
+    fields, base classes, or virtual functions.
+-   The adapted type is compatible with the original type, and that relationship
+    is an equivalence class, so all of `Song`, `SongByTitle`, `FormattedSong`,
+    and `FormattedSongByTitle` end up compatible with each other.
+-   Since adapted types are compatible with the original type, you may
+    explicitly cast between them, but there is no implicit casting between these
+    types (unlike between a type and one of its facet types / impls).
+-   For the purposes of generics, we only need to support adding interface
+    implementations. But this `adapter` feature could be used more generally,
+    such as to add methods.
+
+Inside an adapter, the `Self` type matches the adapter. Members of the original
+type may be accessed like any other facet type; either by a cast:
+
+```
+adapter SongByTitle for Song {
+  impl as Comparable {
+    fn Less[me: Self](that: Self) -> Bool {
+      return (this as Song).Title() < (that as Song).Title();
+    }
+  }
+}
+```
+
+or using qualified names:
+
+```
+adapter SongByTitle for Song {
+  impl as Comparable {
+    fn Less[me: Self](that: Self) -> Bool {
+      return this.(Song.Title)() < that(Song.Title)();
+    }
+  }
+}
+```
+
+**Open question:** As an alternative to:
+
+```
+impl as Printable = FormattedSong as Printable;
+```
+
+we could allow users to write:
+
+```
+impl as Printable = FormattedSong;
+```
+
+This would remove ceremony that the compiler doesn't need. The concern is
+whether it makes sense or is a category error. In this example, is
+`FormattedSong`, a type, a suitable value to provide when asking for a
+`Printable` implementation? An argument for this terser syntax is that the
+implicit conversion is legal in other contexts:
+
+```
+// ✅ Legal implicit conversion
+var v:! Printable = FormattedSong;
+```
+
+**Comparison with other languages:** This matches the Rust idiom called
+"newtype", which is used to implement traits on types while avoiding coherence
+problems, see
+[here](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types)
+and
+[here](https://github.com/Ixrec/rust-orphan-rules#user-content-why-are-the-orphan-rules-controversial).
+Rust's mechanism doesn't directly support reusing implementations, though some
+of that is provided by macros defined in libraries. Haskell has a
+[`newtype` feature](https://wiki.haskell.org/Newtype) as well. Haskell's feature
+doesn't directly support reusing implementations either, but the most popular
+compiler provides it as
+[an extension](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/newtype_deriving.html).
+
+### Adapter compatibility
+
+The framework from the [type compatibility section](#type-compatibility) allows
+us to evaluate when we can cast between two different arguments to a
+parameterized type. Consider three compatible types, all of which implement
+`Hashable`:
+
+```
+class Song {
+  impl as Hashable { ... }
+  impl as Printable { ... }
+}
+adapter SongHashedByTitle for Song {
+  impl as Hashable { ... }
+}
+adapter PlayableSong for Song {
+  impl as Hashable = Song as Hashable;
+  impl as Media { ... }
+}
+```
+
+Observe that `Song as Hashable` is different from
+`SongHashedByTitle as Hashable`, since they have different definitions of the
+`Hashable` interface even though they are compatible types. However
+`Song as Hashable` and `PlayableSong as Hashable` are almost the same. In
+addition to using the same data representation, they both implement one
+interface, `Hashable`, and use the same implementation for that interface. The
+one difference between them is that `Song as Hashable` may be implicitly cast to
+`Song`, which implements interface `Printable`, and `PlayableSong as Hashable`
+may be implicilty cast to `PlayableSong`, which implements interface `Media`.
+This means that it is safe to cast between
+`HashMap(Song, Int) == HashMap(Song as Hashable, Int)` and
+`HashMap(PlayableSong, Int) == HashMap(PlayableSong as Hashable, Int)` (though
+maybe only with an explicit cast) but
+`HashMap(SongHashedByTitle, Int) == HashMap(SongHashByTitle as Hashable, Int)`
+is incompatible. This is a relief, because we know that in practice the
+invariants of a `HashMap` implementation rely on the hashing function staying
+the same.
+
+### Extending adapter
+
+Frequently we expect that the adapter type will want to preserve most or all of
+the API of the original type. The two most common cases expected are adding and
+replacing an interface implementation. Users would indicate that an adapter
+starts from the original type's existing API by using the `extends` keyword
+instead of `for`:
+
+```
+class Song {
+  impl as Hashable { ... }
+  impl as Printable { ... }
+}
+
+adapter SongByArtist extends Song {
+  // Add an implementation of a new interface
+  impl as Comparable { ... }
+
+  // Replace an existing implementation of an interface
+  // with an alternative.
+  impl as Hashable { ... }
+}
+```
+
+The resulting type `SongByArtist` would:
+
+-   implement `Comparable`, unlike `Song`,
+-   implement `Hashable`, but differently than `Song`, and
+-   implement `Printable`, inherited from `Song`.
+
+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).
+
+### Use case: Using independent libraries together
+
+Imagine we have two packages that are developed independently. Package
+`CompareLib` defines an interface `CompareLib.Comparable` and a generic
+algorithm `CompareLib.Sort` that operates on types that implement
+`CompareLib.Comparable`. Package `SongLib` defines a type `SongLib.Song`.
+Neither has a dependency on the other, so neither package defines an
+implementation for `CompareLib.Comparable` for type `SongLib.Song`. A user that
+wants to pass a value of type `SongLib.Song` to `CompareLib.Sort` has to define
+an adapter that provides an implementation of `CompareLib.Comparable` for
+`SongLib.Song`. This adapter will probably use the
+[`extends` facility of adapters](#extending-adapter) to preserve the
+`SongLib.Song` API.
+
+```
+import CompareLib;
+import SongLib;
+
+adapter Song extends SongLib.Song {
+  impl as CompareLib.Comparable { ... }
+}
+// Or, to keep the names from CompareLib.Comparable out of Song's API:
+adapter Song extends SongLib.Song { }
+external impl Song as CompareLib.Comparable { ... }
+```
+
+The caller can either cast `SongLib.Song` values to `Song` when calling
+`CompareLib.Sort` or just start with `Song` values in the first place.
+
+```
+var lib_song: SongLib.Song = ...;
+CompareLib.Sort((lib_song as Song,));
+
+var song: Song = ...;
+CompareLib.Sort((song,));
+```
+
+### Adapter with stricter invariants
+
+**Future work:** Rust also uses the newtype idiom to create types with
+additional invariants or other information encoded in the type
+([1](https://doc.rust-lang.org/rust-by-example/generics/new_types.html),
+[2](https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction),
+[3](https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)).
+This is used to record in the type system that some data has passed validation
+checks, like `ValidDate` with the same data layout as `Date`. Or to record the
+units associated with a value, such as `Seconds` versus `Milliseconds` or `Feet`
+versus `Meters`. We should have some way of restricting the casts between a type
+and an adapter to address this use case.
+
+### Application: Defining an impl for use by other types
+
+Let's say we want to provide a possible implementation of an interface for use
+by types for which that implementation would be appropriate. We can do that by
+defining an adapter implementing the interface that is parameterized on the type
+it is adapting. That impl may then be pulled in using the `impl as ... = ...;`
+syntax.
+
+```
+interface Comparable {
+  fn Less[me: Self](that: Self) -> Bool;
+}
+adapter ComparableFromDifferenceFn
+    (T:! Type, Difference:! fnty(T, T)->Int) for T {
+  impl as Comparable {
+    fn Less[me: Self](that: Self) -> Bool {
+      return Difference(this, that) < 0;
+    }
+  }
+}
+class IntWrapper {
+  var x: Int;
+  fn Difference(this: Self, that: Self) {
+    return that.x - this.x;
+  }
+  impl as Comparable =
+      ComparableFromDifferenceFn(IntWrapper, Difference)
+      as Comparable;
+}
+```
+
+## Associated constants
+
+In addition to associated methods, we allow other kinds of
+[associated entities](terminology.md#associated-entity). For consistency, we use
+the same syntax to describe a constant in an interface as in a type without
+assigning a value. As constants, they are declared using the `let` introducer.
+For example, a fixed-dimensional point type could have the dimension as an
+associated constant.
+
+```
+interface NSpacePoint {
+  let N:! Int;
+  // The following require: 0 <= i < N.
+  fn Get[addr me: Self*](i: Int) -> Float64;
+  fn Set[addr me: Self*](i: Int, value: Float64);
+  // Associated constants may be used in signatures:
+  fn SetAll[addr me: Self*](value: Array(Float64, N));
+}
+```
+
+Implementations of `NSpacePoint` for different types might have different values
+for `N`:
+
+```
+class Point2D {
+  impl as NSpacePoint {
+    let N:! Int = 2;
+    fn Get[addr me: Self*](i: Int) -> Float64 { ... }
+    fn Set[addr me: Self*](i: Int, value: Float64) { ... }
+    fn SetAll[addr me: Self*](value: Array(Float64, 2)) { ... }
+  }
+}
+
+class Point3D {
+  impl as NSpacePoint {
+    let N:! Int = 3;
+    fn Get[addr me: Self*](i: Int) -> Float64 { ... }
+    fn Set[addr me: Self*](i: Int, value: Float64) { ... }
+    fn SetAll[addr me: Self*](value: Array(Float64, 3)) { ... }
+  }
+}
+```
+
+And these values may be accessed as members of the type:
+
+```
+Assert(Point2D.N == 2);
+Assert(Point3D.N == 3);
+
+fn PrintPoint[PointT:! NSpacePoint](p: PointT) {
+  for (var i: Int = 0; i < PointT.N; ++i) {
+    if (i > 0) { Print(", "); }
+    Print(p.Get(i));
+  }
+}
+
+fn ExtractPoint[PointT:! NSpacePoint](
+    p: PointT,
+    dest: Array(Float64, PointT.N)*) {
+  for (var i: Int = 0; i < PointT.N; ++i) {
+    (*dest)[i] = p.Get(i);
+  }
+}
+```
+
+**Comparison with other languages:** This feature is also called
+[associated constants in Rust](https://doc.rust-lang.org/reference/items/associated-items.html#associated-constants).
+
+**Aside:** In general, the use of `:!` here means these `let` declarations will
+only have compile-time and not runtime storage associated with them.
+
+### Associated class functions
+
+To be consistent with normal
+[class function](/docs/design/classes.md#class-functions) declaration syntax,
+associated class functions are written:
+
+```
+interface DeserializeFromString {
+  fn Deserialize(serialized: String) -> Self;
+}
+
+class MySerializableType {
+  var i: Int;
+
+  impl as DeserializeFromString {
+    fn Deserialize(serialized: String) -> Self {
+      return (.i = StringToInt(serialized));
+    }
+  }
+}
+
+var x: MySerializableType = MySerializableType.Deserialize("3");
+
+fn Deserialize(T:! DeserializeFromString, serialized: String) -> T {
+  return T.Deserialize(serialized);
+}
+var y: MySerializableType = Deserialize(MySerializableType, "4");
+```
+
+This is instead of declaring an associated constant using `let` with a function
+type.
+
+Together associated methods and associated class functions are called
+_associated functions_, much like together methods and class functions are
+called [member functions](/docs/design/classes.md#member-functions).
+
+## Associated types
+
+Associated types are [associated entities](terminology.md#associated-entity)
+that happen to be types. These are particularly interesting since they can be
+used in the signatures of associated methods or functions, to allow the
+signatures of methods to vary from implementation to implementation. We already
+have one example of this: the `Self` type discussed
+[above in the "Interfaces" section](#interfaces). For other cases, we can say
+that the interface declares that each implementation will provide a type under a
+specific name. For example:
+
+```
+interface StackAssociatedType {
+  let ElementType:! Type;
+  fn Push[addr me: Self*](value: ElementType);
+  fn Pop[addr me: Self*]() -> ElementType;
+  fn IsEmpty[addr me: Self*]() -> Bool;
+}
+```
+
+Here we have an interface called `StackAssociatedType` which defines two
+methods, `Push` and `Pop`. The signatures of those two methods declare them as
+accepting or returning values with the type `ElementType`, which any implementer
+of `StackAssociatedType` must also define. For example, maybe `DynamicArray`
+implements `StackAssociatedType`:
+
+```
+class DynamicArray(T:! Type) {
+  class IteratorType { ... }
+  fn Begin[addr me: Self*]() -> IteratorType;
+  fn End[addr me: Self*]() -> IteratorType;
+  fn Insert[addr me: Self*](pos: IteratorType, value: T);
+  fn Remove[addr me: Self*](pos: IteratorType);
+
+  impl as StackAssociatedType {
+    // Set the associated type `ElementType` to `T`.
+    let ElementType:! Type = T;
+    fn Push[addr me: Self*](value: ElementType) {
+      this->Insert(this->End(), value);
+    }
+    fn Pop[addr me: Self*]() -> ElementType {
+      var pos: IteratorType = this->End();
+      Assert(pos != this->Begin());
+      --pos;
+      returned var ret: ElementType = *pos;
+      this->Remove(pos);
+      return var;
+    }
+    fn IsEmpty[addr me: Self*]() -> Bool {
+      return this->Begin() == this->End();
+    }
+  }
+}
+```
+
+**Alternatives considered:** See
+[other syntax options considered for specifying associated types](/proposals/p0731.md#syntax-for-associated-constants).
+In particular, it was deemed that
+[Swift's approach of inferring the associated type from method signatures in the impl](https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID190)
+was unneeded complexity.
 
-### Associated constants
+The definition of the `StackAssociatedType` is sufficient for writing a generic
+function that operates on anything implementing that interface, for example:
 
-In addition to associated methods, we will allow other kinds of associated items
-associating values with types implementing an interface.
+```
+fn PeekAtTopOfStack[StackType:! StackAssociatedType](s: StackType*)
+    -> StackType.ElementType {
+  var top: StackType.ElementType = s->Pop();
+  s->Push(top);
+  return top;
+}
+
+var my_array: DynamicArray(i32) = (1, 2, 3);
+// PeekAtTopOfStack's `StackType` is set to
+// `DynamicArray(i32) as StackAssociatedType`.
+// `StackType.ElementType` becomes `i32`.
+Assert(PeekAtTopOfStack(my_array) == 3);
+```
+
+Associated types can also be implemented using a
+[member type](/docs/design/classes.md#member-type).
+
+```
+interface Container {
+  let IteratorType:! Iterator;
+  ...
+}
 
-### Associated types
+class DynamicArray(T:! Type) {
+  ...
+  impl as Container {
+    class IteratorType { ... }
+    ...
+  }
+}
+```
+
+For context, see
+["Interface type parameters and associated types" in the generics terminology document](terminology.md#interface-type-parameters-versus-associated-types).
 
-Associated types are associated constants that happen to be types. These are
-particularly interesting since they can be used in the signatures of associated
-methods or functions, to allow the signatures of methods to vary from
-implementation to implementation.
+**Comparison with other languages:** Both
+[Rust](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#specifying-placeholder-types-in-trait-definitions-with-associated-types)
+and [Swift](https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID189)
+support associated types.
 
-### Parameterized interfaces
+### Model
+
+The associated type can be modeled by a witness table field in the interface's
+witness table.
+
+```
+interface Iterator {
+  fn Advance[addr me: Self*]();
+}
+
+interface Container {
+  let IteratorType:! Iterator;
+  fn Begin[addr me: Self*]() -> IteratorType;
+}
+```
+
+is represented by:
+
+```
+class Iterator(Self:! Type) {
+  var Advance: fnty(this: Self*);
+  ...
+}
+class Container(Self:! Type) {
+  // Representation type for the iterator.
+  let IteratorType:! Type;
+  // Witness that IteratorType implements Iterator.
+  var iterator_impl: Iterator(IteratorType)*;
+
+  // Method
+  var Begin: fnty (this: Self*) -> IteratorType;
+  ...
+}
+```
+
+## Parameterized interfaces
 
 Associated types don't change the fact that a type can only implement an
-interface at most once. If instead you want a family of related interfaces, each
-of which could be implemented for a given type, you could use parameterized
-interfaces instead.
+interface at most once.
+
+If instead you want a family of related interfaces, one per possible value of a
+type parameter, multiple of which could be implemented for a single type, you
+would use parameterized interfaces. To write a parameterized version the stack
+interface instead of using associated types, write a parameter list after the
+name of the interface instead of the associated type declaration:
+
+```
+interface StackParameterized(ElementType:! Type) {
+  fn Push[addr me: Self*](value: ElementType);
+  fn Pop[addr me: Self*]() -> ElementType;
+  fn IsEmpty[addr me: Self*]() -> Bool;
+}
+```
+
+Then `StackParameterized(Fruit)` and `StackParameterized(Veggie)` would be
+considered different interfaces, with distinct implementations.
+
+```
+class Produce {
+  var fruit: DynamicArray(Fruit);
+  var veggie: DynamicArray(Veggie);
+  impl as StackParameterized(Fruit) {
+    fn Push[addr me: Self*](value: Fruit) {
+      this->fruit.Push(value);
+    }
+    fn Pop[addr me: Self*]() -> Fruit {
+      return this->fruit.Pop();
+    }
+    fn IsEmpty[addr me: Self*]() -> Bool {
+      return this->fruit.IsEmpty();
+    }
+  }
+  impl as StackParameterized(Veggie) {
+    fn Push[addr me: Self*](value: Veggie) {
+      this->veggie.Push(value);
+    }
+    fn Pop[addr me: Self*]() -> Veggie {
+      return this->veggie.Pop();
+    }
+    fn IsEmpty[addr me: Self*]() -> Bool {
+      return this->veggie.IsEmpty();
+    }
+  }
+}
+```
+
+Unlike associated types in interfaces and parameters to types, interface
+parameters can't be deduced. For example, if we were to rewrite
+[the `PeekAtTopOfStack` example in the "associated types" section](#associated-types)
+for `StackParameterized(T)` it would generate a compile error:
+
+```
+// ❌ Error: can't deduce interface parameter `T`.
+fn BrokenPeekAtTopOfStackParameterized
+    [T:! Type, StackType:! StackParameterized(T)]
+    (s: StackType*) -> T { ... }
+```
+
+This error is because the compiler can not determine if `T` should be `Fruit` or
+`Veggie` when passing in argument of type `Produce*`. The function's signature
+would have to be changed so that the value for `T` could be determined from the
+explicit parameters.
+
+```
+fn PeekAtTopOfStackParameterized
+    [T:! Type, StackType:! StackParameterized(T)]
+    (s: StackType*, _: singleton_type_of(T)) -> T { ... }
+
+var produce: Produce = ...;
+var top_fruit: Fruit =
+    PeekAtTopOfStackParameterized(&produce, Fruit);
+var top_veggie: Veggie =
+    PeekAtTopOfStackParameterized(&produce, Veggie);
+```
+
+The pattern `_: singleton_type_of(T)` is a placeholder syntax for an expression
+that will only match `T`, until issue
+[#578: Value patterns as function parameters](https://github.com/carbon-language/carbon-lang/issues/578)
+is resolved. Using that pattern in the explicit parameter list allows us to make
+`T` available earlier in the declaration so it can be passed as the argument to
+the parameterized interface `StackParameterized`.
+
+This approach is useful for the `ComparableTo(T)` interface, where a type might
+be comparable with multiple other types, and in fact interfaces for
+[operator overloads](#operator-overloading) more generally. Example:
+
+```
+interface EquatableWith(T:! Type) {
+  fn Equals[me: Self](that: T) -> Bool;
+  ...
+}
+class Complex {
+  var real: f64;
+  var imag: f64;
+  // Can implement this interface more than once as long as it has different
+  // arguments.
+  impl as EquatableWith(Complex) { ... }
+  impl as EquatableWith(f64) { ... }
+}
+```
+
+All interface parameters must be marked as "generic", using the `:!` syntax.
+This reflects these two properties of these parameters:
+
+-   They must be resolved at compile-time, and so can't be passed regular
+    dynamic values.
+-   We allow either generic or template values to be passed in.
+
+**Context:** See
+[interface type parameters](terminology.md#interface-type-parameters-versus-associated-types)
+in the terminology doc.
+
+**Note:** Interface parameters aren't required to be types, but that is the vast
+majority of cases. As an example, if we had an interface that allowed a type to
+define how the tuple-member-read operator would work, the index of the member
+could be an interface parameter:
+
+```
+interface ReadTupleMember(index:! u32) {
+  let T:! Type;
+  // Returns me[index]
+  fn Get[me: Self]() -> T;
+}
+```
+
+This requires that the index be known at compile time, but allows different
+indices to be associated with different types.
+
+**Caveat:** When implementing an interface twice for a type, you need to be sure
+that the interface parameters will always be different. For example:
+
+```
+interface Map(FromType:! Type, ToType:! Type) {
+  fn Map[addr me: Self*](needle: FromType) -> Optional(ToType);
+}
+class Bijection(FromType:! Type, ToType:! Type) {
+  impl as Map(FromType, ToType) { ... }
+  impl as Map(ToType, FromType) { ... }
+}
+// ❌ Error: Bijection has two impls of interface Map(String, String)
+var oops: Bijection(String, String) = ...;
+```
 
-#### Impl lookup
+In this case, it would be better to have an [adapting type](#adapting-types) to
+contain the `impl` for the reverse map lookup, instead of implementing the `Map`
+interface twice:
 
-We will have rules limiting where interface implementations are defined for
-coherence.
+```
+class Bijection(FromType:! Type, ToType:! Type) {
+  impl as Map(FromType, ToType) { ... }
+}
+adapter ReverseLookup(FromType:! Type, ToType:! Type)
+    for Bijection(FromType, ToType) {
+  impl as Map(ToType, FromType) { ... }
+}
+```
+
+**Comparison with other languages:** Rust calls
+[traits with type parameters "generic traits"](https://doc.rust-lang.org/reference/items/traits.html#generic-traits)
+and
+[uses them for operator overloading](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#default-generic-type-parameters-and-operator-overloading).
+Note that Rust further supports defaults for those type parameters (such as
+`Self`).
+
+[Rust uses the term "type parameters"](https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md#clearer-trait-matching)
+for both interface type parameters and associated types. The difference is that
+interface parameters are "inputs" since they _determine_ which `impl` to use,
+and associated types are "outputs" since they are determined _by_ the `impl`,
+but play no role in selecting the `impl`.
+
+### Impl lookup
+
+Let's say you have some interface `I(T, U(V))` being implemented for some type
+`A(B(C(D), E))`. To satisfy the orphan rule for coherence, that `impl` must be
+defined in some library that must be imported in any code that looks up whether
+that interface is implemented for that type. This requires that `impl` is
+defined in the same library that defines the interface or one of the names
+needed by the type. That is, the `impl` must be defined with one of `I`, `T`,
+`U`, `V`, `A`, `B`, `C`, `D`, or `E`. We further require anything looking up
+this `impl` to import the _definitions_ of all of those names. Seeing a forward
+declaration of these names is insufficient, since you can presumably see forward
+declarations without seeing an `impl` with the definition. This accomplishes a
+few goals:
+
+-   The compiler can check that there is only one definition of any `impl` that
+    is actually used, avoiding
+    [One Definition Rule (ODR)](https://en.wikipedia.org/wiki/One_Definition_Rule)
+    problems.
+-   Every attempt to use an `impl` will see the exact same `impl`, making the
+    interpretation and semantics of code consistent no matter its context, in
+    accordance with the
+    [low context-sensitivity principle](/docs/project/principles/low_context_sensitivity.md).
+-   Allowing the `impl` to be defined with either the interface or the type
+    addresses the
+    [expression problem](https://eli.thegreenplace.net/2016/the-expression-problem-and-its-solutions).
+
+Note that [the rules for specialization](#lookup-resolution-and-specialization)
+do allow there to be more than one `impl` to be defined for a type, as long as
+one can unambiguously be picked as most specific.
+
+**References:** Implementation coherence is
+[defined in terminology](terminology.md#coherence), and is
+[a goal for Carbon](goals.md#coherence). More detail can be found in
+[this appendix with the rationale and alternatives considered](appendix-coherence.md).
+
+### Parameterized structural interfaces
+
+We should also allow the [structural interface](#structural-interfaces)
+construct to support parameters. Parameters would work the same way as for
+regular, that is nominal or non-structural, interfaces.
+
+## Future work
 
 ### Constraints
 

+ 101 - 16
docs/design/generics/overview.md

@@ -29,6 +29,10 @@ pointers to other design documents that dive deeper into individual topics.
     -   [Combining interfaces](#combining-interfaces)
         -   [Structural interfaces](#structural-interfaces)
         -   [Type erasure](#type-erasure)
+    -   [Adapting types](#adapting-types)
+    -   [Interface input and output types](#interface-input-and-output-types)
+        -   [Associated types](#associated-types)
+        -   [Parameterized interfaces](#parameterized-interfaces)
 -   [Future work](#future-work)
 
 <!-- tocstop -->
@@ -55,7 +59,7 @@ Summary of how Carbon generics work:
     They are used to avoid writing specialized, near-duplicate code for similar
     situations.
 -   Generics are written using _interfaces_ which have a name and describe
-    methods, functions, and other items for types to implement.
+    methods, functions, and other entities for types to implement.
 -   Types must explicitly _implement_ interfaces to indicate that they support
     its functionality. A given type may implement an interface at most once.
 -   Implementations may be part of the type's definition, in which case you can
@@ -140,8 +144,8 @@ requirements were sufficient.
 
 #### Defining interfaces
 
-Interfaces, then, have a name and describe methods, functions, and other items
-for types to implement.
+Interfaces, then, have a name and describe methods, functions, and other
+entities for types to implement.
 
 Example:
 
@@ -464,19 +468,100 @@ At that point, two erasures occur:
     of `PrintIt` you can cast a `CDCover as Printable` value back to `CDCover`.
     Inside of `PrintIt`, you can't cast `p` or `T` back to `CDCover`.
 
+### Adapting types
+
+Carbon has a mechanism called "adapting types" to create new types that are
+compatible with existing types but with different interface implementations.
+This could be used to add or replace implementations, or define implementations
+for reuse.
+
+In this example, we have multiple ways of sorting a collection of `Song` values.
+
+```
+class Song { ... }
+
+adapter SongByArtist extends Song {
+  impl as Comparable { ... }
+}
+
+adapter SongByTitle extends Song {
+  impl as Comparable { ... }
+}
+```
+
+Values of type `Song` may be cast to `SongByArtist` or `SongByTitle` to get a
+specific sort order.
+
+### Interface input and output types
+
+[Associated types and interface parameters](terminology.md#interface-type-parameters-and-associated-types)
+allow function signatures to vary with the implementing type. The biggest
+difference between these is that associated types ("output types") may be
+deduced from a type, and types can implement the same interface multiple times
+with different interface parameters ("input types").
+
+#### Associated types
+
+Expect types that vary in an interface to be associated types by default. Since
+associated types may be deduced, they are more convenient to use. Imagine a
+`Stack` interface. Different types implementing `Stack` will have different
+element types:
+
+```
+interface Stack {
+  let ElementType:! Movable;
+  fn Push[addr me: Self*](value: ElementType);
+  fn Pop[addr me: Self*]() -> ElementType;
+  fn IsEmpty[addr me: Self*]() -> Bool;
+}
+```
+
+`ElementType` is an associated type of the interface `Stack`. Types that
+implement `Stack` give `ElementType` a specific value of some type implementing
+`Movable`. Functions that accept a type implementing `Stack` can deduce the
+`ElementType` from the stack type.
+
+```
+// ✅ This is allowed, since the type of the stack will determine
+// `ElementType`.
+fn PeekAtTopOfStack[StackType:! Stack](s: StackType*)
+    -> StackType.ElementType;
+```
+
+#### Parameterized interfaces
+
+Parameterized interfaces are commonly associated with overloaded operators.
+Imagine an interface for determining if two values are equivalent that allows
+those types to be different. An element in a hash map might have type
+`Pair(String, i64)` that implements both `Equatable(String)` and
+`Equatable(Pair(String, i64))`.
+
+```
+interface Equatable(T:! Type) {
+  fn IsEqual[me: Self](compare_to: T) -> Bool;
+}
+```
+
+`T` is a parameter to interface `Equatable`. A type can implement `Equatable`
+multiple times as long as each time it is with a different value of the `T`
+parameter. Functions may accept types implementing `Equatable(i32)` or
+`Equatable(f32)`. Functions can't accept types implementing `Equatable(T)` in
+general, unless some other parameter determines `T`.
+
+```
+// ✅ This is allowed, since the value of `T` is determined by the
+// `v` parameter.
+fn FindInVector[T:! Type, U:! Equatable(T)](v: Vector(T), needle: U)
+    -> Optional(i32);
+
+// ❌ This is forbidden. Since `U` could implement `Equatable`
+// multiple times, there is no way to determine the value for `T`.
+// Contrast with `PeekAtTopOfStack` in the associated type example.
+fn CompileError[T:! Type, U:! Equatable(T)](x: U) -> T;
+```
+
 ## Future work
 
--   Be able to have non-type generic parameters like the `UInt` size of an array
-    or tuple.
--   A "newtype" mechanism called "adapting types" may be provided to create new
-    types that are compatible with existing types but with different interface
-    implementations. This could be used to add or replace implementations, or
-    define implementations for reuse.
--   Associated types and interface parameters will be provided to allow function
-    signatures to vary with the implementing type. The biggest difference
-    between these is that associated types ("output types") may be deduced from
-    a type, and types can implement the same interface multiple times with
-    different interface parameters ("input types").
 -   Other kinds of constraints will be finalized.
 -   Implementations can be parameterized to apply to multiple types. These
     implementations would be restricted to various conditions are true for the
@@ -484,8 +569,8 @@ At that point, two erasures occur:
     specialization rule that picks the more specific one.
 -   Support functions should have a way to accept types that types that vary at
     runtime.
--   You should have the ability to mark items as `upcoming` or `deprecated` to
-    support evolution.
+-   You should have the ability to mark entities as `upcoming` or `deprecated`
+    to support evolution.
 -   Types should be able to define overloads for operators by implementing
     standard interfaces.
 -   There should be a way to provide default implementations of methods in

+ 98 - 33
docs/design/generics/terminology.md

@@ -24,6 +24,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 -   [Interface](#interface)
     -   [Structural interfaces](#structural-interfaces)
     -   [Nominal interfaces](#nominal-interfaces)
+-   [Associated entity](#associated-entity)
 -   [Impls: Implementations of interfaces](#impls-implementations-of-interfaces)
 -   [Compatible types](#compatible-types)
 -   [Subtyping and casting](#subtyping-and-casting)
@@ -39,7 +40,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Template specialization](#template-specialization)
     -   [Generic specialization](#generic-specialization)
 -   [Conditional conformance](#conditional-conformance)
--   [Interface type parameters versus associated types](#interface-type-parameters-versus-associated-types)
+-   [Interface type parameters and associated types](#interface-type-parameters-and-associated-types)
 -   [Type constraints](#type-constraints)
 -   [Type-of-type](#type-of-type)
 
@@ -51,7 +52,7 @@ Generally speaking, when we talk about either templates or a generics system, we
 are talking about generalizing some language construct by adding a parameter to
 it. Language constructs here primarily would include functions and types, but we
 may want to support parameterizing other language constructs like
-[interfaces](#interface-type-parameters-versus-associated-types).
+[interfaces](#interface-type-parameters-and-associated-types).
 
 This parameter broadens the scope of the language construct on an axis defined
 by that parameter, for example it could define a family of functions instead of
@@ -296,14 +297,30 @@ We use the "structural" versus "nominal" terminology as a generalization of the
 same terms being used in a
 [subtyping context](https://en.wikipedia.org/wiki/Subtyping#Subtyping_schemes).
 
+## Associated entity
+
+An _associated entity_ is a requirement in an interface that a type's
+implementation of the interface must satisfy by having a matching member. A
+requirement that the type define a value for a member constant is called an
+_associated constant_, and similarly an _associated function_ or _associated
+type_.
+
+Different types can satisfy an interface with different definitions for a given
+member. These definitions are _associated_ with what type is implementing the
+interface. An [impl](#impls-implementations-of-interfaces) defines what is
+associated with the type for that interface.
+
+Rust uses the term
+["associated item"](https://doc.rust-lang.org/reference/items/associated-items.html)
+instead of associated entity.
+
 ## Impls: Implementations of interfaces
 
 An _impl_ is an implementation of an interface for a specific type. It is the
 place where the function bodies are defined, values for associated types, etc.
-are given. A given generics programming model may support default impls, named
-impls, or both. Impls are mostly associated with nominal interfaces; structural
-interfaces define conformance implicitly instead of by requiring an impl to be
-defined.
+are given. Impls are needed for [nominal interfaces](#nominal-interfaces);
+[structural interfaces](#structural-interfaces) define conformance implicitly
+instead of by requiring an impl to be defined.
 
 ## Compatible types
 
@@ -514,18 +531,19 @@ that it always supports, but satisfies additional interfaces under some
 conditions on the type argument. For example: `Array(T)` might implement
 `Comparable` if `T` itself implements `Comparable`, using lexicographical order.
 
-## Interface type parameters versus associated types
+## Interface type parameters and associated types
 
-Let's say you have 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 a type parameter; if it is an output, we say it is an associated type.
+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).
 
-Type parameter example:
+Interface type parameter example:
 
 ```
-interface Stack(ElementType:! Type)
+interface StackTP(ElementType:! Type)
   fn Push[addr me: Self*](value: ElementType);
   fn Pop[addr me: Self*]() -> ElementType;
 }
@@ -534,8 +552,8 @@ interface Stack(ElementType:! Type)
 Associated type example:
 
 ```
-interface Stack {
-  let ElementType: Type;
+interface StackAT {
+  let ElementType:! Type;
   fn Push[addr me: Self*](value: ElementType);
   fn Pop[addr me: Self*]() -> ElementType;
 }
@@ -551,33 +569,80 @@ 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;
+  let IteratorType:! Iterator;
   ...
   fn Insert[addr me: Self*](position: IteratorType, value: ElementType);
 }
 class ListIterator(ElementType:! Type) {
   ...
-  impl Iterator;
+  impl as Iterator;
 }
 class List(ElementType:! Type) {
   // Iterator type is determined by the container type.
-  let IteratorType: Iterator = ListIterator(ElementType);
+  let IteratorType:! Iterator = ListIterator(ElementType);
   fn Insert[addr me: Self*](position: IteratorType, value: ElementType) {
     ...
   }
-  impl Container;
+  impl as Container;
 }
 ```
 
-Since type parameters are directly under the user's control, it is easier to
-express things like "this type parameter is the same for all these interfaces",
-and other type constraints.
+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
+specified, a type can only have a single implementation of the given interface.
+This unique implementation choice determines the values of associated types.
 
-If you have an interface with type parameters, there is a question of whether a
-type can have multiple impls for different combinations of type parameters, or
-if you can only have a single impl (in which case you can directly infer the
-type parameters given just a type implementing the interface). You can always
-infer associated types.
+For example, we might have an interface that says how to perform addition with
+another type:
+
+```
+interface Addable(T:! Type) {
+  let ResultType:! Type;
+  fn Add[me: Self](rhs: T) -> ResultType;
+}
+```
+
+An `i32` value might support addition with `i32`, `u16`, and `f64` values.
+
+```
+impl i32 as Addable(i32) {
+  let ResultType:! Type = i32;
+  // ...
+}
+impl i32 as Addable(u16) {
+  let ResultType:! Type = i32;
+  // ...
+}
+impl i32 as Addable(f64) {
+  let ResultType:! Type = f64;
+  // ...
+}
+```
+
+To write a generic function requiring a parameter to be `Addable`, 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 {
+  return x.Add(y);
+}
+
+// ❌ This is forbidden, can't uniquely determine `T`.
+fn CompileError[T:! Type, U:! Addable(T)](x: U) -> T;
+```
+
+Once the interface parameter can be determined, that determines the values for
+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)`
+// for `Apple`.
+DoAdd(apple, orange);
+```
 
 ## Type constraints
 
@@ -595,12 +660,12 @@ express, for example:
     element type.
 -   An interface may define an associated type that needs to be constrained to
     implement some interfaces.
--   This type parameter must be [compatible](#compatible-types) with another
-    type. You might use this to define alternate implementations of a single
-    interfaces, such as sorting order, for a single type.
+-   This type must be [compatible](#compatible-types) with another type. You
+    might use this to define alternate implementations of a single interfaces,
+    such as sorting order, for a single type.
 
-Note that type constraints can be a restriction on one type parameter, or can
-define a relationship between multiple type parameters.
+Note that type constraints can be a restriction on one type parameter or
+associated type, or can define a relationship between multiple types.
 
 ## Type-of-type
 

+ 1 - 0
proposals/README.md

@@ -68,5 +68,6 @@ request:
 -   [0676 - `:!` generic syntax](p0676.md)
 -   [0680 - And, or, not](p0680.md)
 -   [0722 - Nominal classes and methods](p0722.md)
+-   [0731 - Generics details 2: adapters, associated types, parameterized interfaces](p0731.md)
 
 <!-- endproposals -->

+ 384 - 0
proposals/p0731.md

@@ -0,0 +1,384 @@
+# Generics details 2: adapters, associated types, parameterized interfaces
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/731)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals)
+-   [Alternatives considered](#alternatives-considered)
+    -   [`adaptor` instead of `adapter`](#adaptor-instead-of-adapter)
+    -   [Syntax for associated constants](#syntax-for-associated-constants)
+        -   [Omitting types](#omitting-types)
+        -   [Inferring associated types from method signatures](#inferring-associated-types-from-method-signatures)
+    -   [Value patterns](#value-patterns)
+    -   [Deduced interface parameters](#deduced-interface-parameters)
+        -   [Rationale for the rejection](#rationale-for-the-rejection)
+            -   [Impl lookup rules with deducible interface parameters](#impl-lookup-rules-with-deducible-interface-parameters)
+    -   [Only associated types, no interface parameters](#only-associated-types-no-interface-parameters)
+    -   [Others](#others)
+
+<!-- tocstop -->
+
+## Problem
+
+We want to Carbon to have a high quality generics feature that achieves the
+goals set out in [#24](https://github.com/carbon-language/carbon-lang/pull/24).
+This is too big to land in a single proposal. This proposal continues
+[#553](https://github.com/carbon-language/carbon-lang/pull/553) defining the
+details of:
+
+-   adapters
+-   associated types and other constants
+-   parameterized interfaces
+
+## Background
+
+This is a follow on to these previous generics proposals:
+
+-   [#24: Generics goals](https://github.com/carbon-language/carbon-lang/pull/24)
+-   [#447: Generics terminology](https://github.com/carbon-language/carbon-lang/pull/447)
+-   [#524: Generics overview](https://github.com/carbon-language/carbon-lang/pull/524)
+-   [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
+
+The content for this proposal was extracted from a larger
+[Generics combined draft proposal](https://github.com/carbon-language/carbon-lang/pull/36).
+
+## Proposal
+
+This is a proposal to add multiple sections to
+[this design document on generics details](/docs/design/generics/details.md).
+
+## Rationale based on Carbon's goals
+
+Much of this rationale was captured in the
+[Generics goals proposal](https://github.com/carbon-language/carbon-lang/pull/24).
+
+## Alternatives considered
+
+### `adaptor` instead of `adapter`
+
+We considered replacing the `adapter` keyword with the alternate spelling of
+"adaptor". Both spellings can be used for the intended meaning, but the "-er"
+spelling is more common in English text and in code. The final deciding factor
+was that the
+[GoF Design Patterns book](https://en.wikipedia.org/wiki/Design_Patterns) spells
+the ["adapter pattern"](https://en.wikipedia.org/wiki/Adapter_pattern) with the
+["-er" spelling](https://springframework.guru/gang-of-four-design-patterns/adapter-pattern/).
+
+### Syntax for associated constants
+
+Issue
+[#739: Associated type syntax](https://github.com/carbon-language/carbon-lang/issues/739)
+decided that the syntax for assigning a value to an associated constant, such as
+an associated type.
+
+The decision was to use `let` with `:!` to express that these are compile-time
+values, matching the use in classes described in proposal
+[#772](p0722.md#let-constants).
+
+```
+interface Stack {
+  let ElementType:! Type;
+  fn Push[addr me: Self*](value: ElementType);
+  ...
+}
+
+class DynamicArray(T:! Type) {
+  ...
+  impl as Stack {
+    let ElementType:! Type = T;
+    fn Push[addr me: Self*](value: ElementType);
+    ...
+  }
+}
+```
+
+One advantage was this opened the door for a type to satisfy the associated
+types of two interfaces with the same name with a single `let` declaration using
+constraints satisfying the requirements of both interfaces.
+
+This type can be replaced with `auto`, to have it determined automatically.
+
+```
+class DynamicArray(T:! Type) {
+  ...
+  impl as Stack {
+    let ElementType:! auto = T;
+    fn Push[addr me: Self*](value: ElementType);
+    ...
+  }
+}
+```
+
+This would avoid needing to change the `impl` when the constraints in the
+interface changed as long as the value to the right of the `=` satisfied the new
+constraints. Otherwise if the constraints are being weakened, first functions
+relying on the capabilities being removed would have to change, then they would
+be changed in the interface, and finally the implementations for types. If the
+constraints are being strengthened, the implementations for types would have to
+change first followed by the interface.
+
+#### Omitting types
+
+We also considered omitting the type in the `impl`, always using the type
+declared in the interface.
+
+```
+class DynamicArray(T:! Type) {
+  ...
+  impl as Stack {
+    let ElementType = T;
+    fn Push[addr me: Self*](value: ElementType);
+    ...
+  }
+}
+```
+
+This would provide the advantage of reducing the number of changes when changing
+the constraint specified in the interface. If the constraints were being
+weakened, then functions that used the capability that was being removed would
+break or need to be modified. If the constraints were being strengthened, then
+only type implementations that didn't satisfy the new constraints would break or
+need to be modified.
+
+The biggest difference from the selected option is when adding a constraint. In
+that case the selected option would have more churn, because all implementations
+would be updated even if they already satisfied the new constraint. This comes
+with the advantage of making it easier _incrementally enforce_ greater
+constraints.
+
+On the whole, it seems like both could be made to work. You could explicitly
+specify constraints with this option by using an alias to a normal
+`let ..:! TypeOfType` declaration that has extra constraints. Conversely, you
+can specify `auto` as the constraints in the selected option.
+
+But on balance, it seemed better to try putting the explicit constraints into
+the implementations so that we have more tools to incrementally roll out changes
+to interface constraints even though those rollouts will as a consequence be
+more noisy in some cases. If experience shows that this is a really bad
+tradeoff, we should revisit it.
+
+#### Inferring associated types from method signatures
+
+The last option considered is used by Swift.
+[Swift allows the value of an associated type to be omitted when it can be determined from the method signatures in the implementation](https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID190).
+For the above example, this would mean figuring out `ElementType == T` from
+context:
+
+```
+class DynamicArray(T:! Type) {
+  ...
+  impl as Stack {
+    // Not needed: let ElementType:! Type = T;
+    fn Push[addr me: Self*](value: T);
+    ...
+  }
+}
+```
+
+One benefit is that it allows an interface to evolve by adding an associated
+type, without having to then modify all implementations of that interface.
+
+One concern is this might be a little more complicated in the presence of method
+overloads with [default implementations](interface-defaults), since it might not
+be clear how they should match up, as in this example:
+
+```
+interface Has2OverloadsWithDefaults {
+  let T:! StackAssociatedType;
+  fn F[me: Self](x: DynamicArray(T), y: T) { ... }
+  fn F[me: Self](x: T, y: T.ElementType) { ... }
+}
+
+class S {
+  impl as Has2OverloadsWithDefaults {
+     // Unclear if T == DynamicArray(Int) or
+     // T == DynamicArray(DynamicArray(Int)).
+     fn F[me: Self](
+         x: DynamicArray(DynamicArray(Int)),
+         y: DynamicArray(Int)) { ... }
+  }
+}
+```
+
+Not to say this can't be resolved, but it does add complexity.
+[Swift considered](https://github.com/apple/swift/blob/main/docs/GenericsManifesto.md#associated-type-inference)
+removing this feature because it was the one thing in Swift that required global
+type inference, which they otherwise avoided. They
+[ultimately decided to keep the feature](https://github.com/apple/swift-evolution/blob/main/proposals/0108-remove-assoctype-inference.md).
+
+This option was only very briefly discussed and not preferred because:
+
+-   It came with complexity of inference.
+-   It seemed unnecessary.
+
+### Value patterns
+
+We considered an alternative to the `type_of` approach from
+[the parameterized interfaces section](/docs/design/generics/details.md#parameterized-interfaces)
+for binding `T` to a type mentioned later in the parameter list. We could
+instead allow functions to have value patterns without a `:`, as in:
+
+```
+fn PeekAtTopOfStackParameterized
+    [T:! Type, StackType:! StackParameterized(T)]
+    (s: StackType*, T) -> T { ... }
+```
+
+However, we don't want to allow value patterns more generally so we can reject
+declarations like `fn F(Int)` when users almost certainly meant `fn F(i: Int)`.
+
+### Deduced interface parameters
+
+The Carbon team considered and then rejected the idea that we would have two
+kinds of interface parameters. "Multi" parameters would work as described in the
+[detailed design document](/docs/design/generics/details.md#parameterized-interfaces).
+"Deducible" type parameters would only allow one implementation of an interface,
+not one per interface & type parameter combination. These deducible type
+parameters could be inferred like
+[associated types](/docs/design/generics/details.md#associated-types) are. For
+example, we could make a `Stack` interface that took a deducible `ElementType`
+parameter. You would only be able to implement that interface once for a type,
+which would allow you to infer the `ElementType` parameter like so:
+
+```
+fn PeekAtTopOfStack[ElementType:! Type, StackType:! Stack(ElementType)]
+    (s: StackType*) -> ElementType { ... }
+```
+
+This can result in more concise code for interfaces where you generally need to
+talk about some parameter anytime you use that interface. For example,
+`NTuple(N, type)` is much shorter without having to specify names with the
+arguments.
+
+#### Rationale for the rejection
+
+-   Having only one type of parameter simplifies the language.
+-   Multi parameters express something we need, while deducible parameters can
+    always be changed to associated types.
+-   One implementation per interface & type parameter combination is more
+    consistent with other parameterized constructs in Carbon. For example,
+    parameterized types `Foo(A)` and `Foo(B)` are distinct, unconnected types.
+-   It would be hard to give clear guidance on when to use associated types
+    versus deducible type parameters, since which is best for a particular use
+    is more of a subtle judgement call.
+-   Deducible parameters in structural interfaces require additional rules to
+    ensure they can be deduced unambiguously.
+
+In addition, deducible interface parameters would complicate the lookup rules
+for impls.
+
+##### Impl lookup rules with deducible interface parameters
+
+Interface implementation is Carbon's only language construct that allows open
+extension, and this sort of open extension is needed to address the "expression
+problem" in programming language design. However, we need to limit which
+libraries can implement an interface for a type so we can be guaranteed to see
+the implementation when we try and use it.
+
+So the question becomes: can we allow an implementation of a parameterized
+interface `I(T)` for a type `A` to be in the same library as `T`, or can it only
+be provided with `I` or `A`? The answer is "yes" if `T` is "multi" and "no" if
+`T` is deducible.
+
+The problem with defining the implementation with a deducible `T` is that it
+would allow users to violate
+[coherence](/docs/design/generics/goals.md#coherence). Consider this collection
+of libraries, where there are implementations for an interface `I(T)` for a type
+`A`, and those implementations are in the libraries defining the type parameter:
+
+```
+package X library "I and A" api;
+
+interface I(Type:$ T) { ... }
+
+struct A { ... }
+```
+
+```
+package Y library "T1" api;
+
+import X library "I and A";
+
+struct T1 { ... }
+
+// Type `X.A` has an implementation for `X.I(T)` for `T == Y.T1`.
+impl X.I(T1) for X.A { ... }
+```
+
+```
+package Z library "T2" api;
+
+import X library "I and A";
+
+struct T2 { ... }
+
+// Type `X.A` has an implementation for `X.I(T)` for `T == Z.T2`.
+impl X.I(T2) for X.A { ... }
+```
+
+```
+package Main api;
+
+import X library "I and A";
+// Consider what happens if we include different combinations
+// of the following two statements:
+// import Y library "T1";
+// import Z library "T2";
+
+// Function `F` is called with value `a` with type `U`,
+// where `U` implements interface `X.I(T)` for some type `T`.
+fn F[Type:$ T, X.I(T):$ U](U:$ a) { ... }
+
+fn Main() {
+  var X.A: a = X.A.Init();
+  F(a);
+}
+```
+
+(In the example, each library is in a different package, but the packages are
+not the important part here.)
+
+The `F(a)` call triggers a lookup for implementations of the interface `X.I(T)`
+for some `T`. There exists such implementations in both libraries `Y.T1` and
+`Z.T2` for different values of `T`. This has a number of sad consequences:
+
+-   "Import what you use" is hard to measure: libraries `Y.T1` and `Z.T2` are
+    important and used even though `Y` and `Z` are not mentioned outside the
+    `import` statement.
+-   The call `F(a)` has different interpretations depending on what libraries
+    are imported:
+    -   If neither is imported, it is an error.
+    -   If both are imported, it is ambiguous.
+    -   If only one is imported, you get totally different code executed
+        depending on which it is.
+-   We have no way of enforcing a "one implementation per interface" rule that
+    would prevent the call to `F` from being ambiguous.
+
+Basically, there is nothing guaranteeing that we import libraries defining the
+types that are used as interface parameters if we allow the interface parameters
+to be deduced.
+
+### Only associated types, no interface parameters
+
+This is what Swift does, but doesn't allow us to use interfaces to express
+operator overloads. For example, a vector should be able to be added to either a
+vector or a point. So we follow Rust, which has trait parameters in addition to
+associated types and uses them to define the behavior of operators.
+
+### Others
+
+Other alternatives considered will be in a future proposal. Some of them can be
+seen in a rough form in
+[#36](https://github.com/carbon-language/carbon-lang/pull/36).