|
@@ -10,8 +10,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
|
|
|
|
## Table of contents
|
|
## Table of contents
|
|
|
|
|
|
|
|
-- [Parameterized language constructs](#parameterized-language-constructs)
|
|
|
|
|
-- [Generic versus template parameters](#generic-versus-template-parameters)
|
|
|
|
|
|
|
+- [Generic means compile-time parameterized](#generic-means-compile-time-parameterized)
|
|
|
|
|
+- [Checked versus template parameters](#checked-versus-template-parameters)
|
|
|
- [Polymorphism](#polymorphism)
|
|
- [Polymorphism](#polymorphism)
|
|
|
- [Parametric polymorphism](#parametric-polymorphism)
|
|
- [Parametric polymorphism](#parametric-polymorphism)
|
|
|
- [Compile-time duck typing](#compile-time-duck-typing)
|
|
- [Compile-time duck typing](#compile-time-duck-typing)
|
|
@@ -21,6 +21,12 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
- [Definition checking](#definition-checking)
|
|
- [Definition checking](#definition-checking)
|
|
|
- [Complete definition checking](#complete-definition-checking)
|
|
- [Complete definition checking](#complete-definition-checking)
|
|
|
- [Early versus late type checking](#early-versus-late-type-checking)
|
|
- [Early versus late type checking](#early-versus-late-type-checking)
|
|
|
|
|
+- [Bindings](#bindings)
|
|
|
|
|
+- [Types and `type`](#types-and-type)
|
|
|
|
|
+- [Facet type](#facet-type)
|
|
|
|
|
+- [Facet](#facet)
|
|
|
|
|
+- [Type expression](#type-expression)
|
|
|
|
|
+- [Facet binding](#facet-binding)
|
|
|
- [Deduced parameter](#deduced-parameter)
|
|
- [Deduced parameter](#deduced-parameter)
|
|
|
- [Interface](#interface)
|
|
- [Interface](#interface)
|
|
|
- [Structural interfaces](#structural-interfaces)
|
|
- [Structural interfaces](#structural-interfaces)
|
|
@@ -28,8 +34,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
- [Named constraints](#named-constraints)
|
|
- [Named constraints](#named-constraints)
|
|
|
- [Associated entity](#associated-entity)
|
|
- [Associated entity](#associated-entity)
|
|
|
- [Impl: Implementation of an interface](#impl-implementation-of-an-interface)
|
|
- [Impl: Implementation of an interface](#impl-implementation-of-an-interface)
|
|
|
- - [Internal impl](#internal-impl)
|
|
|
|
|
- - [External impl](#external-impl)
|
|
|
|
|
|
|
+ - [Extending an impl](#extending-an-impl)
|
|
|
- [Member access](#member-access)
|
|
- [Member access](#member-access)
|
|
|
- [Simple member access](#simple-member-access)
|
|
- [Simple member access](#simple-member-access)
|
|
|
- [Qualified member access expression](#qualified-member-access-expression)
|
|
- [Qualified member access expression](#qualified-member-access-expression)
|
|
@@ -46,50 +51,60 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
- [Instantiation](#instantiation)
|
|
- [Instantiation](#instantiation)
|
|
|
- [Specialization](#specialization)
|
|
- [Specialization](#specialization)
|
|
|
- [Template specialization](#template-specialization)
|
|
- [Template specialization](#template-specialization)
|
|
|
- - [Generic specialization](#generic-specialization)
|
|
|
|
|
|
|
+ - [Checked-generic specialization](#checked-generic-specialization)
|
|
|
- [Conditional conformance](#conditional-conformance)
|
|
- [Conditional conformance](#conditional-conformance)
|
|
|
-- [Interface type parameters and associated types](#interface-type-parameters-and-associated-types)
|
|
|
|
|
|
|
+- [Interface parameters and associated constants](#interface-parameters-and-associated-constants)
|
|
|
- [Type constraints](#type-constraints)
|
|
- [Type constraints](#type-constraints)
|
|
|
-- [Type-of-type](#type-of-type)
|
|
|
|
|
- [References](#references)
|
|
- [References](#references)
|
|
|
|
|
|
|
|
<!-- tocstop -->
|
|
<!-- tocstop -->
|
|
|
|
|
|
|
|
-## Parameterized language constructs
|
|
|
|
|
|
|
+## Generic means compile-time parameterized
|
|
|
|
|
|
|
|
-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-and-associated-types).
|
|
|
|
|
|
|
+Generally speaking, when we talk about _generics_, either
|
|
|
|
|
+[checked or template](#checked-versus-template-parameters), we are talking about
|
|
|
|
|
+generalizing some language construct by adding a compile-time parameter, called
|
|
|
|
|
+a _generic parameter_, to it. So:
|
|
|
|
|
+
|
|
|
|
|
+- a _generic function_ is a function with at least one compile-time parameter,
|
|
|
|
|
+ which could be an explicit argument to the function or
|
|
|
|
|
+ [deduced](#deduced-parameter);
|
|
|
|
|
+- a _generic type_ is a function with a compile-time parameter, for example a
|
|
|
|
|
+ container type parameterized by the type of the contained elements;
|
|
|
|
|
+- a _generic interface_ is an [interface](#interface) with
|
|
|
|
|
+ [a compile-time parameter](#interface-parameters-and-associated-constants).
|
|
|
|
|
|
|
|
This parameter broadens the scope of the language construct on an axis defined
|
|
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
|
|
by that parameter, for example it could define a family of functions instead of
|
|
|
a single one.
|
|
a single one.
|
|
|
|
|
|
|
|
-## Generic versus template parameters
|
|
|
|
|
|
|
+Note that different languages allow different things to be parameterized; for
|
|
|
|
|
+example, Rust supports
|
|
|
|
|
+[generic associated types](https://rust-lang.github.io/rfcs/1598-generic_associated_types.html).
|
|
|
|
|
+
|
|
|
|
|
+## Checked versus template parameters
|
|
|
|
|
|
|
|
-When we are distinguishing between generics and templates in Carbon, it is on a
|
|
|
|
|
|
|
+When we distinguish between checked and template generics in Carbon, it is on a
|
|
|
parameter by parameter basis. A single function can take a mix of regular,
|
|
parameter by parameter basis. A single function can take a mix of regular,
|
|
|
-generic, and template parameters.
|
|
|
|
|
|
|
+checked, and template parameters.
|
|
|
|
|
|
|
|
- **Regular parameters**, or "dynamic parameters", are designated using the
|
|
- **Regular parameters**, or "dynamic parameters", are designated using the
|
|
|
"\<name>`:` \<type>" syntax (or "\<value>").
|
|
"\<name>`:` \<type>" syntax (or "\<value>").
|
|
|
-- **Generic parameters** are designated using `:!` between the name and the
|
|
|
|
|
|
|
+- **Checked parameters** are designated using `:!` between the name and the
|
|
|
type (so it is "\<name>`:!` \<type>").
|
|
type (so it is "\<name>`:!` \<type>").
|
|
|
- **Template parameters** are designated using "`template` \<name>`:!`
|
|
- **Template parameters** are designated using "`template` \<name>`:!`
|
|
|
\<type>".
|
|
\<type>".
|
|
|
|
|
|
|
|
-The syntax for generic and template parameters was decided in
|
|
|
|
|
|
|
+The syntax for checked and template parameters was decided in
|
|
|
[questions-for-leads issue #565](https://github.com/carbon-language/carbon-lang/issues/565).
|
|
[questions-for-leads issue #565](https://github.com/carbon-language/carbon-lang/issues/565).
|
|
|
|
|
|
|
|
-Expected difference between generics and templates:
|
|
|
|
|
|
|
+Expected difference between checked and template parameters:
|
|
|
|
|
|
|
|
<table>
|
|
<table>
|
|
|
<tr>
|
|
<tr>
|
|
|
- <td><strong>Generics</strong>
|
|
|
|
|
|
|
+ <td><strong>Checked</strong>
|
|
|
</td>
|
|
</td>
|
|
|
- <td><strong>Templates</strong>
|
|
|
|
|
|
|
+ <td><strong>Template</strong>
|
|
|
</td>
|
|
</td>
|
|
|
</tr>
|
|
</tr>
|
|
|
<tr>
|
|
<tr>
|
|
@@ -107,7 +122,7 @@ Expected difference between generics and templates:
|
|
|
<tr>
|
|
<tr>
|
|
|
<td>name lookup resolved for definitions in isolation ("early")
|
|
<td>name lookup resolved for definitions in isolation ("early")
|
|
|
</td>
|
|
</td>
|
|
|
- <td>some name lookup may require information from calls (name lookup may be "late")
|
|
|
|
|
|
|
+ <td>name lookup can use information from arguments (name lookup may be "late")
|
|
|
</td>
|
|
</td>
|
|
|
</tr>
|
|
</tr>
|
|
|
<tr>
|
|
<tr>
|
|
@@ -138,7 +153,7 @@ Expected difference between generics and templates:
|
|
|
|
|
|
|
|
### Polymorphism
|
|
### Polymorphism
|
|
|
|
|
|
|
|
-Generics and templates provide different forms of
|
|
|
|
|
|
|
+Generics provide different forms of
|
|
|
[polymorphism](<https://en.wikipedia.org/wiki/Polymorphism_(computer_science)>)
|
|
[polymorphism](<https://en.wikipedia.org/wiki/Polymorphism_(computer_science)>)
|
|
|
than object-oriented programming with inheritance. That uses
|
|
than object-oriented programming with inheritance. That uses
|
|
|
[subtype polymorphism](https://en.wikipedia.org/wiki/Subtyping) where different
|
|
[subtype polymorphism](https://en.wikipedia.org/wiki/Subtyping) where different
|
|
@@ -186,19 +201,19 @@ Templates work with ad-hoc polymorphism in two ways:
|
|
|
will only resolve that call after the types are known.
|
|
will only resolve that call after the types are known.
|
|
|
|
|
|
|
|
In Carbon, we expect there to be a compile error if overloading of some name
|
|
In Carbon, we expect there to be a compile error if overloading of some name
|
|
|
-prevents a generic function from being typechecked from its definition alone.
|
|
|
|
|
-For example, let's say we have some overloaded function called `F` that has two
|
|
|
|
|
-overloads:
|
|
|
|
|
|
|
+prevents a checked-generic function from being typechecked from its definition
|
|
|
|
|
+alone. For example, let's say we have some overloaded function called `F` that
|
|
|
|
|
+has two overloads:
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
fn F[template T:! type](x: T*) -> T;
|
|
fn F[template T:! type](x: T*) -> T;
|
|
|
fn F(x: Int) -> bool;
|
|
fn F(x: Int) -> bool;
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-A generic function `G` can call `F` with a type like `T*` that cannot possibly
|
|
|
|
|
-call the `F(Int)` overload for `F`, and so it can consistently determine the
|
|
|
|
|
-return type of `F`. But `G` can't call `F` with an argument that could match
|
|
|
|
|
-either overload.
|
|
|
|
|
|
|
+A checked generic function `G` can call `F` with a type like `T*` that cannot
|
|
|
|
|
+possibly call the `F(Int)` overload for `F`, and so it can consistently
|
|
|
|
|
+determine the return type of `F`. But `G` can't call `F` with an argument that
|
|
|
|
|
+could match either overload.
|
|
|
|
|
|
|
|
**Note:** It is undecided what to do in the situation where `F` is overloaded,
|
|
**Note:** It is undecided what to do in the situation where `F` is overloaded,
|
|
|
but the signatures are consistent and so callers could still typecheck calls to
|
|
but the signatures are consistent and so callers could still typecheck calls to
|
|
@@ -220,15 +235,15 @@ they could be removed and the function would still have the same capabilities.
|
|
|
Constraints only affect the caller, which will use them to resolve overloaded
|
|
Constraints only affect the caller, which will use them to resolve overloaded
|
|
|
calls to the template and provide clearer error messages.
|
|
calls to the template and provide clearer error messages.
|
|
|
|
|
|
|
|
-With generics using constrained genericity, the function body can be checked
|
|
|
|
|
-against the signature at the time of definition. Note that it is still perfectly
|
|
|
|
|
-permissible to have no constraints on a type; that just means that you can only
|
|
|
|
|
-perform operations that work for all types (such as manipulate pointers to
|
|
|
|
|
-values of that type) in the body of the function.
|
|
|
|
|
|
|
+With checked generics using constrained genericity, the function body can be
|
|
|
|
|
+checked against the signature at the time of definition. Note that it is still
|
|
|
|
|
+perfectly permissible to have no constraints on a type; that just means that you
|
|
|
|
|
+can only perform operations that work for all types (such as manipulate pointers
|
|
|
|
|
+to values of that type) in the body of the function.
|
|
|
|
|
|
|
|
### Dependent names
|
|
### Dependent names
|
|
|
|
|
|
|
|
-A name is said to be _dependent_ if it depends on some generic or template
|
|
|
|
|
|
|
+A name is said to be _dependent_ if it depends on some checked or template
|
|
|
parameter. Note: this matches
|
|
parameter. Note: this matches
|
|
|
[the use of the term "dependent" in C++](https://www.google.com/search?q=c%2B%2B+dependent+name),
|
|
[the use of the term "dependent" in C++](https://www.google.com/search?q=c%2B%2B+dependent+name),
|
|
|
not as in [dependent types](https://en.wikipedia.org/wiki/Dependent_type).
|
|
not as in [dependent types](https://en.wikipedia.org/wiki/Dependent_type).
|
|
@@ -236,11 +251,11 @@ not as in [dependent types](https://en.wikipedia.org/wiki/Dependent_type).
|
|
|
### Definition checking
|
|
### Definition checking
|
|
|
|
|
|
|
|
Definition checking is the process of semantically checking the definition of
|
|
Definition checking is the process of semantically checking the definition of
|
|
|
-parameterized code for correctness _independently_ of any particular arguments.
|
|
|
|
|
-It includes type checking and other semantic checks. It is possible, even with
|
|
|
|
|
-templates, to check semantics of expressions that are not
|
|
|
|
|
|
|
+parameterized code for correctness _independently_ of any particular argument
|
|
|
|
|
+values. It includes type checking and other semantic checks. It is possible,
|
|
|
|
|
+even with templates, to check semantics of expressions that are not
|
|
|
[dependent](#dependent-names) on any template parameter in the definition.
|
|
[dependent](#dependent-names) on any template parameter in the definition.
|
|
|
-Adding constraints to template parameters and/or switching them to be generic
|
|
|
|
|
|
|
+Adding constraints to template parameters and/or switching them to be checked
|
|
|
allows the compiler to increase how much of the definition can be checked. Any
|
|
allows the compiler to increase how much of the definition can be checked. Any
|
|
|
remaining checks are delayed until [instantiation](#instantiation), which can
|
|
remaining checks are delayed until [instantiation](#instantiation), which can
|
|
|
fail.
|
|
fail.
|
|
@@ -250,21 +265,114 @@ fail.
|
|
|
Complete definition checking is when the definition can be _fully_ semantically
|
|
Complete definition checking is when the definition can be _fully_ semantically
|
|
|
checked, including type checking. It is an especially useful property because it
|
|
checked, including type checking. It is an especially useful property because it
|
|
|
enables _separate_ semantic checking of the definition, a prerequisite to
|
|
enables _separate_ semantic checking of the definition, a prerequisite to
|
|
|
-separate compilation. It also enables implementation strategies that don’t
|
|
|
|
|
-instantiate the implementation (for example, [type erasure](#type-erasure) or
|
|
|
|
|
|
|
+separate compilation. It also is a requirement for implementation strategies
|
|
|
|
|
+that don’t instantiate the implementation (for example,
|
|
|
|
|
+[type erasure](#type-erasure) or
|
|
|
[dynamic-dispatch witness tables](#dynamic-dispatch-witness-table)).
|
|
[dynamic-dispatch witness tables](#dynamic-dispatch-witness-table)).
|
|
|
|
|
|
|
|
#### Early versus late type checking
|
|
#### Early versus late type checking
|
|
|
|
|
|
|
|
Early type checking is where expressions and statements are type checked when
|
|
Early type checking is where expressions and statements are type checked when
|
|
|
the definition of the function body is compiled, as part of definition checking.
|
|
the definition of the function body is compiled, as part of definition checking.
|
|
|
-This occurs for regular and generic values.
|
|
|
|
|
|
|
+This occurs for regular and checked-generic values.
|
|
|
|
|
|
|
|
Late type checking is where expressions and statements may only be fully
|
|
Late type checking is where expressions and statements may only be fully
|
|
|
typechecked once calling information is known. Late type checking delays
|
|
typechecked once calling information is known. Late type checking delays
|
|
|
complete definition checking. This occurs for
|
|
complete definition checking. This occurs for
|
|
|
[template-dependent](#dependent-names) values.
|
|
[template-dependent](#dependent-names) values.
|
|
|
|
|
|
|
|
|
|
+## Bindings
|
|
|
|
|
+
|
|
|
|
|
+_Binding patterns_ associate a name with a type and a value. This is used to
|
|
|
|
|
+declare function parameters, in `let` and `var` declarations, as well as to
|
|
|
|
|
+declare [generic parameters](#generic-means-compile-time-parameterized). There
|
|
|
|
|
+are three kinds of binding patterns, corresponding to
|
|
|
|
|
+[the three value phases](/docs/design/README.md#value-categories-and-value-phases):
|
|
|
|
|
+
|
|
|
|
|
+- A _runtime binding pattern_ binds to a dynamic value at runtime, and is
|
|
|
|
|
+ written using a `:`, as in `x: i32`.
|
|
|
|
|
+- A _symbolic constant binding pattern_ or _symbolic binding pattern_ binds to
|
|
|
|
|
+ a compile-time value that is not known when type checking, and is used to
|
|
|
|
|
+ declare [checked generic](#checked-versus-template-parameters) parameters.
|
|
|
|
|
+ These binding use `:!`, as in `T:! type`.
|
|
|
|
|
+- A _template constant binding pattern_ or _template binding pattern_ binds to
|
|
|
|
|
+ a compile-time value that is known when type checking, and is used to
|
|
|
|
|
+ declare [template](#checked-versus-template-parameters) parameters. These
|
|
|
|
|
+ bindings use the keyword `template` in addition to `:!`, as in
|
|
|
|
|
+ `template T:! type`.
|
|
|
|
|
+
|
|
|
|
|
+The last two binding patterns, which are about binding a compile-time value, are
|
|
|
|
|
+called _constant binding patterns_, and correspond to those binding patterns
|
|
|
|
|
+that use `:!`.
|
|
|
|
|
+
|
|
|
|
|
+The name being declared, which is the identifier to the left of the `:` or `:!`,
|
|
|
|
|
+is called a _binding_, or more specifically a _runtime binding_, _constant
|
|
|
|
|
+binding_, _symbolic binding_, or _template binding_. The expression to the right
|
|
|
|
|
+defining the type of the binding pattern is called the _binding type
|
|
|
|
|
+expression_, a kind of [type expression](#type-expression). For example, in
|
|
|
|
|
+`T:! Hashable`, `T` is the binding (a symbolic binding in this case), and
|
|
|
|
|
+`Hashable` is the binding type expression.
|
|
|
|
|
+
|
|
|
|
|
+## Types and `type`
|
|
|
|
|
+
|
|
|
|
|
+A _type_ is a value of type `type`. Conversely, `type` is the type of all types.
|
|
|
|
|
+
|
|
|
|
|
+Expressions in type position, for example a [binding type expression](#bindings)
|
|
|
|
|
+or the return type of a function, are implicitly cast to type `type`. This means
|
|
|
|
|
+that it is legal to put a value that is not a type where a type is expected, as
|
|
|
|
|
+long as it has an implicit conversion to `type` that may be performed at compile
|
|
|
|
|
+time.
|
|
|
|
|
+
|
|
|
|
|
+## Facet type
|
|
|
|
|
+
|
|
|
|
|
+> **TODO:** Documents using the obsolete term "type-of-type" should be updated
|
|
|
|
|
+> to say "facet type" instead.
|
|
|
|
|
+
|
|
|
|
|
+A _facet type_ is a [type](#types-and-type) whose values are some subset of the
|
|
|
|
|
+values of `type`, determined by a set of [type constraints](#type-constraints):
|
|
|
|
|
+
|
|
|
|
|
+- [Interfaces](#interface) and [named constraints](#named-constraints) are
|
|
|
|
|
+ facet types whose constraints are that the interface or named constraint is
|
|
|
|
|
+ satisfied by the type.
|
|
|
|
|
+- The values produced by `&` operations between facet types and by `where`
|
|
|
|
|
+ expressions are facet types, whose set of constraints are determined by the
|
|
|
|
|
+ `&` or `where` expression.
|
|
|
|
|
+- `type` is a facet type whose set of constraints is empty.
|
|
|
|
|
+
|
|
|
|
|
+A facet type is the type used when declaring some type parameter. It foremost
|
|
|
|
|
+determines which types are legal arguments for that type parameter. For template
|
|
|
|
|
+parameters, that is all a facet type does. For checked parameters, it also
|
|
|
|
|
+determines the API that is available in the body of the definition of the
|
|
|
|
|
+[generic function, class, or other entity](#generic-means-compile-time-parameterized).
|
|
|
|
|
+
|
|
|
|
|
+## Facet
|
|
|
|
|
+
|
|
|
|
|
+A _facet_ is a value of a [facet type](#facet-type). For example,
|
|
|
|
|
+`i32 as Hashable` is a facet, and `Hashable` is a facet type. Note that all
|
|
|
|
|
+types are facets, since [`type`](#types-and-type) is considered a facet type.
|
|
|
|
|
+Not all facets are types, though: `i32 as Hashable` is of type `Hashable` not
|
|
|
|
|
+`type`, so it is a facet that is not a type. However, in places where a type is
|
|
|
|
|
+expected, for example in a [binding type expression](#bindings) or after the
|
|
|
|
|
+`->` in a function declaration, there is an automatic implicit conversion to
|
|
|
|
|
+`type`. This means that a facet may be used in those positions. For example, the
|
|
|
|
|
+facet `i32 as Hashable` will implicitly convert to `(i32 as Hashable) as type`,
|
|
|
|
|
+which is `i32`, in those contexts.
|
|
|
|
|
+
|
|
|
|
|
+## Type expression
|
|
|
|
|
+
|
|
|
|
|
+A _type expression_ is an expression that can be used as a type. In some cases,
|
|
|
|
|
+what is written in the source code is a value, like a [facet](#facet) or tuple
|
|
|
|
|
+of types, that is not a type but has an implicit conversion to `type`. In those
|
|
|
|
|
+cases, we are concerned with the type value after the implicit conversion.
|
|
|
|
|
+
|
|
|
|
|
+## Facet binding
|
|
|
|
|
+
|
|
|
|
|
+We use the term _facet binding_ to refer to the name introduced by a
|
|
|
|
|
+[constant binding pattern](#bindings) (using `:!` with or without the `template`
|
|
|
|
|
+modifier) where the declared type is a [facet type](#facet-type). In the binding
|
|
|
|
|
+pattern `T:! Hashable`, `T` is a facet binding, and the value of `T` is a
|
|
|
|
|
+[facet](#facet).
|
|
|
|
|
+
|
|
|
## Deduced parameter
|
|
## Deduced parameter
|
|
|
|
|
|
|
|
A deduced parameter is listed in the optional `[` `]` section right after the
|
|
A deduced parameter is listed in the optional `[` `]` section right after the
|
|
@@ -275,14 +383,6 @@ function name in a function signature:
|
|
|
|
|
|
|
|
Deduced arguments are determined as a result of pattern matching the explicit
|
|
Deduced arguments are determined as a result of pattern matching the explicit
|
|
|
argument values (usually the types of those values) to the explicit parameters.
|
|
argument values (usually the types of those values) to the explicit parameters.
|
|
|
-Note that function signatures can typically be rewritten to avoid using deduced
|
|
|
|
|
-parameters:
|
|
|
|
|
-
|
|
|
|
|
-```
|
|
|
|
|
-fn F[template T:! type](value: T);
|
|
|
|
|
-// is equivalent to:
|
|
|
|
|
-fn F(value: (template T:! type));
|
|
|
|
|
-```
|
|
|
|
|
|
|
|
|
|
See more [here](overview.md#deduced-parameters).
|
|
See more [here](overview.md#deduced-parameters).
|
|
|
|
|
|
|
@@ -294,7 +394,8 @@ to know about the interface requirements to call the function, not anything
|
|
|
about the implementation of the function body, and the compiler can check the
|
|
about the implementation of the function body, and the compiler can check the
|
|
|
function body without knowing anything more about the caller. Callers of the
|
|
function body without knowing anything more about the caller. Callers of the
|
|
|
function provide a value that has an implementation of the API and the body of
|
|
function provide a value that has an implementation of the API and the body of
|
|
|
-the function may then use that API (and nothing else).
|
|
|
|
|
|
|
+the function may then use that API. In the case of a checked generic, the
|
|
|
|
|
+function may _only_ use that API.
|
|
|
|
|
|
|
|
### Structural interfaces
|
|
### Structural interfaces
|
|
|
|
|
|
|
@@ -326,15 +427,20 @@ definition. The criteria for a named constraint, however, are less focused on
|
|
|
the type's API and instead might include a set of nominal interfaces that the
|
|
the type's API and instead might include a set of nominal interfaces that the
|
|
|
type must implement and constraints on the
|
|
type must implement and constraints on the
|
|
|
[associated entities](#associated-entity) and
|
|
[associated entities](#associated-entity) and
|
|
|
-[interface type parameters](#interface-type-parameters-and-associated-types).
|
|
|
|
|
|
|
+[interface parameters](#interface-parameters-and-associated-constants).
|
|
|
|
|
|
|
|
## Associated entity
|
|
## Associated entity
|
|
|
|
|
|
|
|
An _associated entity_ is a requirement in an interface that a type's
|
|
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
|
|
|
|
|
|
|
+implementation of the interface must satisfy by having a matching definition. A
|
|
|
requirement that the type define a value for a member constant is called an
|
|
requirement that the type define a value for a member constant is called an
|
|
|
-_associated constant_, and similarly an _associated function_ or _associated
|
|
|
|
|
-type_.
|
|
|
|
|
|
|
+_associated constant_. If the type of the associated constant is a
|
|
|
|
|
+[facet type](#facet-type), then it is called an _associated [facet](#facet)_,
|
|
|
|
|
+which corresponds to what is called an "associated type" in other languages
|
|
|
|
|
+([Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics/#Associated-Types),
|
|
|
|
|
+[Rust](https://doc.rust-lang.org/reference/items/associated-items.html#associated-types)).
|
|
|
|
|
+Similarly, an interface can have _associated function_, _associated method_, or
|
|
|
|
|
+_associated class function_.
|
|
|
|
|
|
|
|
Different types can satisfy an interface with different definitions for a given
|
|
Different types can satisfy an interface with different definitions for a given
|
|
|
member. These definitions are _associated_ with what type is implementing the
|
|
member. These definitions are _associated_ with what type is implementing the
|
|
@@ -349,27 +455,24 @@ instead of associated entity.
|
|
|
|
|
|
|
|
An _impl_ is an implementation of an interface for a specific type, called the
|
|
An _impl_ is an implementation of an interface for a specific type, called the
|
|
|
_implementing type_. It is the place where the function bodies are defined,
|
|
_implementing type_. It is the place where the function bodies are defined,
|
|
|
-values for associated types, etc. are given. Implementations are needed for
|
|
|
|
|
|
|
+values for associated constants, etc. are given. Implementations are needed for
|
|
|
[nominal interfaces](#nominal-interfaces);
|
|
[nominal interfaces](#nominal-interfaces);
|
|
|
[structural interfaces](#structural-interfaces) and
|
|
[structural interfaces](#structural-interfaces) and
|
|
|
[named constraints](#named-constraints) define conformance implicitly instead of
|
|
[named constraints](#named-constraints) define conformance implicitly instead of
|
|
|
-by requiring an impl to be defined. In can still make sense to implement a named
|
|
|
|
|
-constraint as a way to implement all of the interfaces it requires.
|
|
|
|
|
|
|
+by requiring an impl to be defined. In can still make sense to explicitly
|
|
|
|
|
+implement a named constraint as a way to implement all of the interfaces it
|
|
|
|
|
+requires.
|
|
|
|
|
|
|
|
-### Internal impl
|
|
|
|
|
|
|
+### Extending an impl
|
|
|
|
|
|
|
|
-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 are available by way of both
|
|
|
|
|
|
|
+A type that _extends_ the implementation of an interface has all the named
|
|
|
|
|
+members of the interface as named members of the type. This means that the
|
|
|
|
|
+members of the interface are available by way of both
|
|
|
[simple member access and qualified member access expressions](#member-access).
|
|
[simple member access and qualified member access expressions](#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
|
|
|
|
|
-[qualified member access expressions](#qualified-member-access-expression) for
|
|
|
|
|
-those members.
|
|
|
|
|
|
|
+If a type implements an interface without extending, the members of the
|
|
|
|
|
+interface may only be accessed using
|
|
|
|
|
+[qualified member access expressions](#qualified-member-access-expression).
|
|
|
|
|
|
|
|
## Member access
|
|
## Member access
|
|
|
|
|
|
|
@@ -382,12 +485,13 @@ qualified names, which we call a _qualified member access expression_.
|
|
|
|
|
|
|
|
Simple member access has the from `object.member`, where `member` is a word
|
|
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
|
|
naming a member of `object`. This form may be used to access members of
|
|
|
-interfaces [implemented internally](#internal-impl) by the type of `object`.
|
|
|
|
|
|
|
+interfaces when the type of `object`
|
|
|
|
|
+[extends the implementation](#extending-an-impl) of that interface.
|
|
|
|
|
|
|
|
-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.
|
|
|
|
|
|
|
+If `String` extends its implementation of `Printable`, 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.
|
|
|
|
|
|
|
|
### Qualified member access expression
|
|
### Qualified member access expression
|
|
|
|
|
|
|
@@ -406,8 +510,7 @@ method may be called using the qualified member name by writing the qualified
|
|
|
member access expression `s1.(Comparable.Less)(s2)`.
|
|
member access expression `s1.(Comparable.Less)(s2)`.
|
|
|
|
|
|
|
|
This form may be used to access any member of an interface implemented for a
|
|
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).
|
|
|
|
|
|
|
+type, whether or not it [extends the implementation](#extending-an-impl).
|
|
|
|
|
|
|
|
## Compatible types
|
|
## Compatible types
|
|
|
|
|
|
|
@@ -441,11 +544,10 @@ function signatures can change from base class to derived class, see
|
|
|
[covariance and contravariance in Wikipedia](<https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)>).
|
|
[covariance and contravariance in Wikipedia](<https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)>).
|
|
|
|
|
|
|
|
In a generics context, we are specifically interested in the subtyping
|
|
In a generics context, we are specifically interested in the subtyping
|
|
|
-relationships between [type-of-types](#type-of-type). In particular, a
|
|
|
|
|
-type-of-type encompasses a set of [type constraints](#type-constraints), and you
|
|
|
|
|
-can convert a type from a more-restrictive type-of-type to another type-of-type
|
|
|
|
|
-whose constraints are implied by the first. C++ concepts terminology uses the
|
|
|
|
|
-term
|
|
|
|
|
|
|
+relationships between [facet types](#facet-type). In particular, a facet type
|
|
|
|
|
+encompasses a set of [type constraints](#type-constraints), and you can convert
|
|
|
|
|
+a type from a more-restrictive facet type to another facet type whose
|
|
|
|
|
+constraints are implied by the first. C++ concepts terminology uses the term
|
|
|
["subsumes"](https://en.cppreference.com/w/cpp/language/constraints#Partial_ordering_of_constraints)
|
|
["subsumes"](https://en.cppreference.com/w/cpp/language/constraints#Partial_ordering_of_constraints)
|
|
|
to talk about this partial ordering of constraints, but we avoid that term since
|
|
to talk about this partial ordering of constraints, but we avoid that term since
|
|
|
it is at odds with the use of the term in
|
|
it is at odds with the use of the term in
|
|
@@ -470,23 +572,26 @@ permitted, always has the same meaning as an explicit cast.
|
|
|
|
|
|
|
|
## Coherence
|
|
## Coherence
|
|
|
|
|
|
|
|
-A generics system has the _implementation coherence_ property, or simply
|
|
|
|
|
-_coherence_, if there is a single answer to the question "what is the
|
|
|
|
|
|
|
+A generics or interface system has the _implementation coherence_ property, or
|
|
|
|
|
+simply _coherence_, if there is a single answer to the question "what is the
|
|
|
implementation of this interface for this type, if any?" independent of context,
|
|
implementation of this interface for this type, if any?" independent of context,
|
|
|
such as the libraries imported into a given file.
|
|
such as the libraries imported into a given file.
|
|
|
|
|
|
|
|
-This is typically enforced by making sure the definition of the implementation
|
|
|
|
|
-must be imported if you import both the interface and the type. This may be done
|
|
|
|
|
-by requiring the implementation to be in the same library as the interface or
|
|
|
|
|
-type. This is called an _orphan rule_, meaning we don't allow an implementation
|
|
|
|
|
-that is not with either of its parents (parent type or parent interface).
|
|
|
|
|
-
|
|
|
|
|
-Note that in addition to an orphan rule that implementations are visible when
|
|
|
|
|
-queried, coherence also requires a rule for resolving what happens if there are
|
|
|
|
|
-multiple non-orphan implementations. In Rust, this is called the
|
|
|
|
|
-[overlap rule or overlap check](https://rust-lang.github.io/chalk/book/clauses/coherence.html#chalk-overlap-check).
|
|
|
|
|
-This could be just producing an error in that situation, or picking one using
|
|
|
|
|
-some specialization rule.
|
|
|
|
|
|
|
+This is enforced using two kinds of rules:
|
|
|
|
|
+
|
|
|
|
|
+- An _orphan rule_ is a restriction on which files may declare a particular
|
|
|
|
|
+ implementation. This is to ensure that the implementation is imported any
|
|
|
|
|
+ time it could be used. For example, if neither the type nor the interface is
|
|
|
|
|
+ parameterized, the orphan rule requires that the implementation must be in
|
|
|
|
|
+ the same library as the interface or type. The rule is we don't allow an
|
|
|
|
|
+ _orphan_ implementation that is not with either of its parents (parent type
|
|
|
|
|
+ or parent interface).
|
|
|
|
|
+- An _overlap rule_ is a way to _consistently_ select a single implementation
|
|
|
|
|
+ when multiple implementations apply. In Carbon, overlap is resolved by
|
|
|
|
|
+ picking a single implementation using a rule that picks the one that is
|
|
|
|
|
+ considered most specialized. In Rust, by contrast, the
|
|
|
|
|
+ [overlap rule or overlap check](https://rust-lang.github.io/chalk/book/clauses/coherence.html#chalk-overlap-check)
|
|
|
|
|
+ instead produces an error if two implementations apply at once.
|
|
|
|
|
|
|
|
## Adapting a type
|
|
## Adapting a type
|
|
|
|
|
|
|
@@ -513,9 +618,9 @@ and as a workaround for
|
|
|
|
|
|
|
|
"Type erasure" is where a type's API is replaced by a subset. Everything outside
|
|
"Type erasure" is where a type's API is replaced by a subset. Everything outside
|
|
|
of the preserved subset is said to have been "erased". This can happen in a
|
|
of the preserved subset is said to have been "erased". This can happen in a
|
|
|
-variety of contexts including both generics and runtime polymorphism. For
|
|
|
|
|
-generics, type erasure restricts a type to just the API required by the
|
|
|
|
|
-constraints on a generic function.
|
|
|
|
|
|
|
+variety of contexts including both checked generics and runtime polymorphism.
|
|
|
|
|
+For checked generics, type erasure restricts a type to just the API required by
|
|
|
|
|
+the constraints on that type stated in the signature of the function.
|
|
|
|
|
|
|
|
An example of type erasure in runtime polymorphism in C++ is casting from a
|
|
An example of type erasure in runtime polymorphism in C++ is casting from a
|
|
|
pointer of a derived type to a pointer to an abstract base type. Only the API of
|
|
pointer of a derived type to a pointer to an abstract base type. Only the API of
|
|
@@ -531,13 +636,13 @@ of "type erasure" used in Carbon.
|
|
|
|
|
|
|
|
A placeholder type is used when type checking a function in place of a generic
|
|
A placeholder type is used when type checking a function in place of a generic
|
|
|
type parameter. This allows type checking when the specific type to be used is
|
|
type parameter. This allows type checking when the specific type to be used is
|
|
|
-not known at type checking time. The type satisfies just its constraint and no
|
|
|
|
|
|
|
+not known at type-checking time. The type satisfies just its constraint and no
|
|
|
more, so it acts as the most general type satisfying the interface. In this way
|
|
more, so it acts as the most general type satisfying the interface. In this way
|
|
|
the archetype is the supertype of all types satisfying the interface.
|
|
the archetype is the supertype of all types satisfying the interface.
|
|
|
|
|
|
|
|
In addition to satisfying all the requirements of its constraint, the archetype
|
|
In addition to satisfying all the requirements of its constraint, the archetype
|
|
|
also has the member names of its constraint. Effectively it is considered to
|
|
also has the member names of its constraint. Effectively it is considered to
|
|
|
-[implement the constraint internally](#internal-impl).
|
|
|
|
|
|
|
+[extend the implementation of the constraint](#extending-an-impl).
|
|
|
|
|
|
|
|
## Extending an interface
|
|
## Extending an interface
|
|
|
|
|
|
|
@@ -549,18 +654,18 @@ interface.
|
|
|
## Witness tables
|
|
## Witness tables
|
|
|
|
|
|
|
|
[Witness tables](https://forums.swift.org/t/where-does-the-term-witness-table-come-from/54334/4)
|
|
[Witness tables](https://forums.swift.org/t/where-does-the-term-witness-table-come-from/54334/4)
|
|
|
-are an implementation strategy where values passed to a generic parameter are
|
|
|
|
|
-compiled into a table of required functionality. That table is then filled in
|
|
|
|
|
-for a given passed-in type with references to the implementation on the original
|
|
|
|
|
-type. The generic is implemented using calls into entries in the witness table,
|
|
|
|
|
-which turn into calls to the original type. This doesn't necessarily imply a
|
|
|
|
|
-runtime indirection: it may be a purely compile-time separation of concerns.
|
|
|
|
|
-However, it insists on a full abstraction boundary between the generic user of a
|
|
|
|
|
-type and the concrete implementation.
|
|
|
|
|
|
|
+are an implementation strategy where values passed to a generic type parameter
|
|
|
|
|
+are compiled into a table of required functionality. That table is then filled
|
|
|
|
|
+in for a given passed-in type with references to the implementation on the
|
|
|
|
|
+original type. The generic is implemented using calls into entries in the
|
|
|
|
|
+witness table, which turn into calls to the original type. This doesn't
|
|
|
|
|
+necessarily imply a runtime indirection: it may be a purely compile-time
|
|
|
|
|
+separation of concerns. However, it insists on a full abstraction boundary
|
|
|
|
|
+between the generic user of a type and the concrete implementation.
|
|
|
|
|
|
|
|
A simple way to imagine a witness table is as a struct of function pointers, one
|
|
A simple way to imagine a witness table is as a struct of function pointers, one
|
|
|
per method in the interface. However, in practice, it's more complex because it
|
|
per method in the interface. However, in practice, it's more complex because it
|
|
|
-must model things like associated types and interfaces.
|
|
|
|
|
|
|
+must model things like associated facets and interfaces.
|
|
|
|
|
|
|
|
Witness tables are called "dictionary passing" in Haskell. Outside of generics,
|
|
Witness tables are called "dictionary passing" in Haskell. Outside of generics,
|
|
|
a [vtable](https://en.wikipedia.org/wiki/Virtual_method_table) is a witness
|
|
a [vtable](https://en.wikipedia.org/wiki/Virtual_method_table) is a witness
|
|
@@ -606,24 +711,25 @@ and other errors may only happen for **some** instantiations.
|
|
|
|
|
|
|
|
### Template specialization
|
|
### Template specialization
|
|
|
|
|
|
|
|
-Specialization in C++ is essentially overloading in the context of a template.
|
|
|
|
|
-The template is overloaded to have a different definition for some subset of the
|
|
|
|
|
|
|
+Specialization in C++ is essentially overloading, or
|
|
|
|
|
+[ad-hoc polymorphism](#ad-hoc-polymorphism), in the context of a template. The
|
|
|
|
|
+template is overloaded to have a different definition for some subset of the
|
|
|
possible template argument values. For example, the C++ type `std::vector<T>`
|
|
possible template argument values. For example, the C++ type `std::vector<T>`
|
|
|
might have a specialization `std::vector<T*>` that is implemented in terms of
|
|
might have a specialization `std::vector<T*>` that is implemented in terms of
|
|
|
`std::vector<void*>` to reduce code size. In C++, even the interface of a
|
|
`std::vector<void*>` to reduce code size. In C++, even the interface of a
|
|
|
templated type can be changed in a specialization, as happens for
|
|
templated type can be changed in a specialization, as happens for
|
|
|
`std::vector<bool>`.
|
|
`std::vector<bool>`.
|
|
|
|
|
|
|
|
-### Generic specialization
|
|
|
|
|
|
|
+### Checked-generic specialization
|
|
|
|
|
|
|
|
-Specialization of generics, or types used by generics, is restricted to changing
|
|
|
|
|
-the implementation _without_ affecting the interface. This restriction is needed
|
|
|
|
|
-to preserve the ability to perform type checking of generic definitions that
|
|
|
|
|
-reference a type that can be specialized, without statically knowing which
|
|
|
|
|
-specialization will be used.
|
|
|
|
|
|
|
+Specialization of checked generics, or types used by checked generics, is
|
|
|
|
|
+restricted to changing the implementation _without_ affecting the interface.
|
|
|
|
|
+This restriction is needed to preserve the ability to perform type checking of
|
|
|
|
|
+generic definitions that reference a type that can be specialized, without
|
|
|
|
|
+statically knowing which specialization will be used.
|
|
|
|
|
|
|
|
While there is nothing fundamentally incompatible about specialization with
|
|
While there is nothing fundamentally incompatible about specialization with
|
|
|
-generics, even when implemented using witness tables, the result may be
|
|
|
|
|
|
|
+checked generics, even when implemented using witness tables, the result may be
|
|
|
surprising because the selection of the specialized generic happens outside of
|
|
surprising because the selection of the specialized generic happens outside of
|
|
|
the witness-table-based indirection between the generic code and the concrete
|
|
the witness-table-based indirection between the generic code and the concrete
|
|
|
implementation. Provided all selection relies exclusively on interfaces, this
|
|
implementation. Provided all selection relies exclusively on interfaces, this
|
|
@@ -636,10 +742,11 @@ that it always supports, but satisfies additional interfaces under some
|
|
|
conditions on the type argument. For example: `Array(T)` might implement
|
|
conditions on the type argument. For example: `Array(T)` might implement
|
|
|
`Comparable` if `T` itself implements `Comparable`, using lexicographical order.
|
|
`Comparable` if `T` itself implements `Comparable`, using lexicographical order.
|
|
|
|
|
|
|
|
-## Interface type parameters and associated types
|
|
|
|
|
|
|
+## Interface parameters and associated constants
|
|
|
|
|
|
|
|
-_Interface type parameters_ and _associated types_ are both ways of allowing the
|
|
|
|
|
-types in function signatures in an interface to vary. For example, different
|
|
|
|
|
|
|
+_Interface parameters_ and [associated constants](#associated-entity) are both
|
|
|
|
|
+ways of allowing the types in function signatures in an interface to vary. For
|
|
|
|
|
+example, different
|
|
|
[stacks](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>) will have
|
|
[stacks](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>) will have
|
|
|
different element types. That element type would be used as the parameter type
|
|
different element types. That element type would be used as the parameter type
|
|
|
of the `Push` function and the return type of the `Pop` function. As
|
|
of the `Push` function and the return type of the `Pop` function. As
|
|
@@ -647,19 +754,18 @@ of the `Push` function and the return type of the `Pop` function. As
|
|
|
we can distinguish these by whether they are input parameters or output
|
|
we can distinguish these by whether they are input parameters or output
|
|
|
parameters:
|
|
parameters:
|
|
|
|
|
|
|
|
-- An interface type parameter is a parameter or input to the interface type.
|
|
|
|
|
- That means they must be specified before an implementation of the interface
|
|
|
|
|
- may be determined.
|
|
|
|
|
-- In contrast, associated types are outputs. This means that they are
|
|
|
|
|
- determined by the implementation, and need not be specified in a type
|
|
|
|
|
- constraint.
|
|
|
|
|
|
|
+- An interface parameter is a parameter or input to the interface. That means
|
|
|
|
|
+ they must be specified before an implementation of the interface may be
|
|
|
|
|
+ determined.
|
|
|
|
|
+- In contrast, associated constants are outputs. This means that they are
|
|
|
|
|
+ determined by the implementation, and need not be specified in a
|
|
|
|
|
+ [type constraint](#type-constraints).
|
|
|
|
|
|
|
|
Functions using an interface as a constraint need not specify the value of its
|
|
Functions using an interface as a constraint need not specify the value of its
|
|
|
-associated types. An associated type is a kind of
|
|
|
|
|
-[associated entity](#associated-entity).
|
|
|
|
|
|
|
+associated constants.
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
-// Stack using associated types
|
|
|
|
|
|
|
+// Stack using associated facets
|
|
|
interface Stack {
|
|
interface Stack {
|
|
|
let ElementType:! type;
|
|
let ElementType:! type;
|
|
|
fn Push[addr self: Self*](value: ElementType);
|
|
fn Push[addr self: Self*](value: ElementType);
|
|
@@ -668,7 +774,7 @@ interface Stack {
|
|
|
|
|
|
|
|
// Works on any type implementing `Stack`. Return type
|
|
// Works on any type implementing `Stack`. Return type
|
|
|
// is determined by the type's implementation of `Stack`.
|
|
// is determined by the type's implementation of `Stack`.
|
|
|
-fn PeekAtTopOfStack[T: Stack](s: T*) -> T.ElementType {
|
|
|
|
|
|
|
+fn PeekAtTopOfStack[T:! Stack](s: T*) -> T.ElementType {
|
|
|
let ret: T.ElementType = s->Pop();
|
|
let ret: T.ElementType = s->Pop();
|
|
|
s->Push(ret);
|
|
s->Push(ret);
|
|
|
return ret;
|
|
return ret;
|
|
@@ -682,17 +788,17 @@ class FruitStack {
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Associated types are particularly called for when the implementation of the
|
|
|
|
|
-interface determines the type, not the caller. For example, the iterator type
|
|
|
|
|
|
|
+Associated constants are particularly called for when the implementation of the
|
|
|
|
|
+interface determines the value, not the caller. For example, the iterator type
|
|
|
for a container is specific to the container and not something you would expect
|
|
for a container is specific to the container and not something you would expect
|
|
|
a user of the interface to specify.
|
|
a user of the interface to specify.
|
|
|
|
|
|
|
|
-If you have an interface with type parameters, a type can have multiple matching
|
|
|
|
|
-impl declarations 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 parameters, a type can have multiple matching
|
|
|
|
|
+`impl` declarations for different combinations of argument values. As a result,
|
|
|
|
|
+interface 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 constants.
|
|
|
|
|
|
|
|
For example, we might have an interface that says how to perform addition with
|
|
For example, we might have an interface that says how to perform addition with
|
|
|
another type:
|
|
another type:
|
|
@@ -726,8 +832,8 @@ fn DoAdd[T:! type, U:! AddWith(T)](x: U, y: T) -> U.ResultType {
|
|
|
fn CompileError[T:! type, U:! AddWith(T)](x: U) -> T;
|
|
fn CompileError[T:! type, U:! AddWith(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
|
|
|
|
|
|
|
+Once the interface parameters can be determined, that determines the values for
|
|
|
|
|
+associated constants, such as `ResultType` in the example. As always, calls with
|
|
|
types for which no implementation exists will be rejected at the call site:
|
|
types for which no implementation exists will be rejected at the call site:
|
|
|
|
|
|
|
|
```
|
|
```
|
|
@@ -736,36 +842,32 @@ types for which no implementation exists will be rejected at the call site:
|
|
|
DoAdd(apple, orange);
|
|
DoAdd(apple, orange);
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
|
|
+The type of an interface parameters and associated constants is commonly a
|
|
|
|
|
+[facet type](#facet-type), but not always. For example, an interface parameter
|
|
|
|
|
+that specifies an array bound might have an integer type.
|
|
|
|
|
+
|
|
|
## Type constraints
|
|
## Type constraints
|
|
|
|
|
|
|
|
-Type constraints restrict which types are legal for template or generic
|
|
|
|
|
-parameters or associated types. They help define semantics under which they
|
|
|
|
|
-should be called, and prevent incorrect calls.
|
|
|
|
|
|
|
+Type constraints restrict which types are legal for generic parameters or
|
|
|
|
|
+associated facets. They help define semantics under which they should be called,
|
|
|
|
|
+and prevent incorrect calls.
|
|
|
|
|
|
|
|
In general there are a number of different type relationships we would like to
|
|
In general there are a number of different type relationships we would like to
|
|
|
express, for example:
|
|
express, for example:
|
|
|
|
|
|
|
|
- This function accepts two containers. The container types may be different,
|
|
- This function accepts two containers. The container types may be different,
|
|
|
but the element types need to match.
|
|
but the element types need to match.
|
|
|
-- For this container interface we have associated types for iterators and
|
|
|
|
|
|
|
+- For this container interface we have associated facets for iterators and
|
|
|
elements. The iterator type's element type needs to match the container's
|
|
elements. The iterator type's element type needs to match the container's
|
|
|
element type.
|
|
element type.
|
|
|
-- An interface may define an associated type that needs to be constrained to
|
|
|
|
|
|
|
+- An interface may define an associated facet that needs to be constrained to
|
|
|
implement some interfaces.
|
|
implement some interfaces.
|
|
|
- This type must be [compatible](#compatible-types) with another type. You
|
|
- This type must be [compatible](#compatible-types) with another type. You
|
|
|
might use this to define alternate implementations of a single interfaces,
|
|
might use this to define alternate implementations of a single interfaces,
|
|
|
such as sorting order, for a single type.
|
|
such as sorting order, for a single type.
|
|
|
|
|
|
|
|
-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
|
|
|
|
|
-
|
|
|
|
|
-A type-of-type is the type used when declaring some type parameter. It foremost
|
|
|
|
|
-determines which types are legal arguments for that type parameter, also known
|
|
|
|
|
-as [type constraints](#type-constraints). For template parameters, that is all a
|
|
|
|
|
-type-of-type does. For generic parameters, it also determines the API that is
|
|
|
|
|
-available in the body of the function.
|
|
|
|
|
|
|
+Note that type constraints can be a restriction on one facet parameter or
|
|
|
|
|
+associated facet, or can define a relationship between multiple facets.
|
|
|
|
|
|
|
|
## References
|
|
## References
|
|
|
|
|
|
|
@@ -773,3 +875,6 @@ available in the body of the function.
|
|
|
- [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)
|
|
- [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)
|
|
|
- [#950: Generic details 6: remove facets](https://github.com/carbon-language/carbon-lang/pull/950)
|
|
- [#950: Generic details 6: remove facets](https://github.com/carbon-language/carbon-lang/pull/950)
|
|
|
- [#1013: Generics: Set associated constants using where constraints](https://github.com/carbon-language/carbon-lang/pull/1013)
|
|
- [#1013: Generics: Set associated constants using where constraints](https://github.com/carbon-language/carbon-lang/pull/1013)
|
|
|
|
|
+- [#2138: Checked and template generic terminology](https://github.com/carbon-language/carbon-lang/pull/2138)
|
|
|
|
|
+- [#2360: Types are values of type `type`](https://github.com/carbon-language/carbon-lang/pull/2360)
|
|
|
|
|
+- [#2760: Consistent `class` and `interface` syntax](https://github.com/carbon-language/carbon-lang/pull/2760)
|