Update design overview to reflect submitted proposals (#3180)

Incorporates proposals: #1885, #2138, #2188, #2200, #2360, #2760, #2964,
and #3162.

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
josh11b
2023-09-08 22:04:48 +00:00
committed by GitHub
co-authored by Richard Smith
parent 75a7b5c9ee
commit 71f2eecec5
+260 -132
View File
@@ -19,6 +19,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Code and comments](#code-and-comments)
- [Build modes](#build-modes)
- [Types are values](#types-are-values)
- [Values usable as types](#values-usable-as-types)
- [Primitive types](#primitive-types)
- [`bool`](#bool)
- [Integer types](#integer-types)
@@ -90,7 +91,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- [Checked and template parameters](#checked-and-template-parameters)
- [Interfaces and implementations](#interfaces-and-implementations)
- [Combining constraints](#combining-constraints)
- [Associated types](#associated-types)
- [Template name lookup](#template-name-lookup)
- [Associated constants](#associated-constants)
- [Generic entities](#generic-entities)
- [Generic Classes](#generic-classes)
- [Generic choice types](#generic-choice-types)
@@ -383,8 +385,8 @@ The behavior of the Carbon compiler depends on the _build mode_:
Expressions compute values in Carbon, and these values are always strongly typed
much like in C++. However, an important difference from C++ is that types are
themselves modeled as values; specifically, compile-time-constant values. This
has a number of consequences:
themselves modeled as values; specifically, compile-time-constant values of type
`type`. This has a number of consequences:
- Names for types are in the same namespace shared with functions, variables,
namespaces, and so on.
@@ -395,14 +397,43 @@ has a number of consequences:
- Function call syntax is used to specify parameters to a type, like
`HashMap(String, i64)`.
Some values, such as `()` and `{}`, may even be used as types, but only act like
types when they are in a type position, like after a `:` in a variable
declaration or the return type after a `->` in a function declaration. Any
expression in a type position must be
[a compile-time constant](#expression-phases) so the compiler can resolve
whether the value can be used as a type. This also puts limits on how much
operators can do different things for types. This is good for consistency, but
is a significant restriction on Carbon's design.
> References:
>
> - Proposal
> [#2360: Types are values of type `type`](https://github.com/carbon-language/carbon-lang/pull/2360)
### Values usable as types
A value used in a type position, like after a `:` in a variable declaration or
the return type after a `->` in a function declaration, must:
- be [a compile-time constant](#expression-phases), so the compiler can
evaluate it at compile time, and
- have a defined implicit conversion to type `type`.
The actual type used is the result of the conversion to type `type`. Of course
this includes values that already are of type `type`, but also allows some
non-type values to be used in a type position.
For example, the value `(bool, bool)` represents a [tuple](#tuples) of types,
but is not itself a type, since it doesn't have type `type`. It does have a
defined implicit conversion to type `type`, which results in the value
`(bool, bool) as type`. This means `(bool, bool)` may be used in a type
position. `(bool, bool) as type` is the type of the value `(true, false)` (among
others), so this code is legal:
```carbon
var b: (bool, bool) = (true, false);`
```
There is some need to be careful here, since the declaration makes it look like
the type of `b` is `(bool, bool)`, when in fact it is `(bool, bool) as type`.
`(bool, bool) as type` and `(bool, bool)` are different values since they have
different types: the first has type `type`, and the second has type
`(type, type) as type`.
In addition to the types of [tuples](#tuples), this also comes up with
[struct types](#struct-types) and [facets](generics/terminology.md#facet).
## Primitive types
@@ -707,8 +738,8 @@ Value expressions are further broken down into three _expression phases_:
expressions with checked-generic arguments, like `Optional(T*)`.
- A _runtime value_ has a dynamic value only known at runtime.
Template constants together with symbolic constants are referred to as
_compile-time constants_.
Template constants and symbolic constants are collectively called _compile-time
constants_ and correspond to declarations using `:!`.
Carbon will automatically convert a template constant to a symbolic constant, or
any value to a runtime value:
@@ -727,6 +758,15 @@ succeeds.
> **Note:** Conversion of runtime values to other phases is provisional.
> References:
>
> - Proposal
> [#2200: Template generics](https://github.com/carbon-language/carbon-lang/pull/2200)
> - Proposal
> [#2964: Expression phase terminology](https://github.com/carbon-language/carbon-lang/pull/2964)
> - Proposal
> [#3162: Reduce ambiguity in terminology](https://github.com/carbon-language/carbon-lang/pull/3162)
## Composite types
### Tuples
@@ -848,8 +888,7 @@ Carbon.Print(a[0]);
> **TODO:** Slices
> **Note:** This is provisional, no design for arrays has been through the
> proposal process yet. See pending proposal
> [#1928: Arrays](https://github.com/carbon-language/carbon-lang/pull/1928).
> proposal process yet.
## Expressions
@@ -979,6 +1018,8 @@ patterns.
> - [Pattern matching](pattern_matching.md)
> - Proposal
> [#162: Basic Syntax](https://github.com/carbon-language/carbon-lang/pull/162)
> - Proposal
> [#2188: Pattern matching syntax and semantics](https://github.com/carbon-language/carbon-lang/pull/2188)
### Binding patterns
@@ -1009,14 +1050,20 @@ example through side effects of the destructor, copy, and move operations, but
the program's correctness must not depend on which option the Carbon
implementation chooses.
A [generic binding](#checked-and-template-parameters) uses `:!` instead of a
colon (`:`) and can only match [compile-time constant](#expression-phases), not
run-time values.
A [compile-time binding](#checked-and-template-parameters) uses `:!` instead of
a colon (`:`) and can only match [compile-time constants](#expression-phases),
not run-time values. A `template` keyword before the binding selects a template
binding instead of a symbolic binding.
The keyword `auto` may be used in place of the type in a binding pattern, as
long as the type can be deduced from the type of a value in the same
declaration.
> References:
>
> - Proposal
> [#3162: Reduce ambiguity in terminology](https://github.com/carbon-language/carbon-lang/pull/3162)
### Destructuring patterns
There are also irrefutable _destructuring patterns_, such as _tuple
@@ -1211,10 +1258,10 @@ The bindings in the parameter list default to
parameters. This binding will be implemented using a pointer, unless it is legal
to copy and copying is cheaper.
If the `var` keyword is added before the binding, then the arguments will be
copied (or moved from a temporary) to new storage, and so can be mutated in the
function body. The copy ensures that any mutations will not be visible to the
caller.
If the `var` keyword is added before the binding pattern, then the arguments
will be copied (or moved from a temporary) to new storage, and so can be mutated
in the function body. The copy ensures that any mutations will not be visible to
the caller.
Use a [pointer](#pointer-types) parameter type to represent an
[input/output parameter](<https://en.wikipedia.org/wiki/Parameter_(computer_programming)#Output_parameters>),
@@ -1395,6 +1442,8 @@ for (var name: String in names) {
> - [`for` loops](control_flow/loops.md#for)
> - Proposal
> [#353: Add C++-like `for` loops](https://github.com/carbon-language/carbon-lang/pull/353)
> - Proposal
> [#1885: ranged-based `for` for user-defined types](https://github.com/carbon-language/carbon-lang/pull/1885)
##### `break`
@@ -1765,8 +1814,9 @@ two methods `Distance` and `Offset`:
The philosophy of inheritance support in Carbon is to focus on use cases where
inheritance is a good match, and use other features for other cases. For
example, [mixins](#mixins) for implementation reuse and [generics](#generics)
for separating interface from implementation. This allows Carbon to move away
from [multiple inheritance](https://en.wikipedia.org/wiki/Multiple_inheritance),
for [separating interface from implementation](#interfaces-and-implementations).
This allows Carbon to move away from
[multiple inheritance](https://en.wikipedia.org/wiki/Multiple_inheritance),
which doesn't have as efficient of an implementation strategy.
Classes by default are
@@ -2519,7 +2569,8 @@ class ContactInfo {
>
> - [Aliases](aliases.md)
> - ["Aliasing" in "Code and name organization"](code_and_name_organization/README.md#aliasing)
> - [`alias` a name from an external impl](generics/details.md#external-impl)
> - <!-- [`alias` a name from an interface impl](generics/details.md#avoiding-name-collisions) -->
> [`alias` a name from an interface impl](generics/details.md#external-impl)
> - [`alias` a name in a named constraint](generics/details.md#named-constraints)
> - Proposal
> [#107: Code and name organization](https://github.com/carbon-language/carbon-lang/pull/107)
@@ -2536,8 +2587,9 @@ The general principle of Carbon name lookup is that we look up names in all
relevant scopes, and report an error if the name is found to refer to more than
one different entity. So Carbon requires disambiguation by adding qualifiers
instead of doing any
[shadowing](https://en.wikipedia.org/wiki/Variable_shadowing) of names. For an
example, see [the "package scope" section](#package-scope).
[shadowing](https://en.wikipedia.org/wiki/Variable_shadowing) of names.
[Member name lookup](expressions/member_access.md) follows a similar philosophy.
For an example, see [the "package scope" section](#package-scope).
Unqualified name lookup walks the semantically-enclosing scopes, not only the
lexically-enclosing ones. So when a lookup is performed within
@@ -2558,18 +2610,6 @@ fn C.G() {
}
```
[Member name lookup](expressions/member_access.md) follows a similar philosophy.
If a [checked-generic type parameter](#checked-and-template-parameters) is known
to implement multiple interfaces due to a constraint using
[`&`](#combining-constraints) or
[`where` clauses](generics/details.md#where-constraints), member name lookup
into that type will look in all of the interfaces. If it is found in multiple,
the name must be disambiguated by qualifying using compound member access
([1](expressions/member_access.md),
[2](generics/details.md#qualified-member-names-and-compound-member-access)). A
[template-generic type parameter](#checked-and-template-parameters) performs
look up into the caller's type in addition to the constraint.
Carbon also rejects cases that would be invalid if all declarations in the file,
including ones appearing later, were visible everywhere, not only after their
point of appearance:
@@ -2625,10 +2665,10 @@ like `i32` and `bool` refer to types defined within this package, based on the
## Generics
Generics allow Carbon constructs like [functions](#functions) and
[classes](#classes) to be written with compile-time parameters and apply
generically to different types using those parameters. For example, this `Min`
function has a type parameter `T` that can be any type that implements the
`Ordered` interface.
[classes](#classes) to be written with compile-time parameters to generalize
across different values of those parameters. For example, this `Min` function
has a type\* parameter `T` that can be any type that implements the `Ordered`
interface.
```carbon
fn Min[T:! Ordered](x: T, y: T) -> T {
@@ -2645,11 +2685,16 @@ Assert(Min(a, b) == 1);
Assert(Min("abc", "xyz") == "abc");
```
Since the `T` type parameter is in the deduced parameter list in square brackets
Since the `T` parameter is in the deduced parameter list in square brackets
(`[`...`]`) before the explicit parameter list in parentheses (`(`...`)`), the
value of `T` is determined from the types of the explicit arguments instead of
being passed as a separate explicit argument.
(\*) Note: `T` here may be thought of as a type parameter, but its values are
actually [facets](generics/terminology.md#facet), which are
[values usable as types](#values-usable-as-types). The `T` in this example is
not itself a type.
> References: **TODO:** Revisit
>
> - [Generics: Overview](generics/overview.md)
@@ -2659,20 +2704,21 @@ being passed as a separate explicit argument.
> [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
> - Proposal
> [#950: Generic details 6: remove facets](https://github.com/carbon-language/carbon-lang/pull/950)
> - Proposal
> [#2360: Types are values of type `type`](https://github.com/carbon-language/carbon-lang/pull/2360)
### Checked and template parameters
The `:!` indicates that the `T` parameter is generic, and therefore bound at
compile time. Generic parameters may either be _checked_ or _template_, and
default to checked.
The `:!` marks it as a compile-time binding pattern, and so `T` is a
compile-time parameter. Compile-time parameters may either be _checked_ or
_template_, and default to checked.
"Checked" here means that the body of `Min` is type checked when the function is
defined, independent of the specific type values `T` is instantiated with, and
name lookup is delegated to the constraint on `T` (`Ordered` in this case). This
type checking is equivalent to saying the function would pass type checking
given any type `T` that implements the `Ordered` interface. Subsequent calls to
`Min` only need to check that the deduced type value of `T` implements
`Ordered`.
defined, independent of the specific values `T` is instantiated with, and name
lookup is delegated to the constraint on `T` (`Ordered` in this case). This type
checking is equivalent to saying the function would pass type checking given any
type `T` that implements the `Ordered` interface. Subsequent calls to `Min` only
need to check that the deduced value of `T` implements `Ordered`.
The parameter could alternatively be declared to be a _template_ generic
parameter by prefixing with the `template` keyword, as in `template T:! type`.
@@ -2694,7 +2740,7 @@ A template parameter can still use a constraint. The `Min` example could have
been declared as:
```carbon
fn Min[template T:! Ordered](x: T, y: T) -> T {
fn TemplatedMin[template T:! Ordered](x: T, y: T) -> T {
return if x <= y then x else y;
}
```
@@ -2707,33 +2753,20 @@ binding.
One difference from C++ templates, Carbon template instantiation is not
controlled by the SFINAE rule of C++
([1](https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error),
[2](https://en.cppreference.com/w/cpp/language/sfinae)) but by explicit `if`
clauses evaluated at compile-time. The `if` clause is at the end of the
declaration, and the condition can only use constant values known at
type-checking time, including `template` parameters.
[2](https://en.cppreference.com/w/cpp/language/sfinae)) but by explicit
constraints declared in the function signature and evaluated at compile-time.
```carbon
class Array(template T:! type, template N:! i64)
if N >= 0 and N < MaxArraySize / sizeof(T);
```
Member lookup into a template type parameter is done in the actual type value
provided by the caller, _in addition_ to any constraints. This means member name
lookup and type checking for anything
[dependent](generics/terminology.md#dependent-names) on the template parameter
can't be completed until the template is instantiated with a specific concrete
type. When the constraint is just `type`, this gives semantics similar to C++
templates. Constraints can then be added incrementally, with the compiler
verifying that the semantics stay the same. Once all constraints have been
added, removing the word `template` to switch to a checked parameter is safe.
> **TODO:** The design for template constraints is still under development.
The [expression phase](#expression-phases) of a checked parameter is a symbolic
constant whereas the expression phase of a template parameter is template
constant.
constant. A binding pattern using `:!` is a _compile-time binding pattern_; more
specifically a _template binding pattern_ if it uses `template`, and a _symbolic
binding pattern_ if it does not.
Although checked generics are generally preferred, templates enable translation
of code between C++ and Carbon, and address some cases where the type checking
rigor of generics are problematic.
rigor of checked generics is problematic.
> References:
>
@@ -2743,13 +2776,15 @@ rigor of generics are problematic.
> - Question-for-leads issue
> [#949: Constrained template name lookup](https://github.com/carbon-language/carbon-lang/issues/949)
> - Proposal
> [#989: Member access expressions](https://github.com/carbon-language/carbon-lang/pull/989)
> [#2138: Checked and template generic terminology](https://github.com/carbon-language/carbon-lang/pull/2138)
> - Proposal
> [#2200: Template generics](https://github.com/carbon-language/carbon-lang/pull/2200)
### Interfaces and implementations
_Interfaces_ specify a set of requirements that a types might satisfy.
Interfaces act both as constraints on types a caller might supply and
capabilities that may be assumed of types that satisfy that constraint.
_Interfaces_ specify a set of requirements that a type might satisfy. Interfaces
act both as constraints on types a caller might supply and capabilities that may
be assumed of types that satisfy that constraint.
```carbon
interface Printable {
@@ -2759,12 +2794,17 @@ interface Printable {
}
```
An interface is kind of [facet type](generics/terminology.md#facet-type), and
the values of this type are [facets](generics/terminology.md#facet), which are
[values usable as types](#values-usable-as-types).
In addition to function requirements, interfaces can contain:
- [requirements that other interfaces be implemented](generics/details.md#interface-requiring-other-interfaces)
or
[interfaces that this interface extends](generics/details.md#interface-extension)
- [associated types](generics/details.md#associated-types) and other
- <!-- [associated facets](generics/details.md#associated-facets) -->
[associated facets](generics/details.md#associated-types) and other
[associated constants](generics/details.md#associated-constants)
- [interface defaults](generics/details.md#interface-defaults)
- [`final` interface members](generics/details.md#final-members)
@@ -2774,10 +2814,17 @@ that they do. Simply having a `Print` function with the right signature is not
sufficient.
```carbon
// Class `Text` does not implement the `Printable` interface.
class Text {
fn Print[self: Self]();
}
class Circle {
var radius: f32;
extend impl as Printable {
// This `impl` declaration establishes that `Circle` implements
// `Printable`.
impl as Printable {
fn Print[self: Self]() {
Carbon.Print("Circle with radius: {0}", self.radius);
}
@@ -2785,16 +2832,40 @@ class Circle {
}
```
In this case, `Print` is a member of `Circle`. Interfaces may also be
implemented [externally](generics/details.md#external-impl), which means the
members of the interface are not direct members of the type. Those methods may
still be called using compound member access syntax
([1](expressions/member_access.md),
[2](generics/details.md#qualified-member-names-and-compound-member-access)) to
qualify the name of the member, as in `x.(Printable.Print)()`. External
implementations don't have to be in the same library as the type definition,
subject to the orphan rule ([1](generics/details.md#impl-lookup),
[2](generics/details.md#orphan-rule)) for
In this case, `Print` is not a direct member of `Circle`, but:
- `Circle` may be passed to functions expecting a type that implements
`Printable`.
```carbon
fn GenericPrint[T:! Printable](x: T) {
// Look up into `T` delegates to `Printable`, so this
// finds `Printable.Print`:
x.Print();
}
```
- The members of `Printable` such as `Print` may be called using compound
member access syntax ([1](expressions/member_access.md),
[2](generics/details.md#qualified-member-names-and-compound-member-access))
to qualify the name of the member, as in:
```carbon
fn CirclePrint(c: Circle) {
// Succeeds, even though `c.Print()` would not.
c.(Printable.Print)();
}
```
<!-- [`extend`](generics/details.md#extend-impl) keyword... -->
To include the members of the interface as direct members of the type, use the
`extend` keyword, as in `extend impl as Printable`. This is only permitted on
`impl` declarations in the body of a class definition.
Without `extend`, implementations don't have to be in the same library as the
type definition, subject to the orphan rule
([1](generics/details.md#impl-lookup), [2](generics/details.md#orphan-rule)) for
[coherence](generics/terminology.md#coherence).
Interfaces and implementations may be
@@ -2812,16 +2883,22 @@ by replacing the definition scope in curly braces (`{`...`}`) with a semicolon.
> - Proposal
> [#624: Coherence: terminology, rationale, alternatives considered](https://github.com/carbon-language/carbon-lang/pull/624)
> - Proposal
> [#989: Member access expressions](https://github.com/carbon-language/carbon-lang/pull/989)
> - Proposal
> [#990: Generics details 8: interface default and final members](https://github.com/carbon-language/carbon-lang/pull/990)
> - Proposal
> [#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084)
> - Question-for-leads issue
> [#1132: How do we match forward declarations with their definitions?](https://github.com/carbon-language/carbon-lang/issues/1132)
> - Proposal
> [#2360: Types are values of type `type`](https://github.com/carbon-language/carbon-lang/pull/2360)
> - Proposal
> [#2760: Consistent `class` and `interface` syntax](https://github.com/carbon-language/carbon-lang/pull/2760)
### Combining constraints
A function can require calling types to implement multiple interfaces by
combining them using an ampersand (`&`):
A function can require type arguments to implement multiple interfaces (or other
facet types) by combining them using an ampersand (`&`):
```carbon
fn PrintMin[T:! Ordered & Printable](x: T, y: T) {
@@ -2851,35 +2928,84 @@ fn DrawTies[T:! Renderable & GameResult](x: T) {
> References:
>
> - [Combining interfaces by anding type-of-types](generics/details.md#combining-interfaces-by-anding-type-of-types)
> - <!-- [Combining interfaces by anding facet types](generics/details.md#combining-interfaces-by-anding-facet-types) -->
> [Combining interfaces by anding type-of-types](generics/details.md#combining-interfaces-by-anding-type-of-types)
> - Question-for-leads issue
> [#531: Combine interfaces with `+` or `&`](https://github.com/carbon-language/carbon-lang/issues/531)
> - Proposal
> [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
### Associated types
### Template name lookup
An associated type is a type member of an interface whose value is determined by
Member lookup into a template parameter is done in the actual value provided by
the caller, _in addition_ to any constraints. This means member name lookup and
type checking for anything [dependent](generics/terminology.md#dependent-names)
on the template parameter can't be completed until the template is instantiated
with a specific concrete type. When the constraint is just `type`, this gives
semantics similar to C++ templates.
```carbon
class Game {
fn Draw[self: Self]() -> bool;
impl as Renderable {
fn Draw[self: Self]();
}
}
fn TemplateDraw[template T:! type](x: T) {
// Calls `Game.Draw` when `T` is `Game`:
x.Draw();
}
fn ConstrainedTemplateDraw[template T:! Renderable](x: T) {
// ❌ Error when `T` is `Game`: Finds both `T.Draw` and
// `Renderable.Draw`, and they are different.
x.Draw();
}
fn CheckedGenericDraw[T:! Renderable](x: T) {
// Always calls `Renderable.Draw`, even when `T` is `Game`:
x.Draw();
}
```
This allows a safe transition from template to checked generics. Constraints can
be added incrementally, with the compiler verifying that the semantics stay the
same. If adding the constraint would change which function gets called, an error
is triggered, as in `ConstrainedTemplateDraw` from the example. Once all
constraints have been added, it is safe to remove the word `template` to switch
to a checked parameter.
> References:
>
> - Proposal
> [#989: Member access expressions](https://github.com/carbon-language/carbon-lang/pull/989)
> - Proposal
> [#2200: Template generics](https://github.com/carbon-language/carbon-lang/pull/2200)
### Associated constants
An associated constant is a member of an interface whose value is determined by
the implementation of that interface for a specific type. These values are set
to compile-time values in implementations, and so use the
[`:!` generic syntax](#checked-and-template-parameters) inside a
[`let` declaration](#constant-let-declarations) without an initializer. This
allows types in the signatures of functions in the interface to vary. For
[`:!` compile-time binding pattern syntax](#checked-and-template-parameters)
inside a [`let` declaration](#constant-let-declarations) without an initializer.
This allows types in the signatures of functions in the interface to vary. For
example, an interface describing a
[stack](<https://en.wikipedia.org/wiki/Stack_(abstract_data_type)>) might use an
associated type to represent the type of elements stored in the stack.
associated constant to represent the type of elements stored in the stack.
```
interface StackInterface {
let ElementType:! Movable;
fn Push[addr self: Self*](value: ElementType);
fn Pop[addr self: Self*]() -> ElementType;
fn IsEmpty[addr self: Self*]() -> bool;
fn IsEmpty[self: Self]() -> bool;
}
```
Then different types implementing `StackInterface` can specify different type
values for the `ElementType` member of the interface using a `where` clause:
Then different types implementing `StackInterface` can specify different values
for the `ElementType` member of the interface using a `where` clause:
```carbon
class IntStack {
@@ -2899,7 +3025,7 @@ class FruitStack {
> References:
>
> - [Generics: Associated types](generics/details.md#associated-types)
> - [Generics: Associated constants](generics/details.md#associated-constants)
> - Proposal
> [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)
> - Proposal
@@ -2913,9 +3039,9 @@ Many Carbon entities, not just functions, may be made generic by adding
#### Generic Classes
Classes may be defined with an optional explicit parameter list. All parameters
to a class must be generic, and so defined with `:!`, either with or without the
`template` prefix. For example, to define a stack that can hold values of any
type `T`:
to a class must be compile-time, and so defined with `:!`, either with or
without the `template` prefix. For example, to define a stack that can hold
values of any type `T`:
```carbon
class Stack(T:! type) {
@@ -2933,7 +3059,7 @@ In this example:
- `Stack` is a type parameterized by a type `T`.
- `T` may be used within the definition of `Stack` anywhere a normal type
would be used.
- `Array(T)` instantiates generic type `Array` with its parameter set to `T`.
- `Array(T)` instantiates generic type `Array` with its argument set to `T`.
- `Stack(i32)` instantiates `Stack` with `T` set to `i32`.
The values of type parameters are part of a type's value, and so may be deduced
@@ -2946,7 +3072,7 @@ fn PeekTopOfStack[T:! type](s: Stack(T)*) -> T {
return top;
}
// `int_stack` has type `Stack(i32)`, so `T` is deduced to be `i32`.
// `int_stack` has type `Stack(i32)`, so `T` is deduced to be `i32`:
PeekTopOfStack(&int_stack);
```
@@ -2981,8 +3107,8 @@ a type can have distinct implementations of `AddWith(i32)` and
`AddWith(BigInt)`.
Parameters to an interface _determine_ which implementation is selected for a
type, in contrast to [associated types](#associated-types) which are _determined
by_ the implementation of an interface for a type.
type, in contrast to [associated constants](#associated-constants) which are
_determined by_ the implementation of an interface for a type.
> References:
>
@@ -2992,7 +3118,7 @@ by_ the implementation of an interface for a type.
#### Generic implementations
An `impl` declaration may be parameterized by adding `forall [`_generic
An `impl` declaration may be parameterized by adding `forall [`_compile-time
parameter list_`]` after the `impl` keyword introducer, as in:
```carbon
@@ -3014,7 +3140,7 @@ pick which definition is selected. These rules ensure:
same implementation is always selected for a given query.
- Libraries will work together as long as they pass their separate checks.
- A generic function can assume that some impl will be successfully selected
if it can see an impl that applies, even though another more specific impl
if it can see an impl that applies, even though another more-specific impl
may be selected.
Implementations may be marked
@@ -3042,7 +3168,8 @@ Carbon generics have a number of other features, including:
- [Named constraints](generics/details.md#named-constraints) may be used to
disambiguate when combining two interfaces that have name conflicts. Named
constraints may be implemented and otherwise used in place of an interface.
constraints define facet types, and may be implemented and otherwise used in
place of an interface.
- [Template constraints](generics/details.md#named-constraints) are a kind of
named constraint that can contain structural requirements. For example, a
template constraint could match any type that has a function with a specific
@@ -3053,18 +3180,18 @@ Carbon generics have a number of other features, including:
same data representation as an existing type, so you may cast between the
two types, but can implement different interfaces or implement interfaces
differently.
- Additional requirements can be placed on the associated types of an
- Additional requirements can be placed on the associated facets of an
interface using
[`where` constraints](generics/details.md#where-constraints).
- [Implied constraints](generics/details.md#implied-constraints) allows some
- [Implied constraints](generics/details.md#implied-constraints) allow some
constraints to be deduced and omitted from a function signature.
- [Dynamic erased types](generics/details.md#runtime-type-fields) can hold any
value with a type implementing an interface, and allows the functions in
that interface to be called using
- _Planned_ [dynamic erased types](generics/details.md#runtime-type-fields)
can hold any value with a type implementing an interface, and allow the
functions in that interface to be called using
[dynamic dispatch](https://en.wikipedia.org/wiki/Dynamic_dispatch), for some
interfaces marked "`dyn`-safe". **Note:** Provisional.
- [Variadics](generics/details.md#variadic-arguments) supports variable-length
parameter lists. **Note:** Provisional.
- _Planned_ [variadics](generics/details.md#variadic-arguments) supports
variable-length parameter lists. **Note:** Provisional.
> References:
>
@@ -3079,8 +3206,8 @@ Carbon generics have a number of other features, including:
### Generic type equality and `observe` declarations
Determining whether two types must be equal in a generic context is in general
undecidable, as
Determining whether two types must be equal in a checked-generic context is in
general undecidable, as
[has been shown in Swift](https://forums.swift.org/t/swift-type-checking-is-undecidable/39024).
To make compilation fast, the Carbon compiler will limit its search to a depth
@@ -3182,7 +3309,7 @@ reference expression.
Operators that can take multiple arguments, such as function calling operator
`f(4)`, have a [variadic](generics/details.md#variadic-arguments) parameter
list.
list. **TODO: Variadics are still provisional.**
Whether and how a value supports other operations, such as being copied,
swapped, or set into an [unformed state](#unformed-state), is also determined by
@@ -3431,8 +3558,8 @@ need to be overridden for a Carbon type, that can be done with a nonmember C++
function.
Carbon interfaces with no C++ equivalent, such as
[`CommonTypeWith(U)`](#common-type), may be implemented for C++ types externally
in Carbon code. To satisfy the orphan rule
[`CommonTypeWith(U)`](#common-type), may be implemented for C++ types
out-of-line in Carbon code. To satisfy the orphan rule
([1](generics/details.md#impl-lookup), [2](generics/details.md#orphan-rule)),
each C++ library will have a corresponding Carbon wrapper library that must be
imported instead of the C++ library if the Carbon wrapper exists. **TODO:**
@@ -3513,11 +3640,12 @@ language features like checked generics in their design and implementation.
Where possible, we will also try to provide implementations of Carbon's standard
library container _interfaces_ for the relevant C++ container types so that they
can be directly used with generic Carbon code. This should allow generic code in
Carbon to work seamlessly with both Carbon and C++ containers without
performance loss or constraining the Carbon container implementations. In the
other direction, Carbon containers will satisfy C++ container requirements, so
templated C++ code can operate directly on Carbon containers as well.
can be directly used with checked-generic Carbon code. This should allow
checked-generic code in Carbon to work seamlessly with both Carbon and C++
containers without performance loss or constraining the Carbon container
implementations. In the other direction, Carbon containers will satisfy C++
container requirements, so templated C++ code can operate directly on Carbon
containers as well.
### Inheritance
@@ -3581,7 +3709,7 @@ existing languages like Rust and Swift to understand what fundamental
capabilities they ended up needing. The two components that stand out are:
- Expanded type system that includes more semantic information.
- More pervasive use of type system abstractions (typically generics).
- More pervasive use of type system abstractions (typically checked generics).
For migrating C++ code, we also need the ability to add features and migrate
code to use those new features incrementally and over time. This requires
@@ -3601,7 +3729,7 @@ just values and [pointers](#pointer-types).
Rust also shows the value of functions parameterized by lifetimes. Since
lifetimes are only used to establish safety properties of the code, there is no
reason to pay the cost of monomorphization for those parameters. So we need a
[generics system](#generics) that can reason about code before it is
[checked-generics system](#generics) that can reason about code before it is
instantiated, unlike C++ templates.
In conclusion, there are two patterns in how Carbon diverges from C++: