Skip to content

Commit

Permalink
Update Generics terminology document (#3048)
Browse files Browse the repository at this point in the history
This reflects changes from a number of approved proposals:
- #920 : concrete statements about orphan and overlap in Carbon
- #2138 : "generic" -> "checked generic", "template" -> "template
generic"
- #2188 : binding patterns are forbidden in type position
- #2360 : "type", "facet type", "facet". Note: I am not using the term
"generic type" from #2360 since that meaning conflicts with the
generally accepted meaning of "generic type" of a type with a
compile-time parameter.
- #2760 / #2770 : internal/external impl -> extending impl
- #2964 : "symbolic constant" and "template constant"

---------

Co-authored-by: Geoff Romer <[email protected]>
Co-authored-by: Richard Smith <[email protected]>
  • Loading branch information
3 people authored Aug 2, 2023
1 parent c8b4237 commit 587ab64
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 210 deletions.
4 changes: 2 additions & 2 deletions docs/design/classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ class MyDerivedClass {

The properties of a type, whether type is abstract, base, or final, and whether
the destructor is virtual or non-virtual, determines which
[type-of-types](/docs/design/generics/terminology.md#type-of-type) it satisfies.
[type-of-types](/docs/design/generics/terminology.md#facet-type) it satisfies.

- Non-abstract classes are `Concrete`. This means you can create local and
member variables of this type. `Concrete` types have destructors that are
Expand Down Expand Up @@ -1623,7 +1623,7 @@ conform to the decision on
| final | any | yes | yes | yes |

The compiler automatically determines which of these
[type-of-types](/docs/design/generics/terminology.md#type-of-type) a given type
[type-of-types](/docs/design/generics/terminology.md#facet-type) a given type
satisfies. It is illegal to directly implement `Concrete`, `Deletable`, or
`Destructible` directly. For more about these constraints, see
["destructor constraints" in the detailed generics design](/docs/design/generics/details.md#destructor-constraints).
Expand Down
4 changes: 2 additions & 2 deletions docs/design/expressions/implicit_conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ var r: Base** = &p;

### Type-of-types

A type `T` with [type-of-type](../generics/terminology.md#type-of-type) `TT1`
can be implicitly converted to the type-of-type `TT2` if `T`
A type `T` with [type-of-type](../generics/terminology.md#facet-type) `TT1` can
be implicitly converted to the type-of-type `TT2` if `T`
[satisfies the requirements](../generics/details.md#subtyping-between-type-of-types)
of `TT2`.

Expand Down
63 changes: 32 additions & 31 deletions docs/design/generics/details.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,9 @@ When the implementation of `ConvertibleToString` for `Song` is defined as
internal, every member of `ConvertibleToString` is also a member of `Song`. 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 a writing function call
[internal](terminology.md#extending-an-impl) or
[external](terminology.md#extending-an-impl), you may access the `ToString`
function for a `Song` value `s` by a writing function call
[using a qualified member access expression](terminology.md#qualified-member-access-expression),
like `s.(ConvertibleToString.ToString)()`.

Expand Down Expand Up @@ -359,8 +359,8 @@ class Player {
### External impl

Interfaces may also be implemented for a type
[externally](terminology.md#external-impl), by using `impl` without `extend`. An
external impl does not add the interface's methods to the type.
[externally](terminology.md#extending-an-impl), by using `impl` without
`extend`. An external impl does not add the interface's methods to the type.

```
class Point2 {
Expand Down Expand Up @@ -597,7 +597,7 @@ var v: Point = AddAndScaleGeneric(a, w, 2.5);
```

Here `T` is a type whose type is `Vector`. The `:!` syntax means that `T` is a
_[generic parameter](terminology.md#generic-versus-template-parameters)_. That
_[generic parameter](terminology.md#checked-versus-template-parameters)_. That
means it must be known to the caller, but we will only use the information
present in the signature of the function to type check the body of
`AddAndScaleGeneric`'s definition. In this case, we know that any value of type
Expand Down Expand Up @@ -628,13 +628,13 @@ acts like a [supertype](https://en.wikipedia.org/wiki/Subtyping) of any `T`
implementing `Vector`.

For name lookup purposes, an archetype is considered to have
[implemented its constraint internally](terminology.md#internal-impl). The only
oddity is that the archetype may have different names for members than specific
types `T` that implement interfaces from the constraint
[externally](terminology.md#external-impl). This difference in names can also
occur for supertypes in C++, for example members in a derived class can hide
members in the base class with the same name, though it is not that common for
it to come up in practice.
[implemented its constraint internally](terminology.md#extending-an-impl). The
only oddity is that the archetype may have different names for members than
specific types `T` that implement interfaces from the constraint
[externally](terminology.md#extending-an-impl). This difference in names can
also occur for supertypes in C++, for example members in a derived class can
hide members in the base class with the same name, though it is not that common
for it to come up in practice.

The behavior of calling `AddAndScaleGeneric` with a value of a specific type
like `Point` is to set `T` to `Point` after all the names have been qualified.
Expand All @@ -648,8 +648,8 @@ fn AddAndScaleForPoint(a: Point, b: Point, s: Double) -> Point {

This qualification gives a consistent interpretation to the body of the function
even when the type supplied by the caller
[implements the interface externally](terminology.md#external-impl), as `Point2`
does:
[implements the interface externally](terminology.md#extending-an-impl), as
`Point2` does:

```
// AddAndScaleGeneric with T = Point2
Expand Down Expand Up @@ -805,15 +805,15 @@ 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-compound-member-access), and
- as a [type-of-type](terminology.md#type-of-type) for
- as a [type-of-type](terminology.md#facet-type) for
[a generic type parameter](#generics).

While interfaces are examples of type-of-types, type-of-types are a more general
concept, for which interfaces are a building block.

## Type-of-types

A [type-of-type](terminology.md#type-of-type) consists of a set of requirements
A [type-of-type](terminology.md#facet-type) consists of a set of requirements
and a set of names. Requirements are typically a set of interfaces that a type
must satisfy, though other kinds of requirements are added below. The names are
aliases for qualified names in those interfaces.
Expand Down Expand Up @@ -883,7 +883,7 @@ whenever an interface may be. This includes all of these
[a qualified name](#qualified-member-names-and-compound-member-access). For
example, `VectorLegoFish.VAdd` refers to the same name as `Vector.Add`.
- A named constraint may be used as a
[type-of-type](terminology.md#type-of-type) for
[type-of-type](terminology.md#facet-type) for
[a generic type parameter](#generics).

We don't expect developers to directly define many named constraints, but other
Expand Down Expand Up @@ -1910,7 +1910,7 @@ fn Complex64.CloserToOrigin[self: Self](them: Self) -> bool {
### Use case: Accessing external names
Consider a case where a function will call several functions from an interface
that is [implemented externally](terminology.md#external-impl) for a type.
that is [implemented externally](terminology.md#extending-an-impl) for a type.
```
interface DrawingContext {
Expand All @@ -1924,9 +1924,10 @@ 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-member-access-expression)
each call to methods in the interface.
the interface is [implemented internally](terminology.md#extending-an-impl).
This avoids having to
[qualify](terminology.md#qualified-member-access-expression) each call to
methods in the interface.
```
class DrawInWindow {
Expand Down Expand Up @@ -2195,7 +2196,7 @@ class DynamicArray(T:! type) {
```
For context, see
["Interface type parameters and associated types" in the generics terminology document](terminology.md#interface-type-parameters-and-associated-types).
["Interface type parameters and associated types" in the generics terminology document](terminology.md#interface-parameters-and-associated-constants).
**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)
Expand Down Expand Up @@ -2245,7 +2246,7 @@ 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](terminology.md#interface-type-parameters-and-associated-types).
[parameterized interfaces](terminology.md#interface-parameters-and-associated-constants).
To write a parameterized version of the stack interface, instead of using
associated types, write a parameter list after the name of the interface instead
of the associated type declaration:
Expand Down Expand Up @@ -3166,8 +3167,8 @@ fn F[T:! Transitive](t: T) {
A value of type `A`, such as the return value of `GetA()`, has the API of `P`.
Any such value also implements `Q`, and since the compiler can see that by way
of a single `where` equality, values of type `A` are treated as if they
implement `Q` [externally](terminology.md#external-impl). However, the compiler
will require a cast to `B` or `C` to see that the type implements `R`.
implement `Q` [externally](terminology.md#extending-an-impl). However, the
compiler will require a cast to `B` or `C` to see that the type implements `R`.

```
fn TakesPQR[U:! P & Q & R](u: U);
Expand Down Expand Up @@ -3624,8 +3625,8 @@ In particular, the compiler should in general avoid monomorphizing to generate
multiple instantiations of the function in this case.

**Open question:** Should `TypeId` be
[implemented externally](terminology.md#external-impl) for types to avoid name
pollution (`.TypeName`, `.TypeHash`, etc.) unless the function specifically
[implemented externally](terminology.md#extending-an-impl) for types to avoid
name pollution (`.TypeName`, `.TypeHash`, etc.) unless the function specifically
requests those capabilities?

### Destructor constraints
Expand Down Expand Up @@ -5695,9 +5696,9 @@ be [implied constraints](#implied-constraints) on the function's parameters.

### Specialization

[Specialization](terminology.md#generic-specialization) is used to improve
performance in specific cases when a general strategy would be inefficient. For
example, you might use
[Specialization](terminology.md#checked-generic-specialization) is used to
improve performance in specific cases when a general strategy would be
inefficient. For example, you might use
[binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm) for
containers that support random access and keep their contents in sorted order
but [linear search](https://en.wikipedia.org/wiki/Linear_search) in other cases.
Expand Down
18 changes: 9 additions & 9 deletions docs/design/generics/goals.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ forward-looking.

## Background

Carbon will support
[generics](terminology.md#generic-versus-template-parameters) to support generic
programming by way of
[parameterization of language constructs](terminology.md#parameterized-language-constructs)
with [early type checking](terminology.md#early-versus-late-type-checking) and
Carbon will support both
[checked and template generics](terminology.md#checked-versus-template-parameters)
to support generic programming by way of
[compile-time parameterization of language constructs](terminology.md#generic-means-compile-time-parameterized).

Carbon's checked generics will feature
[early type checking](terminology.md#early-versus-late-type-checking) and
[complete definition checking](terminology.md#complete-definition-checking).

This is in contrast with the
Carbon's template generics, in contrast, will more closely follow the
[compile-time duck typing](https://en.wikipedia.org/wiki/Duck_typing#Templates_or_generic_types)
approach of C++ templates, and _in addition_ to
[template support in Carbon](#relationship-to-templates), if we decide to
support templates in Carbon beyond interoperability with C++ templates.
approach of C++ templates.

### Generic parameters

Expand Down
6 changes: 3 additions & 3 deletions docs/design/generics/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ definition is required after seeing the call sites once all the
[instantiations](terminology.md#instantiation) are known.

Note: [Generics terminology](terminology.md) goes into more detail about the
[differences between generics and templates](terminology.md#generic-versus-template-parameters).
[differences between generics and templates](terminology.md#checked-versus-template-parameters).

### Implementing interfaces

Expand Down Expand Up @@ -259,7 +259,7 @@ specific type value assigned to `T` is not known when type checking the
`SortVector` function. Instead it is the constraints on `T` that let the
compiler know what operations may be performed on values of type `T`. Those
constraints are represented by the type of `T`, a
[**_type-of-type_**](terminology.md#type-of-type).
[**_type-of-type_**](terminology.md#facet-type).

In general, a type-of-type describes the capabilities of a type, while a type
defines specific implementations of those capabilities. An interface, like
Expand Down Expand Up @@ -519,7 +519,7 @@ specific sort order.

### Interface input and output types

[Associated types and interface parameters](terminology.md#interface-type-parameters-and-associated-types)
[Associated types and interface parameters](terminology.md#interface-parameters-and-associated-constants)
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
Expand Down
Loading

0 comments on commit 587ab64

Please sign in to comment.