Procházet zdrojové kódy

Switch generics to using compound/simple member access terminology (#1138)

This is following #1119 .

* Updates terminology.md, overview.md, details.md
josh11b před 4 roky
rodič
revize
f0d6e3122a

+ 39 - 32
docs/design/generics/details.md

@@ -15,7 +15,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 -   [Implementing interfaces](#implementing-interfaces)
     -   [Implementing multiple interfaces](#implementing-multiple-interfaces)
     -   [External impl](#external-impl)
-    -   [Qualified member names](#qualified-member-names)
+    -   [Qualified member names and compound member access](#qualified-member-names-and-compound-member-access)
     -   [Access](#access)
 -   [Generics](#generics)
     -   [Return type](#return-type)
@@ -188,9 +188,9 @@ This includes members of `ConvertibleToString` that are not explicitly named in
 the `impl` definition but have defaults. Whether the implementation is defined
 as [internal](terminology.md#internal-impl) or
 [external](terminology.md#external-impl), you may access the `ToString` function
-for a `Song` value `s` by writing a
-[qualified](terminology.md#qualified-and-unqualified-member-names) function
-call, like `s.(ConvertibleToString.ToString)()`.
+for a `Song` value `s` by a writing function call
+[using the compound member access syntax with the qualified name](terminology.md#compound-member-access-using-qualified-names),
+like `s.(ConvertibleToString.ToString)()`.
 
 If `Song` doesn't implement an interface or we would like to use a different
 implementation of that interface, we can define another type that also has the
@@ -405,8 +405,9 @@ Carbon requires `impl`s defined in a different library to be `external` so that
 the API of `Point3` doesn't change based on what is imported. It would be
 particularly bad if two different libraries implemented interfaces with
 conflicting names that both affected the API of a single type. As a consequence
-of this restriction, you can find all the names of direct (unqualified) members
-of a type in the definition of that type. The only thing that may be in another
+of this restriction, you can find all the names of direct members (those
+available by [simple member access](terminology.md#simple-member-access)) of a
+type in the definition of that type. The only thing that may be in another
 library is an `impl` of an interface.
 
 You might also use `external impl` to implement an interface for a type to avoid
@@ -476,8 +477,10 @@ same library as the class?
 different files based on explicit configuration in that file. For example, we
 could support a declaration that a given interface or a given method of an
 interface is "in scope" for a particular type in this file. With that
-declaration, the method could be called unqualified. This avoids most concerns
-arising from name collisions between interfaces. It has a few downsides though:
+declaration, the method could be called using
+[simple member access](terminology.md#simple-member-access). This avoids most
+concerns arising from name collisions between interfaces. It has a few downsides
+though:
 
 -   It increases variability between files, since the same type will have
     different APIs depending on these declarations. This makes it harder to
@@ -495,12 +498,14 @@ Swift and Rust, we don't allow a type's API to be modified outside its
 definition. So in Carbon a type's API is consistent no matter what is imported,
 unlike Swift and Rust.
 
-### Qualified member names
+### Qualified member names and compound member access
 
 Given a value of type `Point3` and an interface `Vector` implemented for that
 type, you can access the methods from that interface using the member's
-_qualified name_, whether or not the implementation is done externally with an
-`external impl` declaration:
+_qualified name_ using
+[the compound member access syntax](terminology.md#simple-member-access),
+whether or not the implementation is done externally with an `external impl`
+declaration:
 
 ```
 var p1: Point3 = {.x = 1.0, .y = 2.0};
@@ -581,7 +586,9 @@ present in the signature of the function to type check the body of
 
 Names are looked up in the body of `AddAndScaleGeneric` for values of type `T`
 in `Vector`. This means that `AddAndScaleGeneric` is interpreted as equivalent
-to adding a `Vector` qualification to all unqualified member accesses of `T`:
+to adding a `Vector`
+[qualification](#qualified-member-names-and-compound-member-access) to replace
+all simple member accesses of `T`:
 
 ```
 fn AddAndScaleGeneric[T:! Vector](a: T, b: T, s: Double) -> T {
@@ -785,7 +792,8 @@ signatures. Implementing `Vector` would not imply an implementation of
 An interface's name may be used in a few different contexts:
 
 -   to define [an `impl` for a type](#implementing-interfaces),
--   as a namespace name in [a qualified name](#qualified-member-names), and
+-   as a namespace name in
+    [a qualified name](#qualified-member-names-and-compound-member-access), and
 -   as a [type-of-type](terminology.md#type-of-type) for
     [a generic type parameter](#generics).
 
@@ -806,7 +814,8 @@ aliases for the corresponding qualified names inside `Vector` as a namespace.
 
 The requirements determine which types are values of a given type-of-type. The
 set of names in a type-of-type determines the API of a generic type value and
-define the result of qualified member name lookup.
+define the result of [member access](/docs/design/expressions/member_access.md)
+into the type-of-type.
 
 This general structure of type-of-types holds not just for interfaces, but
 others described in the rest of this document.
@@ -875,9 +884,8 @@ members of those interfaces.
 To declare a named constraint that includes other declarations for use with
 template parameters, use the `template` keyword before `constraint`. Method,
 associated type, and associated function requirements may only be declared
-inside a `template constraint`. Note that a generic constraint ignores the
-unqualified member names defined for a type, but a template constraint can
-depend on them.
+inside a `template constraint`. Note that a generic constraint ignores the names
+of members defined for a type, but a template constraint can depend on them.
 
 There is an analogy between declarations used in a `constraint` and in an
 `interface` definition. If an `interface` `I` has (non-`alias`) declarations
@@ -1036,8 +1044,8 @@ constraint {
 ```
 
 Conflicts can be resolved at the call site using
-[the qualified name syntax](#qualified-member-names), or by defining a named
-constraint explicitly and renaming the methods:
+[the compound member access syntax using qualified names](#qualified-member-names-and-compound-member-access),
+or by defining a named constraint explicitly and renaming the methods:
 
 ```
 constraint RenderableAndEndOfGame {
@@ -1561,7 +1569,7 @@ adapter SongByTitle for Song {
 }
 ```
 
-or using qualified names:
+or using qualified names with the compound member access syntax:
 
 ```
 adapter SongByTitle for Song {
@@ -1852,8 +1860,8 @@ external impl Window as DrawingContext { ... }
 An adapter can make that much more convenient by making a compatible type where
 the interface is [implemented internally](terminology.md#internal-impl). This
 avoids having to
-[qualify](terminology.md#qualified-and-unqualified-member-names) each call to
-methods in the interface.
+[qualify](terminology.md#compound-member-access-using-qualified-names) each call
+to methods in the interface.
 
 ```
 adapter DrawInWindow for Window {
@@ -2580,14 +2588,13 @@ fn Contains
 the `where` constraint means `CT.ElementType` must satisfy `Comparable` as well.
 However, inside the body of `Contains`, `CT.ElementType` will only act like the
 implementation of `Comparable` is [external](#external-impl). That is, items
-from the `needles` container won't have an unqualified `Compare` method member,
-but can still be implicitly converted to `Comparable` and can still call
-`Compare` using the qualified member syntax, `needle.(Comparable.Compare)(elt)`.
-The rule is that an `==` `where` constraint between two type variables does not
-modify the set of unqualified member names of either type. (If you write
+from the `needles` container won't directly have a `Compare` method member, but
+can still be implicitly converted to `Comparable` and can still call `Compare`
+using the compound member access syntax, `needle.(Comparable.Compare)(elt)`. The
+rule is that an `==` `where` constraint between two type variables does not
+modify the set of member names of either type. (If you write
 `where .ElementType = String` with a `=` and a concrete type, then
-`.ElementType` is actually set to `String` including the complete unqualified
-`String` API.)
+`.ElementType` is actually set to `String` including the complete `String` API.)
 
 Note that `==` constraints are symmetric, so the previous declaration of
 `Contains` is equivalent to an alternative declaration where `CT` is declared
@@ -2876,9 +2883,9 @@ This implied constraint is equivalent to the explicit constraint that each
 parameter and return type [is legal](#must-be-legal-type-argument-constraints).
 
 **Note:** These implied constraints affect the _requirements_ of a generic type
-parameter, but not its _unqualified member names_. This way you can always look
-at the declaration to see how name resolution works, without having to look up
-the definitions of everything it is used as an argument to.
+parameter, but not its _member names_. This way you can always look at the
+declaration to see how name resolution works, without having to look up the
+definitions of everything it is used as an argument to.
 
 **Limitation:** To limit readability concerns and ambiguity, this feature is
 limited to a single signature. Consider this interface declaration:

+ 22 - 19
docs/design/generics/overview.md

@@ -20,7 +20,7 @@ pointers to other design documents that dive deeper into individual topics.
         -   [Defining interfaces](#defining-interfaces)
         -   [Contrast with templates](#contrast-with-templates)
     -   [Implementing interfaces](#implementing-interfaces)
-        -   [Qualified and unqualified access](#qualified-and-unqualified-access)
+        -   [Accessing members of interfaces](#accessing-members-of-interfaces)
     -   [Type-of-types](#type-of-types)
     -   [Generic functions](#generic-functions)
         -   [Deduced parameters](#deduced-parameters)
@@ -90,8 +90,9 @@ Summary of how Carbon generics work:
     ["named constraints"](terminology.md#named-constraints). Named constraints
     can express requirements that multiple interfaces be implemented, and give
     you control over how name conflicts are handled.
--   Alternatively, you may resolve name conflicts by using a qualified syntax to
-    directly call a function from a specific interface.
+-   Alternatively, you may resolve name conflicts by using the compound member
+    access syntax to directly call a function from a specific interface using a
+    qualified name.
 
 ## What are generics?
 
@@ -216,16 +217,17 @@ external impl Song as Comparable {
 
 Implementations may be defined within the class definition itself or
 out-of-line. Implementations may optionally be start with the `external` keyword
-to say the members of the interface are not unqualified members of the class.
-Out-of-line implementations must be external. External implementations may be
-defined in the library defining either the class or the interface.
+to say the members of the interface are not members of the class. Out-of-line
+implementations must be external. External implementations may be defined in the
+library defining either the class or the interface.
 
-#### Qualified and unqualified access
+#### Accessing members of interfaces
 
 The methods of an interface implemented internally within the class definition
-may be called with the ordinary unqualified member syntax. Methods of all
-implemented interfaces may be called with the
-[qualified member syntax](terminology.md#qualified-and-unqualified-member-names),
+may be called with the
+[simple member access syntax](terminology.md#simple-member-access). Methods of
+all implemented interfaces may be called with the
+[compound member access syntax using qualified names](terminology.md#compound-member-access-using-qualified-names),
 whether they are defined internally or externally.
 
 ```
@@ -235,7 +237,8 @@ song.Print();
 // `Less` is defined in `Comparable`, which is implemented
 // externally for `Song`
 song.(Comparable.Less)(song);
-// Can also call `Print` using the qualified syntax:
+// Can also call `Print` using the compound access syntax,
+// using the qualified name `Printable.Print`:
 song.(Printable.Print)();
 ```
 
@@ -257,9 +260,8 @@ type is that it must implement the interface `Comparable`.
 
 A type-of-type also defines a set of names and a mapping to corresponding
 qualified names. Those names are used for
-[unqualfied member lookup](terminology.md#qualified-and-unqualified-member-names)
-in scopes where the value of the type is not known, such as when the type is a
-generic parameter.
+[simple member lookup](terminology.md#simple-member-access) in scopes where the
+value of the type is not known, such as when the type is a generic parameter.
 
 You may combine interfaces into new type-of-types using
 [the `&` operator](#combining-interfaces) or
@@ -325,8 +327,9 @@ differently because they are defined as generic, as long as you only refer to
 the names defined by [type-of-type](#type-of-types) for the type parameter.
 
 You may also refer to any of the methods of interfaces required by the
-type-of-type using the [qualified syntax](#qualified-and-unqualified-access), as
-shown in the following sections.
+type-of-type using the
+[compound member access syntax with the qualified member name](#accessing-members-of-interfaces),
+as shown in the following sections.
 
 A function can have a mix of generic, template, and regular parameters.
 Likewise, it's allowed to pass a template or generic value to a generic or
@@ -409,7 +412,7 @@ fn F[T:! Renderable & EndOfGame](game_state: T*) -> (i32, i32) {
 ```
 
 Names with conflicts can be accessed using the
-[qualified syntax](#qualified-and-unqualified-access).
+[compound member access syntax](#accessing-members-of-interfaces).
 
 ```
 fn BothDraws[T:! Renderable & EndOfGame](game_state: T*) {
@@ -442,8 +445,8 @@ fn CallItAll[T:! Combined](game_state: T*, int winner) {
     game_state->Draw_EndOfGame();
   }
   game_state->Draw_Renderable();
-  // Can still use qualified syntax for names
-  // not defined in the named constraint
+  // Can still use compound member access syntax for
+  // names not defined in the named constraint
   return game_state->(Renderable.Center)();
 }
 ```

+ 38 - 13
docs/design/generics/terminology.md

@@ -30,7 +30,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 -   [Impls: Implementations of interfaces](#impls-implementations-of-interfaces)
     -   [Internal impl](#internal-impl)
     -   [External impl](#external-impl)
--   [Qualified and unqualified member names](#qualified-and-unqualified-member-names)
+-   [Member access](#member-access)
+    -   [Simple member access](#simple-member-access)
+    -   [Compound member access using qualified names](#compound-member-access-using-qualified-names)
 -   [Compatible types](#compatible-types)
 -   [Subtyping and casting](#subtyping-and-casting)
 -   [Coherence](#coherence)
@@ -357,28 +359,51 @@ constraint as a way to implement all of the interfaces it requires.
 
 A type that implements an interface _internally_ has all the named members of
 the interface as named members of the type. This means that the members of the
-interface may be accessed as either
-[unqualified or qualified members](#qualified-and-unqualified-member-names).
+interface are available by way of both
+[simple member access and compound member access using qualified names](#member-access).
 
 ### External impl
 
 In contrast, a type that implements an interface _externally_ does not include
 the named members of the interface in the type. The members of the interface are
-still implemented by the type, though, and so may be accessed using the
-[qualified names](#qualified-and-unqualified-member-names) of those members.
+still implemented by the type, though, and so may be accessed using
+[compound member access using the qualified names](#compound-member-access-using-qualified-names)
+of those members.
 
-## Qualified and unqualified member names
+## Member access
 
-A qualified member includes both the name of the interface defining the member
-and the name of the member. So if `String` implements `Comparable` which has a
-`Less` method, and `s1` and `s2` are variables of type `String`, then the `Less`
+There are two different kinds of member access: _simple_ and _compound_. There
+is a [member access design document](/docs/design/expressions/member_access.md)
+with the details, but a summary of how they apply to generics is given here.
+
+### Simple member access
+
+Simple member access has the from `object.member`, where `member` is a word
+naming a member of `object`. This form may be used to access members of
+interfaces [implemented internally](#internal-impl) by the type of `object`.
+
+If `String` implements `Printable` internally, then `s1.Print()` calls the
+`Print` method of `Printable` using simple member access. In this case, the name
+`Print` is used without qualifying it with the name of the interface it is a
+member of since it is recognized as a member of the type itself as well.
+
+### Compound member access using qualified names
+
+Compound member access has the form `object.(expression)`, where `expression` is
+resolved in the containing scope. This expression may be the _qualified member
+name_ of an interface member, that consists of the name of the interface,
+possibly qualified with a package or namespace name, a dot `.` and the name of
+the member.
+
+For example, if the `Comparable` interface has a `Less` member method, then the
+qualified name of that member is `Comparable.Less`. So if `String` implements
+`Comparable`, and `s1` and `s2` are variables of type `String`, then the `Less`
 method may be called using the qualified member name by writing
 `s1.(Comparable.Less)(s2)`.
 
-If the interface is implemented internally, then the method can be called using
-the unqualified syntax as well. If `String` implements `Printable` internally,
-then `s1.Print()` calls the `Print` method of `Printable` as an unqualified
-member.
+This form may be used to access any member of an interface implemented for a
+type, whether it is implemented [internally](#internal-impl) or
+[externally](#external-impl).
 
 ## Compatible types