소스 검색

Generics: cleanups and updates (#881)

Add references, update syntax, merge future work

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
josh11b 4 년 전
부모
커밋
c7c653adba
4개의 변경된 파일98개의 추가작업 그리고 74개의 파일을 삭제
  1. 81 74
      docs/design/generics/details.md
  2. 5 0
      docs/design/generics/goals.md
  3. 6 0
      docs/design/generics/overview.md
  4. 6 0
      docs/design/generics/terminology.md

+ 81 - 74
docs/design/generics/details.md

@@ -1,4 +1,4 @@
-# Carbon deep dive: combined interfaces
+# Carbon generics details
 
 <!--
 Part of the Carbon Language project, under the Apache License v2.0 with LLVM
@@ -65,8 +65,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Field requirements](#field-requirements)
     -   [Generic type specialization](#generic-type-specialization)
     -   [Bridge for C++ customization points](#bridge-for-c-customization-points)
-    -   [Reverse generics for return types](#reverse-generics-for-return-types)
     -   [Variadic arguments](#variadic-arguments)
+-   [References](#references)
 
 <!-- tocstop -->
 
@@ -336,7 +336,7 @@ class GameBoard {
     // ❌ Error: `GameBoard` has two methods named
     // `Draw` with the same signature.
     fn Draw[me: Self]() { ... }
-    fn Winner[me: Self](player: Int) { ... }
+    fn Winner[me: Self](player: i32) { ... }
   }
 }
 ```
@@ -751,7 +751,7 @@ fn Identity[T:! Type](x: T) -> T {
   return x;
 }
 
-var i: Int = Identity(3);
+var i: i32 = Identity(3);
 var s: String = Identity("string");
 ```
 
@@ -865,7 +865,7 @@ interface Printable {
   fn Print[me: Self]();
 }
 interface Renderable {
-  fn Center[me: Self]() -> (Int, Int);
+  fn Center[me: Self]() -> (i32, i32);
   fn Draw[me: Self]();
 }
 
@@ -890,7 +890,7 @@ class Sprite {
     fn Print[me: Self]() { ... }
   }
   impl as Renderable {
-    fn Center[me: Self]() -> (Int, Int) { ... }
+    fn Center[me: Self]() -> (i32, i32) { ... }
     fn Draw[me: Self]() { ... }
   }
 }
@@ -904,12 +904,12 @@ error to use.
 
 ```
 interface Renderable {
-  fn Center[me: Self]() -> (Int, Int);
+  fn Center[me: Self]() -> (i32, i32);
   fn Draw[me: Self]();
 }
 interface EndOfGame {
   fn Draw[me: Self]();
-  fn Winner[me: Self](player: Int);
+  fn Winner[me: Self](player: i32);
 }
 // `Renderable & EndOfGame` is syntactic sugar for this type-of-type:
 structural interface {
@@ -1017,10 +1017,10 @@ will use the same semantics and syntax as we do for
 [structural interfaces](#structural-interfaces):
 
 ```
-interface Equatable { fn Equals[me: Self](that: Self) -> Bool; }
+interface Equatable { fn Equals[me: Self](that: Self) -> bool; }
 
 interface Iterable {
-  fn Advance[addr me: Self*]() -> Bool;
+  fn Advance[addr me: Self*]() -> bool;
   impl as Equatable;
 }
 
@@ -1034,7 +1034,7 @@ def DoAdvanceAndEquals[T:! Iterable](x: T) {
 
 class Iota {
   impl as Iterable { fn Advance[me: Self]() { ... } }
-  impl as Equatable { fn Equals[me: Self](that: Self) -> Bool { ... } }
+  impl as Equatable { fn Equals[me: Self](that: Self) -> bool { ... } }
 }
 var x: Iota;
 DoAdvanceAndEquals(x);
@@ -1046,7 +1046,7 @@ by itself add any names to the interface, but again those can be added with
 
 ```
 interface Hashable {
-  fn Hash[me: Self]() -> UInt64;
+  fn Hash[me: Self]() -> u64;
   impl as Equatable;
   alias Equals = Equatable.Equals;
 }
@@ -1070,8 +1070,8 @@ as well. In the case of `Hashable` above, this includes all the members of
 ```
 class Song {
   impl as Hashable {
-    fn Hash[me: Self]() -> UInt64 { ... }
-    fn Equals[me: Self](that: Self) -> Bool { ... }
+    fn Hash[me: Self]() -> u64 { ... }
+    fn Equals[me: Self](that: Self) -> bool { ... }
   }
 }
 var y: Song;
@@ -1090,17 +1090,17 @@ benefits:
 We expect this concept to be common enough to warrant dedicated syntax:
 
 ```
-interface Equatable { fn Equals[me: Self](that: Self) -> Bool; }
+interface Equatable { fn Equals[me: Self](that: Self) -> bool; }
 
 interface Hashable {
   extends Equatable;
-  fn Hash[me: Self]() -> UInt64;
+  fn Hash[me: Self]() -> u64;
 }
 // is equivalent to the definition of Hashable from before:
 // interface Hashable {
 //   impl as Equatable;
 //   alias Equals = Equatable.Equals;
-//   fn Hash[me: Self]() -> UInt64;
+//   fn Hash[me: Self]() -> u64;
 // }
 ```
 
@@ -1355,7 +1355,7 @@ the capabilities of the iterator being passed in:
 ```
 interface ForwardIntIterator {
   fn Advance[addr me: Self*]();
-  fn Get[me: Self]() -> Int;
+  fn Get[me: Self]() -> i32;
 }
 interface BidirectionalIntIterator {
   extends ForwardIntIterator;
@@ -1363,18 +1363,18 @@ interface BidirectionalIntIterator {
 }
 interface RandomAccessIntIterator {
   extends BidirectionalIntIterator;
-  fn Skip[addr me: Self*](offset: Int);
-  fn Difference[me: Self](that: Self) -> Int;
+  fn Skip[addr me: Self*](offset: i32);
+  fn Difference[me: Self](that: Self) -> i32;
 }
 
 fn SearchInSortedList[IterT:! ForwardIntIterator]
-    (begin: IterT, end: IterT, needle: Int) -> Bool {
+    (begin: IterT, end: IterT, needle: i32) -> bool {
   ... // does linear search
 }
 // Will prefer the following overload when it matches
 // since it is more specific.
 fn SearchInSortedList[IterT:! RandomAccessIntIterator]
-    (begin: IterT, end: IterT, needle: Int) -> Bool {
+    (begin: IterT, end: IterT, needle: i32) -> bool {
   ... // does binary search
 }
 ```
@@ -1401,19 +1401,19 @@ interface Hashable { ... }
 class HashMap(KeyT:! Hashable, ValueT:! Type) { ... }
 ```
 
-If we write something like `HashMap(String, Int)` the type we actually get is:
+If we write something like `HashMap(String, i32)` the type we actually get is:
 
 ```
-HashMap(String as Hashable, Int as Type)
+HashMap(String as Hashable, i32 as Type)
 ```
 
 This is the same type we will get if we pass in some other facet types in, so
 all of these types are equal:
 
--   `HashMap(String, Int)`
--   `HashMap(String as Hashable, Int as Type)`
--   `HashMap((String as Printable) as Hashable, Int)`
--   `HashMap((String as Printable & Hashable) as Hashable, Int)`
+-   `HashMap(String, i32)`
+-   `HashMap(String as Hashable, i32 as Type)`
+-   `HashMap((String as Printable) as Hashable, i32)`
+-   `HashMap((String as Printable & Hashable) as Hashable, i32)`
 
 This means we don't generally need to worry about getting the wrong facet type
 as the argument for a generic type. This means we don't get type mismatches when
@@ -1425,7 +1425,7 @@ fn PrintValue
     [KeyT:! Printable & Hashable, ValueT:! Printable]
     (map: HashMap(KeyT, ValueT), key: KeyT) { ... }
 
-var m: HashMap(String, Int);
+var m: HashMap(String, i32);
 PrintValue(m, "key");
 ```
 
@@ -1444,14 +1444,14 @@ interface Printable {
   fn Print[me: Self]();
 }
 interface Comparable {
-  fn Less[me: Self](that: Self) -> Bool;
+  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 { ... }
+    fn Less[me: Self](that: Self) -> bool { ... }
   }
 }
 adapter FormattedSong for Song {
@@ -1488,7 +1488,7 @@ 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 {
+    fn Less[me: Self](that: Self) -> bool {
       return (this as Song).Title() < (that as Song).Title();
     }
   }
@@ -1500,7 +1500,7 @@ or using qualified names:
 ```
 adapter SongByTitle for Song {
   impl as Comparable {
-    fn Less[me: Self](that: Self) -> Bool {
+    fn Less[me: Self](that: Self) -> bool {
       return this.(Song.Title)() < that(Song.Title)();
     }
   }
@@ -1574,10 +1574,10 @@ one difference between them is that `Song as Hashable` may be implicitly
 converted to `Song`, which implements interface `Printable`, and
 `PlayableSong as Hashable` may be implicilty converted to `PlayableSong`, which
 implements interface `Media`. This means that it is safe to convert between
-`HashMap(Song, Int) == HashMap(Song as Hashable, Int)` and
-`HashMap(PlayableSong, Int) == HashMap(PlayableSong as Hashable, Int)` (though
+`HashMap(Song, i32) == HashMap(Song as Hashable, i32)` and
+`HashMap(PlayableSong, i32) == HashMap(PlayableSong as Hashable, i32)` (though
 maybe only with an explicit cast) but
-`HashMap(SongHashedByTitle, Int) == HashMap(SongHashByTitle as Hashable, Int)`
+`HashMap(SongHashedByTitle, i32) == HashMap(SongHashByTitle as Hashable, i32)`
 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.
@@ -1680,18 +1680,18 @@ syntax.
 
 ```
 interface Comparable {
-  fn Less[me: Self](that: Self) -> Bool;
+  fn Less[me: Self](that: Self) -> bool;
 }
 adapter ComparableFromDifferenceFn
-    (T:! Type, Difference:! fnty(T, T)->Int) for T {
+    (T:! Type, Difference:! fnty(T, T)->i32) for T {
   impl as Comparable {
-    fn Less[me: Self](that: Self) -> Bool {
+    fn Less[me: Self](that: Self) -> bool {
       return Difference(this, that) < 0;
     }
   }
 }
 class IntWrapper {
-  var x: Int;
+  var x: i32;
   fn Difference(this: Self, that: Self) {
     return that.x - this.x;
   }
@@ -1712,12 +1712,12 @@ associated constant.
 
 ```
 interface NSpacePoint {
-  let N:! Int;
+  let N:! i32;
   // The following require: 0 <= i < N.
-  fn Get[addr me: Self*](i: Int) -> Float64;
-  fn Set[addr me: Self*](i: Int, value: Float64);
+  fn Get[addr me: Self*](i: i32) -> f64;
+  fn Set[addr me: Self*](i: i32, value: f64);
   // Associated constants may be used in signatures:
-  fn SetAll[addr me: Self*](value: Array(Float64, N));
+  fn SetAll[addr me: Self*](value: Array(f64, N));
 }
 ```
 
@@ -1727,19 +1727,19 @@ 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)) { ... }
+    let N:! i32 = 2;
+    fn Get[addr me: Self*](i: i32) -> f64 { ... }
+    fn Set[addr me: Self*](i: i32, value: f64) { ... }
+    fn SetAll[addr me: Self*](value: Array(f64, 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)) { ... }
+    let N:! i32 = 3;
+    fn Get[addr me: Self*](i: i32) -> f64 { ... }
+    fn Set[addr me: Self*](i: i32, value: f64) { ... }
+    fn SetAll[addr me: Self*](value: Array(f64, 3)) { ... }
   }
 }
 ```
@@ -1751,7 +1751,7 @@ Assert(Point2D.N == 2);
 Assert(Point3D.N == 3);
 
 fn PrintPoint[PointT:! NSpacePoint](p: PointT) {
-  for (var i: Int = 0; i < PointT.N; ++i) {
+  for (var i: i32 = 0; i < PointT.N; ++i) {
     if (i > 0) { Print(", "); }
     Print(p.Get(i));
   }
@@ -1759,8 +1759,8 @@ fn PrintPoint[PointT:! NSpacePoint](p: PointT) {
 
 fn ExtractPoint[PointT:! NSpacePoint](
     p: PointT,
-    dest: Array(Float64, PointT.N)*) {
-  for (var i: Int = 0; i < PointT.N; ++i) {
+    dest: Array(f64, PointT.N)*) {
+  for (var i: i32 = 0; i < PointT.N; ++i) {
     (*dest)[i] = p.Get(i);
   }
 }
@@ -1784,7 +1784,7 @@ interface DeserializeFromString {
 }
 
 class MySerializableType {
-  var i: Int;
+  var i: i32;
 
   impl as DeserializeFromString {
     fn Deserialize(serialized: String) -> Self {
@@ -1824,7 +1824,7 @@ interface StackAssociatedType {
   let ElementType:! Type;
   fn Push[addr me: Self*](value: ElementType);
   fn Pop[addr me: Self*]() -> ElementType;
-  fn IsEmpty[addr me: Self*]() -> Bool;
+  fn IsEmpty[addr me: Self*]() -> bool;
 }
 ```
 
@@ -1856,7 +1856,7 @@ class DynamicArray(T:! Type) {
       this->Remove(pos);
       return var;
     }
-    fn IsEmpty[addr me: Self*]() -> Bool {
+    fn IsEmpty[addr me: Self*]() -> bool {
       return this->Begin() == this->End();
     }
   }
@@ -1963,7 +1963,7 @@ 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;
+  fn IsEmpty[addr me: Self*]() -> bool;
 }
 ```
 
@@ -1981,7 +1981,7 @@ class Produce {
     fn Pop[addr me: Self*]() -> Fruit {
       return this->fruit.Pop();
     }
-    fn IsEmpty[addr me: Self*]() -> Bool {
+    fn IsEmpty[addr me: Self*]() -> bool {
       return this->fruit.IsEmpty();
     }
   }
@@ -1992,7 +1992,7 @@ class Produce {
     fn Pop[addr me: Self*]() -> Veggie {
       return this->veggie.Pop();
     }
-    fn IsEmpty[addr me: Self*]() -> Bool {
+    fn IsEmpty[addr me: Self*]() -> bool {
       return this->veggie.IsEmpty();
     }
   }
@@ -2041,7 +2041,7 @@ be comparable with multiple other types, and in fact interfaces for
 
 ```
 interface EquatableWith(T:! Type) {
-  fn Equals[me: Self](that: T) -> Bool;
+  fn Equals[me: Self](that: T) -> bool;
   ...
 }
 class Complex {
@@ -2220,9 +2220,17 @@ values they could have different real types.
 
 ### Abstract return types
 
-This lets you return am anonymous type implementing an interface from a
-function.
-[Rust has this feature](https://rust-lang.github.io/rfcs/1522-conservative-impl-trait.html).
+This lets you return an anonymous type implementing an interface from a
+function. In Rust this is the
+[`impl Trait` return type](https://rust-lang.github.io/rfcs/1522-conservative-impl-trait.html).
+
+In Swift, there are discussions about implementing this feature under the name
+"reverse generics" or "opaque result types":
+[1](https://forums.swift.org/t/improving-the-ui-of-generics/22814#heading--reverse-generics),
+[2](https://forums.swift.org/t/reverse-generics-and-opaque-result-types/21608),
+[3](https://forums.swift.org/t/se-0244-opaque-result-types/21252),
+[4](https://forums.swift.org/t/se-0244-opaque-result-types-reopened/22942),
+Swift is considering spelling this `<V: Collection> V` or `some Collection`.
 
 ### Interface defaults
 
@@ -2266,11 +2274,13 @@ a type to an implementation of an interface parameterized by that type.
 #### Generic associated types
 
 Generic associated types are about when this is a requirement of an interface.
+These are also called "associated type constructors."
 
 #### Higher-ranked types
 
 Higher-ranked types are used to represent this requirement in a function
-signature.
+signature. They can be
+[emulated using generic associated types](https://smallcultfollowing.com/babysteps//blog/2016/11/03/associated-type-constructors-part-2-family-traits/).
 
 ### Field requirements
 
@@ -2288,15 +2298,12 @@ description of what this might involve.
 
 See details in [the goals document](goals.md#bridge-for-c-customization-points).
 
-### Reverse generics for return types
-
-In Rust this is
-[return type of "`impl Trait`"](https://rust-lang.github.io/rfcs/1522-conservative-impl-trait.html).
-In Swift,
-[this feature is in discussion](https://forums.swift.org/t/improving-the-ui-of-generics/22814#heading--reverse-generics).
-Swift is considering spelling this `<V: Collection> V` or `some Collection`.
-
 ### Variadic arguments
 
 Some facility for allowing a function to generically take a variable number of
 arguments.
+
+## References
+
+-   [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
+-   [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)

+ 5 - 0
docs/design/generics/goals.md

@@ -38,6 +38,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Template use cases that are out of scope](#template-use-cases-that-are-out-of-scope)
     -   [Generics will be checked when defined](#generics-will-be-checked-when-defined)
     -   [Specialization strategy](#specialization-strategy)
+-   [References](#references)
 
 <!-- tocstop -->
 
@@ -667,3 +668,7 @@ cases.
 Lastly, runtime specialization is out of scope as an implementation strategy.
 That is, some language runtimes JIT a specialization when it is first needed,
 but it is not a goal for Carbon to support such an implementation strategy.
+
+## References
+
+-   [#24: Generics goals](https://github.com/carbon-language/carbon-lang/pull/24)

+ 6 - 0
docs/design/generics/overview.md

@@ -34,6 +34,7 @@ pointers to other design documents that dive deeper into individual topics.
         -   [Associated types](#associated-types)
         -   [Parameterized interfaces](#parameterized-interfaces)
 -   [Future work](#future-work)
+-   [References](#references)
 
 <!-- tocstop -->
 
@@ -577,3 +578,8 @@ fn CompileError[T:! Type, U:! Equatable(T)](x: U) -> T;
     interfaces and other ways to reuse code across implementations.
 -   There should be a way to define generic associated and higher-ranked/kinded
     types.
+
+## References
+
+-   [#524: Generics overview](https://github.com/carbon-language/carbon-lang/pull/524)
+-   [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)

+ 6 - 0
docs/design/generics/terminology.md

@@ -43,6 +43,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 -   [Interface type parameters and associated types](#interface-type-parameters-and-associated-types)
 -   [Type constraints](#type-constraints)
 -   [Type-of-type](#type-of-type)
+-   [References](#references)
 
 <!-- tocstop -->
 
@@ -682,3 +683,8 @@ available in the body of the function. Calling a function with a type `T` passed
 to a generic type parameter `U` with type-of-type `I`, ends up setting `U` to
 the facet type `T as I`. This has the API determined by `I`, with the
 implementation of that API coming from `T`.
+
+## References
+
+-   [#447: Generics terminology](https://github.com/carbon-language/carbon-lang/pull/447)
+-   [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)