Просмотр исходного кода

Consistent `class` and `interface` syntax (#2760)

Update syntax of `class` and `interface` definitions to be more consistent. Constructs that add names to the class or interface from another definition are always prefixed by the `extend` keyword.

Implements the decisions in:

-   [#995: Generics external impl versus extends](https://github.com/carbon-language/carbon-lang/issues/995),
-   [#1159: adaptor versus adapter may be harder to spell than we'd like](https://github.com/carbon-language/carbon-lang/issues/1159),
-   [#2580: How should Carbon handle conditionally implemented internal interfaces](https://github.com/carbon-language/carbon-lang/issues/2580), and
-   [#2770: Terminology for internal and external implementations](https://github.com/carbon-language/carbon-lang/issues/2770).

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
josh11b 2 лет назад
Родитель
Сommit
6f8cf38329
2 измененных файлов с 841 добавлено и 2 удалено
  1. 3 2
      docs/design/lexical_conventions/words.md
  2. 838 0
      proposals/p2760.md

+ 3 - 2
docs/design/lexical_conventions/words.md

@@ -37,6 +37,7 @@ in Unicode Normalization Form C (NFC).
 The following words are interpreted as keywords:
 
 -   `abstract`
+-   `adapt`
 -   `addr`
 -   `alias`
 -   `and`
@@ -51,8 +52,7 @@ The following words are interpreted as keywords:
 -   `continue`
 -   `default`
 -   `else`
--   `extends`
--   `external`
+-   `extend`
 -   `final`
 -   `fn`
 -   `for`
@@ -77,6 +77,7 @@ The following words are interpreted as keywords:
 -   `partial`
 -   `private`
 -   `protected`
+-   `require`
 -   `return`
 -   `returned`
 -   `Self`

+ 838 - 0
proposals/p2760.md

@@ -0,0 +1,838 @@
+# Consistent `class` and `interface` syntax
+
+<!--
+Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+Exceptions. See /LICENSE for license information.
+SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+-->
+
+[Pull request](https://github.com/carbon-language/carbon-lang/pull/2760)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Abstract](#abstract)
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Details](#details)
+    -   [Class inheritance](#class-inheritance)
+    -   [Class implementing an interface](#class-implementing-an-interface)
+    -   [Class conditional implementation](#class-conditional-implementation)
+    -   [Adapters](#adapters)
+    -   [Interfaces](#interfaces)
+-   [Future work: mixins](#future-work-mixins)
+-   [Rationale](#rationale)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Use `extends` instead of `extend`](#use-extends-instead-of-extend)
+    -   [Allow interfaces to `require` another interface without writing `Self impls`](#allow-interfaces-to-require-another-interface-without-writing-self-impls)
+    -   [Allow other kinds of `where` clauses after `require`](#allow-other-kinds-of-where-clauses-after-require)
+    -   [Continue to use `impl as` for interface requirements](#continue-to-use-impl-as-for-interface-requirements)
+    -   [Continue to use `adapter` or `adaptor` instead of `adapt`](#continue-to-use-adapter-or-adaptor-instead-of-adapt)
+    -   [Use some other syntax for extending adapters](#use-some-other-syntax-for-extending-adapters)
+    -   [Continue to have some term for "external" or non-extended implementations](#continue-to-have-some-term-for-external-or-non-extended-implementations)
+    -   [More direct support for conditionally implementing internal interfaces](#more-direct-support-for-conditionally-implementing-internal-interfaces)
+    -   [Use `external` consistently instead of `extend`](#use-external-consistently-instead-of-extend)
+    -   [Use `mix` keyword for mixins](#use-mix-keyword-for-mixins)
+    -   [Allow more control over access to mixins](#allow-more-control-over-access-to-mixins)
+    -   [List base class in class declaration](#list-base-class-in-class-declaration)
+
+<!-- tocstop -->
+
+## Abstract
+
+Update syntax of `class` and `interface` definitions to be more consistent.
+Constructs that add names to the class or interface from another definition are
+always prefixed by the `extend` keyword.
+
+Implements the decisions in:
+
+-   [#995: Generics external impl versus extends](https://github.com/carbon-language/carbon-lang/issues/995),
+-   [#1159: adaptor versus adapter may be harder to spell than we'd like](https://github.com/carbon-language/carbon-lang/issues/1159),
+-   [#2580: How should Carbon handle conditionally implemented internal interfaces](https://github.com/carbon-language/carbon-lang/issues/2580),
+    and
+-   [#2770: Terminology for internal and external implementations](https://github.com/carbon-language/carbon-lang/issues/2770).
+
+## Problem
+
+Classes and adapters, prior to this proposal, use `impl` to say that an
+interface is
+[implemented internally](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/terminology.md#internal-impl),
+which means that the names that are members of the interface are included as
+names of the class. The keyword `external` is added to indicate the names should
+not be included. Interfaces and named constraints, in contrast, use `impl` to
+mean another interface is required, but its names are not included. Instead, to
+include the names, the `extends` keyword used instead of `impl`.
+
+| Include names:            | Yes       | No              |
+| ------------------------- | --------- | --------------- |
+| `class`, `adapter`        | `impl`    | `external impl` |
+| `interface`, `constraint` | `extends` | `impl`          |
+
+In the time since this syntax has been introduced, we have found `external` in
+particular easy to accidentally omit.
+
+In addition to resolving this inconsistency, it would be an advantage if readers
+of a class could quickly scan the definition to identify other places to look
+for members that contribute to the class' API.
+
+## Background
+
+These proposals that defined the syntax for these entities that are being
+modified:
+
+-   [#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553)
+    defined the syntax for classes implementing interfaces, internally or
+    externally, and the syntax for named constraints (then "structural
+    interfaces") and interfaces requiring or extending other interfaces.
+-   [#731: Generics details 2: adapters, associated types, parameterized interfaces](https://github.com/carbon-language/carbon-lang/pull/731)
+    defined the syntax for adapters and extending adapters.
+-   [#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084)
+    allowed forward declaration of implementations, so internal `impl`
+    declarations may appear outside of a class definition, and `external impl`
+    declarations may appear inside.
+-   [#777: Inheritance](https://github.com/carbon-language/carbon-lang/pull/777)
+    defined the syntax for a class to extend a base class.
+
+No proposal so far has defined how forward declarations work for classes. The
+rule used for forward `interface`, `constraint`, and `impl` declarations is that
+the declaration part of the definition is everything up to the opening `{` of
+the definition body. See
+[the forward declaration section of the Generics details design doc](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#forward-declarations-and-cyclic-references)
+added in proposal
+[#1084: Generics details 9: forward declarations](https://github.com/carbon-language/carbon-lang/pull/1084).
+
+This proposal incorporates the decisions made in these question-for-leads
+issues:
+
+-   [#995: Generics external impl versus extends](https://github.com/carbon-language/carbon-lang/issues/995),
+-   [#1159: adaptor versus adapter may be harder to spell than we'd like](https://github.com/carbon-language/carbon-lang/issues/1159),
+-   [#2580: How should Carbon handle conditionally implemented internal interfaces](https://github.com/carbon-language/carbon-lang/issues/2580),
+    and
+-   [#2770: Terminology for internal and external implementations](https://github.com/carbon-language/carbon-lang/issues/2770).
+
+Some of thinking around the resolution of #995 was documented in
+[issue #2293: reconsider syntax for internal / external implementation of interfaces](https://github.com/carbon-language/carbon-lang/issues/2293),
+which was closed as a duplicate of #995.
+
+In addition to modifying syntax from previous proposals,
+[#995](https://github.com/carbon-language/carbon-lang/issues/995) also gives a
+syntax for using a mixin in a class. Mixins are described as a use case in
+[#561: Basic classes: use cases, struct literals, struct types, and future work](https://github.com/carbon-language/carbon-lang/pull/561),
+but have not been added in any proposal. Question-for-leads issue
+[#1000: Mixins: base classes or data members?](https://github.com/carbon-language/carbon-lang/issues/1000),
+does state that a class will treat a mixin syntactically like a data member
+instead of a base class.
+
+## Proposal
+
+Any declaration that adds the names from another entity shall start with the
+(new) `extend` keyword. This includes:
+
+-   _Inheritance_: A class now indicates that it inherits from a base class
+    using an
+
+    > `extend base:` _base-class_ `;`
+
+    declaration inside the class definition. The `extend` keyword indicates that
+    the API of the base class is included.
+
+-   _Adapters_: Adapter types are now declared as a class, with an
+
+    > [ `extend` ] `adapt` _adapted-class_ `;`
+
+    declaration inside the definition, as an alternative to a base class
+    declaration. The optional `extend` keyword controls whether the API of the
+    adapted class is included.
+
+-   _Implementations_: Internal implementations are marked with the `extend`
+    keyword on the declaration inside the class. Only the declaration inside the
+    class, which is required for internal implementations, uses the `extend`
+    keyword. External implementations are not marked.
+
+    > [ `extend` ] `impl` ...
+
+-   _Interfaces_: The `extends` declaration in an interface definition is
+    replaced by an `extend` declaration, with no change except removing the `s`
+    from the end of the keyword. Other interface requirements are now written
+    using a `require` declaration, with a constraint that matches a `where`
+    clause. This means
+
+    > `impl as` _required-interface_ `;`
+
+    will now be written as
+
+    > `require Self impls` _required-interface_ `;`
+
+    and
+
+    > `impl` _type-expression_ `as` _required-interface_ `;`
+
+    will now be written as
+
+    > `require` _type-expression_ `impls` _required-interface_ `;`
+
+    For now, only the `impls` forms of `where` clauses are permitted after
+    `require`.
+
+In summary:
+
+| Before                          | After                                   |
+| ------------------------------- | --------------------------------------- |
+| `class D extends B { ... }`     | `class D { extend base: B; ... }`       |
+| `external impl C as Sub;`       | `impl C as Sub;`                        |
+| `class C { impl as Sortable; }` | `class C { extend impl as Sortable; }`  |
+| `adapter A for C { ... }`       | `class A { adapt C; ... }`              |
+| `adapter A extends C { ... }`   | `class A { extend adapt C; ... }`       |
+| `interface I { impl as J; }`    | `interface I { require Self impls J; }` |
+| `interface I { impl T as J; }`  | `interface I { require T impls J; }`    |
+| `interface I { extends J; }`    | `interface I { extend J; }`             |
+
+None of `adapter`, `extends`, `external` will continue to be keywords. To match
+these changes, "internal implementations" will now be referred to as "extended
+implementations," and we will no longer use "external" to refer to
+implementations.
+
+In addition, we drop the syntax for conditionally implemented internal
+interfaces. Instead, an external interface implementation can be combined with
+aliases to the members of the interface.
+
+## Details
+
+### Class inheritance
+
+What was previously written:
+
+```
+base class B;
+class D extends B;
+class D extends B {
+  ...
+}
+```
+
+is now written:
+
+```
+base class B;
+class D;
+class D {
+  extend base: B;
+  ...
+}
+```
+
+An extend base class declaration may appear in the body of a class definition,
+and has this form:
+
+> `extend` `base` `:` _type-expression_ `;`
+
+The `extend base: B;` declaration must appear before any other data member
+declaration, including any [mixin declaration](#future-work-mixins), once those
+are added. This reflects both the importance of the information, and the fact
+that the base subobject appears first in the memory layout of objects.
+
+Note that `base` is already a keyword, for example used in `base class`
+declarations. The colon in `base: B` is to indicate that `base` acts like a data
+member for
+[purposes of initialization](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/classes.md#constructors).
+
+This makes the part of a class definition that is used in forward declarations
+be exactly the part before the curly braces (`{`...`}`). Before this proposal,
+class forward declarations would exclude the `extends` clause from the the first
+line of the class definition. This change makes classes consistent with other
+entities that may be forward declared.
+
+### Class implementing an interface
+
+What was previously written:
+
+```
+interface Sortable;
+interface Add;
+interface Sub;
+class C;
+
+// Forward declaration says whether external.
+impl C as Sortable;
+external impl C as Add;
+
+class C {
+  // Internal impl contributes to the API.
+  impl as Sortable;
+
+  // External impl of an operator.
+  external impl as Add;
+}
+
+// External impl of an operator.
+external impl C as Sub;
+
+// Definition of `impl` declared earlier.
+impl C as Sortable { ... }
+external impl C as Add { ... }
+```
+
+is now written:
+
+```
+interface Sortable;
+interface Add;
+interface Sub;
+class C;
+
+// Forward declaration same whether extended or not.
+impl C as Sortable;
+impl C as Add;
+
+class C {
+  // Extended impl contributes to the API.
+  extend impl as Sortable;
+
+  // (Non-extended) Impl of an operator.
+  impl as Add;
+}
+
+// (Non-extended) Impl of an operator.
+impl C as Sub;
+
+// Definition of `impl` declared earlier.
+impl C as Sortable { ... }
+impl C as Add { ... }
+```
+
+Whether an interface is extended or not is now only reflected in its declaration
+inside the class body, not in any declaration or definition outside.
+
+An `impl` declaration, with this proposal, must have one of these two forms:
+
+-   Without an `extend` keyword prefix, used for non-extended `impl`
+    declarations and for all `impl` declarations outside of a class body:
+
+    <!-- prettier-ignore -->
+    > `impl` [`forall` `[` _deduced-parameters_ `]`] [_type-expression_] `as`
+    > _facet-type-expression_ (`;`|`{` _impl-body_ `}`)
+
+    The _type-expression_ is required outside of a class body, otherwise it
+    defaults to `Self`.
+
+-   With an `extend` keyword prefix, to indicate this implementation is
+    extended, only in a class body:
+
+    > `extend` `impl` `as` _facet-type-expression_ (`;`|`{` _impl-body_ `}`)
+
+    Note that this form does not allow either a `forall` clause nor a
+    _type-expression_ before the `as` keyword. This reflects the restriction
+    that
+    [wildcard `impl` declarations must never be extended (formerly: "always be external")](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#wildcard-impl-declarations),
+    and that this proposal removes support for
+    [extended (formerly "internal") conditional implementation](#class-conditional-implementation).
+
+### Class conditional implementation
+
+We remove direct support for conditionally implemented extended (formerly
+"internal") interfaces, called
+[conditional conformance](https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/generics/details.md#conditional-conformance).
+We can work around this restriction by using an non-extended interface
+implementation and aliases to the members of the interface.
+
+What was previously written:
+
+```
+interface Printable {
+  fn Print[self: Self]();
+}
+
+class Vector(T:! type) {
+  // ...
+
+  impl forall [U:! Printable] Vector(U) as Printable {
+    fn Print[self: Self]();
+  }
+}
+```
+
+is now written:
+
+```
+interface Printable {
+  fn Print[self: Self]();
+}
+
+class Vector(T:! type) {
+  // ...
+  alias Print = Printable.Print;
+}
+
+impl forall [U:! Printable] Vector(U) as Printable {
+  fn Print[self: Self]();
+}
+```
+
+The way this works is that `Vector.Print` is equivalent to
+`Vector.(Printable.Print)`, which may or may not be defined. The name
+`Vector.Print` can no longer be conditional, and the meaning of that name is
+fixed. However, the implementation of `Printable` for `Vector(T)` may not exist
+for some types `T`.
+
+### Adapters
+
+What was previously written:
+
+```
+class C;
+// Forward declarations of adapters.
+adapter A for C;
+adapter E extends C;
+
+// Definitions of an adapter.
+adapter A for C {
+  ...
+}
+// Definition of an extending adapter.
+adapter E extends C {
+  ...
+}
+```
+
+is now written:
+
+```
+class C;
+// Forward declarations of adapters.
+class A;
+class E;
+
+// Definitions of an adapter.
+class A {
+  adapt C;
+  ...
+}
+// Definition of an extending adapter.
+class E {
+  extend adapt C;
+  ...
+}
+```
+
+Note:
+
+-   Adapters are now a special case of classes, not a distinct top-level
+    declaration.
+-   Classes with `adapt` still must not contain anything that was previously
+    forbidden for adapters: no fields, no base class, no virtual methods, no
+    implementations of virtual methods, and so on.
+-   The `adapt` declaration must appear before
+    [mixin declarations](#future-work-mixins), if any.
+-   The syntax for an `adapt` declaration inside a class body is:
+
+    > [`extend`] `adapt` _type-expression_ `;`
+
+### Interfaces
+
+What was previously written:
+
+```
+interface A { let T:! Type; }
+interface B { let U:! Type; }
+interface C(V:! Type) { }
+
+interface I {
+  // `A`'s interface is incorporated into `I`:
+  extends A where .T = i32;
+
+  // No impact on `I`s interface, but an
+  // implementation must exist:
+  impl as B where .U = i32;
+
+  // Implementation must exist on another type:
+  impl i32 as C(Self);
+}
+```
+
+is now written:
+
+```
+interface A { let T:! Type; }
+interface B { let U:! Type; }
+interface C(V:! Type) { }
+
+interface I {
+  // `A`'s interface is incorporated into `I`:
+  extend A where .T = i32;
+
+  // No impact on `I`s interface, but an
+  // implementation must exist:
+  require Self impls B where .U = i32;
+
+  // Implementation must exist on another type:
+  require i32 impls C(Self);
+}
+```
+
+Notes:
+
+-   The same change applies to named constraints, and is intended to be used in
+    the future for named predicates used as template constraints.
+-   One syntax for constraints in either `where` clauses or `require`
+    declarations.
+-   Want to open up the syntax to expressing more general constraints.
+-   Syntax for a `require` declaration in an interface or named constraint:
+
+    > `require` _type-expression_ `impls` _facet-type-expression_ `;`
+
+    As
+    [with `impl`...`as` declarations before](/docs/design/generics/details.md#interface-requiring-other-interfaces-revisited),
+    a `require` declaration must use `Self`, either to the left or right of
+    `impls`. Note that `require` only supports this subset of `where` clause
+    expressions. Adding other kinds of constraints is future work.
+
+-   Syntax for an `extend` declaration in an interface or named constraint:
+
+    > `extend` _facet-type-expression_ `;`
+
+## Future work: mixins
+
+Mixins have not been defined in a proposal so far. However, part of the process
+of resolving
+[issue #995](https://github.com/carbon-language/carbon-lang/issues/995) was
+deciding on a syntax for including a mixin in a class. This was done in order to
+make sure that class declarations that included names from another entity were
+treated consistently, for example always starting with the `extend` keyword.
+
+```
+// Mixin declarations and definitions are
+// outside the scope of this proposal.
+mixin M1;
+mixin M2;
+
+class C {
+  // Mixing in mixin M1
+  extend m: M1;
+
+  // Mixing in mixin M2. This member is not named.
+  // Initialized using `M2.MakeDefault()`.
+  extend _: M2 = M2.MakeDefault();
+
+  // Alternative to the above `M2` that uses a
+  // private name instead of no name:
+  extend private m2: M2;
+}
+```
+
+The declaration that a class uses a mixin is called a "mix" declaration. The
+syntax of a mix declaration is:
+
+<!-- prettier-ignore -->
+> `extend` [`private`|`protected`] (`_`|_id_) `:` _mixin-expression_ [`=`
+> _initializer-expression_] `;`
+
+The _id_ part of the mix declaration defines the name assigned to that mixin
+subobject. This name is may be used to access members of the mixin and to
+initialize the mixin in a constructor for the class. The optional `private` or
+`protected` access specifier controls the access to this name.
+
+With this proposal, base class declarations appear in the body of the class
+definition, like data members, so decision of whether mixins are more like base
+classes or data members of issue
+[#1000: Mixins: base classes or data members?](https://github.com/carbon-language/carbon-lang/issues/1000)
+is less significant. Like base classes, the mix declaration syntax begins with
+`extend`. Like data members, a class may have multiple mix declarations and they
+may be intermixed with field declarations. The layout of the memory of an object
+reflects the order of the declarations in the class body, defining the order of
+the mixin and field subobjects.
+
+## Rationale
+
+The main reason for the new syntax is consistency and simplification:
+
+-   The use of the `extend` keyword is the consistent way to mark what other
+    entities are consulted during name lookup.
+-   The `class` declaration is simplified by moving more into the definition
+    body.
+-   Making adapters a kind of class removes a kind of top-level declaration, a
+    simplification, and matches how base classes are declared, a consistency.
+-   Dropping the class conditional implementation is a simplification.
+
+These consistency and simplification improvements help:
+
+-   ease the implementation of
+    [language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem)
+    by reducing the size of the language, and providing regularities
+    implementations can use to reuse code or more easily identify relevant parts
+    of the code for queries;
+-   make Carbon code
+    [easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write).
+-   teaching the language, since there is less to learn.
+
+## Alternatives considered
+
+### Use `extends` instead of `extend`
+
+Keyword `extend` was chosen over `extends` to parallel `impl`, a declaration,
+instead of `impls`, a binary predicate, decided in
+[issue #2495](https://github.com/carbon-language/carbon-lang/issues/2495) and
+accepted in
+[proposal #2483](https://github.com/carbon-language/carbon-lang/pull/2483).
+
+We chose to use `require` instead of `requires` and `adapt` instead of `adapts`
+for the same consistency.
+
+### Allow interfaces to `require` another interface without writing `Self impls`
+
+We
+[considered](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1418387971)
+allowing `interface I { require J; }` as a short-hand for
+`interface I { require Self impls J; }`. This is something we would consider
+adding in the future based on experience with the current approach, but for now
+we wanted to maintain consistency with the constraint syntax of `where` clauses.
+
+This decision and rationale was described in
+[this comment in #995](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1416659207).
+
+### Allow other kinds of `where` clauses after `require`
+
+The decision on
+[#995](https://github.com/carbon-language/carbon-lang/issues/995), see
+[1](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1439336141)
+and
+[2](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1496781087),
+called for the same constraint syntax after `require` as we are using after
+`where`. This proposal _only_ allows `impls` clauses after `require`, since
+there were concerns about the other kinds of clauses:
+
+-   We had questions about what syntax to use to refer to members of the
+    interface, such as associated types, to constrain them. Must they start with
+    `Self.` or `.`? See
+    [this comment thread on #2760](https://github.com/carbon-language/carbon-lang/pull/2760#discussion_r1213789364).
+-   Modifying the constraints on an associated type after the declaration for
+    that associated type was not something we clearly wanted to allow. Allowing
+    that would mean having to read the whole interface definition body to
+    understand a single member.
+-   It was unclear if rewrite constraints (using `=` instead of `==`), would be
+    allowed in a `require` declaration, and if they were, whether they would be
+    changed into equality constraints (as if they were declared using `==`). See
+    [this comment on #2760](https://github.com/carbon-language/carbon-lang/pull/2760#discussion_r1213791304).
+-   It would have provided more different ways of declaring equivalent
+    interfaces. This concern was raised
+    [in this comment on #2760](https://github.com/carbon-language/carbon-lang/pull/2760#discussion_r1214571215).
+
+For now, we only needed to replace the existing uses of `impl as` constraints,
+which had none of these concerns. We did not want to block this proposal, so we
+made sure the `require` clauses were consistent with that _subset_ of `where`
+clauses.
+
+### Continue to use `impl as` for interface requirements
+
+There were a few reasons motivating the change to use the new `require`
+declarations in interfaces and named constraints, instead of using `impl as` to
+match how a type could satisfy that requirement. These mostly came down to some
+observed breaks in the parallel structure between the requirement in interfaces
+and the satisfaction of that requirement in types.
+
+-   Whether an interface `I` extends or just requires another interface `J` is
+    independent of whether a type implementing `I` extends or just implements
+    `J`.
+-   If `R` requires interface `I`, the implementation of `R` for a type won't
+    have the implementation of `I` as a nested sub-block.
+-   With the change in
+    [#2173: Associated constant assignment versus equality](https://github.com/carbon-language/carbon-lang/pull/2173),
+    the behavior of `impl as` in interfaces is different from in classes with
+    respect to rewrites of associated types, motivating a change to make those
+    look more different.
+
+Furthermore, we had a desire to be able to express the full range of constraints
+in `where` clauses in named constraints, and we wanted the transformation from a
+`where` clause to a named constraint to be straightforward. We also wanted the
+syntax for constraints to be the same between interfaces and named constraints,
+at least for all constraints that were allowed in both.
+
+This was discussed in
+[#generics-and-templates on 2023-01-30](https://discord.com/channels/655572317891461132/941071822756143115/1069691751968817283)
+and in
+[issue #995](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1412478644).
+
+### Continue to use `adapter` or `adaptor` instead of `adapt`
+
+We didn't want to allow both `adapter` and `adaptor`, since that adds complexity
+for readers and tooling, but neither seemed clearly dominant enough in usage to
+pick one over the other. By moving the declaration into the body of the class
+definition, we were able to switch from the noun form to the verb form of
+`adapt`, which doesn't have an alternate form in common usage. See
+[#1159: adaptor versus adapter may be harder to spell than we'd like](https://github.com/carbon-language/carbon-lang/issues/1159)
+for the discussion.
+
+We also considered using `adapts` in a class declaration, as in
+`class PlayableSong adapts Song { ... }`, see
+[this comment in #1159](https://github.com/carbon-language/carbon-lang/issues/1159#issuecomment-1316669416).
+This would have also worked, but was not consistent with our resolution of
+[#995: Generics external impl versus extends](https://github.com/carbon-language/carbon-lang/issues/995).
+
+### Use some other syntax for extending adapters
+
+In the
+[open discussion on 2023-02-27](https://docs.google.com/document/d/1gnJBTfY81fZYvI_QXjwKk1uQHYBNHGqRLI2BS_cYYNQ/edit?resourcekey=0-ql1Q1WvTcDvhycf8LbA9DQ#heading=h.9steyq834zuq),
+we discussed some alternatives to `extend adapt` _adapted-class_ `;`:
+
+-   Adding `and` to make it read more like fluent English:
+
+    > `extend and adapt` _adapted-class_ `;`
+
+    However, this felt arbitrary and not compositional.
+
+-   Make the extending and adapting be separate declarations:
+
+    > `extend` _adapted-class_ `;` <br> `adapt` _adapted-class_ `;`
+
+    This felt too repetitive.
+
+-   Make the only way to make an extending adapter be trying to inherit from a
+    final base class
+
+    > `extend base:` _adapted-class_ `;`
+
+    However, this meant using the same syntax for two different things that
+    could only be distinguished by looking at the declaration of the adapted
+    class, which could be far away. It also would have meant making an extending
+    adapter of a non-final class much more cumbersome.
+
+Ultimately, we decided that `extend adapt` would be the most compositional way
+of combining `extend` and `adapt`, so that is what users would expect. Reading
+like natural English was not considered essential.
+
+### Continue to have some term for "external" or non-extended implementations
+
+The fact that there were some different rules for external implementations was
+brought up in
+[this post in #2770](https://github.com/carbon-language/carbon-lang/issues/2770#issuecomment-1509288478).
+However,
+[this reply](https://github.com/carbon-language/carbon-lang/issues/2770#issuecomment-1515522070)
+pointed out those rules could be clearly stated in terms of where you are
+allowed to write `extend`. That same post made the convincing argument that to
+get the maximum benefit of the decision on
+[#995](https://github.com/carbon-language/carbon-lang/issues/995), we should
+treat `extend` and `impl` as separate orthogonal concepts as much as possible.
+
+### More direct support for conditionally implementing internal interfaces
+
+We considered two different ways of more directly supporting conditionally
+extending a class by an interface:
+
+-   Prior to this proposal, both name lookup and the implementation were
+    conditional on the same condition. This has the disadvantage of entangling
+    the concerns of name lookup and implementation, and was considered a complex
+    and difficult model.
+-   We also considered fully separating these features, and allowing a type to
+    separately extend its API with an interface and then only conditionally
+    implement that interface. This would allow name lookup to succeed
+    unconditionally, but in cases where the names were in fact not implemented
+    it would produce an error.
+
+Both of these approaches would have required some support for expressing this in
+the new syntax. None of the syntactic approaches we considered were found to be
+satisfactory. By making name lookup never conditional, it made it much easier to
+have a consistent marker for declarations that extended name lookup.
+
+Ultimately, the alternative of not having a dedicated syntax to support this
+case seemed the simplest in the short term, given the workaround of conditional
+external (non-extending) implementation paired with aliases that provide the
+name lookup, unconditionally. We can always add dedicated syntax later, given
+sufficient motivating information.
+
+The options were considered in
+[#2580: How should Carbon handle conditionally implemented internal interfaces](https://github.com/carbon-language/carbon-lang/issues/2580).
+
+### Use `external` consistently instead of `extend`
+
+We considered making "extending name lookup" the default and overriding that
+default with the `external` keyword. The argument for this option rested on it
+being more convenient to express conditional internal implementation, and wasn't
+seen as attractive once that feature was removed. In the discussion, we
+generally preferred marking additional places to consult in name lookup since
+that was something we expected readers of the code to want to specifically look
+for.
+
+This option was proposed as the third option in the
+[original #995 question](https://github.com/carbon-language/carbon-lang/issues/995#issue-1085174338),
+and was considered in
+[this comment](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1006096692).
+
+### Use `mix` keyword for mixins
+
+We considered a variety of different syntax options for using a mixin for a type
+in
+[this comment on #995](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1315948818).
+Many of them used the `mix` keyword, but we ultimately decided that `mix` was
+redundant with saying `extend`, which we wanted to be included with all
+constructs extending the type's API by another entity.
+
+### Allow more control over access to mixins
+
+There were three different aspects of mixins that we considered giving control
+over access:
+
+-   the inclusion of names exported by the mixin into the mixer class,
+-   the ability to cast between the mixin and the mixer class types, and
+-   the ability to use the name of the mixin given by the mixer class to access
+    members of the mixin.
+
+This was particularly relevant when we were considering separate declarations
+for declaring the mixin member and the API extension
+([1](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1315948818),
+[2](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1317598076)).
+
+This approach had the problem that the common case for mixins was extending the
+API, which would not have been the default. The only examples we had where the
+mixer class would not want to include the names exported by the mixin were cases
+where the mixin had nothing to export. This led to
+[the position](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1325746398)
+that the mixin would control which of its member would be included into the
+mixer class' API -- that is the mixin would "inject" members rather than
+"export" them and leave it up to the mixer class to import them.
+
+We had concerns that there might be name conflicts, but we thought those might
+be handled by some other mechanism. This is being considered in
+question-for-leads issue
+[#2745: Name conflicts beyond inheritance](https://github.com/carbon-language/carbon-lang/issues/2745).
+
+We wanted mixin member names to behave consistently like other class member
+names, and so default to public but can have a `private` modifier to make
+private, following
+[#665: `private` vs `public` _syntax_ strategy, as well as other visibility tools like `external`/`api`/etc.](https://github.com/carbon-language/carbon-lang/issues/665).
+We decided to put the `private` keyword _between_ the `extend` keyword and the
+member name for two reasons:
+
+-   to make it easier to scan for all uses of `extend` in a class, and
+-   to make it clearer that the `private` access control only applies to the
+    member name, not what the `extend` controls.
+
+We did not see a use case for controlling the ability to cast between the mixin
+and the mixer class types separately from being able to access the name the
+mixin member of the mixin class. This was consistent with our desire to limit
+declarations to a single access control specifier per declaration, see
+[this update in #995](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1322892195).
+
+### List base class in class declaration
+
+By moving the base class into the class body, we accomplished three things:
+
+-   made forward declarations shorter,
+-   made it possible to inherit from a type declared inside the body of the
+    class definition, and
+-   allowed greater consistency, all API extensions are now declarations in the
+    body of the class definition starting with `extend`.
+
+This was decided in
+[this comment on #995](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1317598076).
+
+This left open the question of what keyword introducer to use in base class
+declarations, since using `base` would cause an ambiguity with declaring a
+member class that could be extended, as considered in
+[this comment](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1320614313).
+Ultimately we avoided this problem by requiring base class declarations to
+always begin with `extend`, not support any form of private or protected
+inheritance (see
+[this comment](https://github.com/carbon-language/carbon-lang/issues/995#issuecomment-1325746398)),
+and not support any combination of an `extend` declaration with a member class
+declaration.