mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 18:40:16 +01:00
Switch generics to using compound/simple member access terminology (#1138)
This is following #1119 . * Updates terminology.md, overview.md, details.md
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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)();
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user