فهرست منبع

Inheritance (#777)

This proposal adds inheritance to classes, following this syntax:
```
// Abstract classes may not be instantiated, but
// may have abstract methods and be extended.
abstract class AbstractBaseClass {
  virtual fn CanBeOverridden[me: Self]() -> i32 {
    return me.data;
  }
  abstract fn PureVirtual[me: Self]() -> i32;
  fn Create(data: i32) -> partial Self {
    return {.data = data};
  }
  protected var data: i32;
}

// Classes are final by default
class FinalClass extends AbstractBaseClass {
  impl fn PureVirtual[me: Self]() -> i32 {
    return me.x;
  }
  fn Create(data: i32) -> Self {
    return {.base = AbstractBaseClass.Create(data), .x = 2 * data};
  }
  private var x: i32;
}

// Can be instantiated and extended
base class ExtensibleClass {
  // May optionally use partial types in factory functions
  protected fn CreateAsBase(data: i32) -> partial Self { ... }
  fn Create(data: i32) -> Self { ... }
}
```

Co-authored-by: Chandler Carruth <chandlerc@gmail.com>
Co-authored-by: Richard Smith <richard@metafoo.co.uk>
josh11b 4 سال پیش
والد
کامیت
3610325c38
3فایلهای تغییر یافته به همراه1131 افزوده شده و 66 حذف شده
  1. 632 66
      docs/design/classes.md
  2. 1 0
      proposals/README.md
  3. 498 0
      proposals/p0777.md

+ 632 - 66
docs/design/classes.md

@@ -43,7 +43,20 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     -   [Member type](#member-type)
     -   [Let](#let)
     -   [Alias](#alias)
-    -   [Private access](#private-access)
+    -   [Inheritance](#inheritance)
+        -   [Virtual methods](#virtual-methods)
+            -   [Virtual override keywords](#virtual-override-keywords)
+        -   [Subtyping](#subtyping)
+        -   [Constructors](#constructors)
+            -   [Partial facet](#partial-facet)
+            -   [Usage](#usage)
+        -   [Assignment with inheritance](#assignment-with-inheritance)
+    -   [Access control](#access-control)
+        -   [Private access](#private-access)
+        -   [Protected access](#protected-access)
+        -   [Friends](#friends)
+        -   [Test friendship](#test-friendship)
+        -   [Access control for construction](#access-control-for-construction)
 -   [Future work](#future-work)
     -   [Struct literal shortcut](#struct-literal-shortcut)
     -   [Optional named parameters](#optional-named-parameters)
@@ -51,10 +64,13 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
         -   [Destructuring in pattern matching](#destructuring-in-pattern-matching)
         -   [Discussion](#discussion)
     -   [Operator overloading](#operator-overloading)
-    -   [Inheritance](#inheritance)
-    -   [C++ abstract base classes interoperating with object-safe interfaces](#c-abstract-base-classes-interoperating-with-object-safe-interfaces)
+    -   [Inheritance](#inheritance-1)
+        -   [Destructors](#destructors)
+        -   [C++ abstract base classes interoperating with object-safe interfaces](#c-abstract-base-classes-interoperating-with-object-safe-interfaces)
+        -   [Overloaded methods](#overloaded-methods)
+        -   [Interop with C++ inheritance](#interop-with-c-inheritance)
+            -   [Virtual base classes](#virtual-base-classes)
     -   [Mixins](#mixins-1)
-    -   [Non-virtual inheritance](#non-virtual-inheritance)
     -   [Memory layout](#memory-layout)
     -   [No `static` variables](#no-static-variables)
     -   [Computed properties](#computed-properties)
@@ -1022,45 +1038,367 @@ Assert(&sp1.first == &sp1.key);
 **Future work:** This needs to be connected to the broader design of aliases,
 once that lands.
 
-### Private access
+### Inheritance
 
-By default, all members of a class are fully publicly accessible. Access can be
-restricted by adding a keyword, called an
-[access modifier](https://en.wikipedia.org/wiki/Access_modifiers), prior to the
-declaration. Access modifiers are how Carbon supports
-[encapsulation](#encapsulated-types).
+Carbon supports
+[inheritance](<https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)>)
+using a
+[class hierarchy](<https://en.wikipedia.org/wiki/Class_(computer_programming)#Hierarchical>),
+on an opt-in basis. Classes by default are
+_[final](https://en.wikipedia.org/wiki/Inheritance_(object-oriented*programming)#Non-subclassable_classes)*,
+which means they may not be extended. To declare a class as allowing extension,
+use either the `base class` or `abstract class` introducer:
 
-```carbon
-class Point {
-  fn Distance[me: Self]() -> f32;
-  // These are only accessible to members of `Point`.
-  private var x: f32;
-  private var y: f32;
+```
+base class MyBaseClass { ... }
+```
+
+A _base class_ may be _extended_ to get a _derived class_:
+
+```
+base class MiddleDerived extends MyBaseClass { ... }
+class FinalDerived extends MiddleDerived { ... }
+// ❌ Forbidden: class Illegal extends FinalDerived { ... }
+```
+
+An _[abstract class](https://en.wikipedia.org/wiki/Abstract_type)_ or _abstract
+base class_ is a base class that may not be instantiated.
+
+```
+abstract class MyAbstractClass { ... }
+// ❌ Forbidden: var a: MyAbstractClass = ...;
+```
+
+**Future work:** For now, the Carbon design only supports single inheritance. In
+the future, Carbon will support multiple inheritance with limitations on all
+base classes except the one listed first.
+
+**Terminology:** We say `MiddleDerived` and `FinalDerived` are _derived
+classes_, transitively extending or _derived from_ `MyBaseClass`. Similarly
+`FinalDerived` is derived from or extends `MiddleDerived`. `MiddleDerived` is
+`FinalDerived`'s _immediate base class_, and both `MiddleDerived` and
+`MyBaseClass` are base classes of `FinalDerived`. Base classes that are not
+abstract are called _extensible classes_.
+
+A derived class has all the members of the class it extends, including data
+members and methods, though it may not be able to access them if they were
+declared `private`.
+
+#### Virtual methods
+
+A base class may define
+[virtual methods](https://en.wikipedia.org/wiki/Virtual_function). These are
+methods whose implementation may be overridden in a derived class.
+
+Only methods defined in the scope of the class definition may be virtual, not
+any defined in
+[external interface impls](/docs/design/generics/details.md#external-impl).
+Interface methods may be implemented using virtual methods when the
+[impl is internal](/docs/design/generics/details.md#implementing-interfaces),
+and calls to those methods by way of the interface will do virtual dispatch just
+like a direct call to the method does.
+
+[Class functions](#class-functions) may not be declared virtual.
+
+##### Virtual override keywords
+
+A method is declared as virtual by using a _virtual override keyword_ in its
+declaration before `fn`.
+
+```
+base class MyBaseClass {
+  virtual fn Overridable[me: Self]() -> i32 { return 7; }
 }
 ```
 
-As in C++, `private` means only accessible to members of the class.
+This matches C++, and makes it relatively easy for authors of derived classes to
+find the functions that can be overridden.
+
+If no keyword is specified, the default for methods is that they are
+_non-virtual_. This means:
+
+-   they can't override methods in bases of this class;
+-   they can't be overridden in derived classes; and
+-   they have an implementation in the current class, and that implementation
+    must work for all derived classes.
+
+There are three virtual override keywords:
+
+-   `virtual` - This marks a method as not present in bases of this class and
+    having an implementation in this class. That implementation may be
+    overridden in derived classes.
+-   `abstract` - This marks a method that must be overridden in a derived class
+    since it has no implementation in this class. This is short for "abstract
+    virtual" but is called
+    ["pure virtual" in C++](https://en.wikipedia.org/wiki/Virtual_function#Abstract_classes_and_pure_virtual_functions).
+    Only abstract classes may have unimplemented abstract methods.
+-   `impl` - This marks a method that overrides a method marked `virtual` or
+    `abstract` in the base class with an implementation specific to -- and
+    defined within -- this class. The method is still virtual and may be
+    overridden again in subsequent derived classes if this is a base class. See
+    [method overriding in Wikipedia](https://en.wikipedia.org/wiki/Method_overriding).
+    Requiring a keyword when overriding allows the compiler to diagnose when the
+    derived class accidentally uses the wrong signature or spelling and so
+    doesn't match the base class. We intentionally use the same keyword here as
+    for implementing interfaces, to emphasize that they are similar operations.
+
+| Keyword on<br />method in `C` | Allowed in<br />`abstract class C` | Allowed in<br />`base class C` | Allowed in<br />final `class C` | in `B` where<br />`C extends B`                          | in `D` where<br />`D extends C`                                                  |
+| ----------------------------- | ---------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
+| `virtual`                     | ✅                                 | ✅                             | ❌                              | _not present_                                            | `abstract`<br />`impl`<br />_not mentioned_                                      |
+| `abstract`                    | ✅                                 | ❌                             | ❌                              | _not present_<br />`virtual`<br />`abstract`<br />`impl` | `abstract`<br />`impl`<br />_may not be<br />mentioned if<br />`D` is not final_ |
+| `impl`                        | ✅                                 | ✅                             | ✅                              | `virtual`<br />`abstract`<br />`impl`                    | `abstract`<br />`impl`                                                           |
+
+#### Subtyping
+
+A pointer to a base class, like `MyBaseClass*` is actually considered to be a
+pointer to that type or any derived class, like `MiddleDerived` or
+`FinalDerived`. This means that a `FinalDerived*` value may be implicitly cast
+to type `MiddleDerived*` or `MyBaseClass*`.
+
+This is accomplished by making the data layout of a type extending `MyBaseClass`
+have `MyBaseClass` as a prefix. In addition, the first class in the inheritance
+chain with a virtual method will include a virtual pointer, or _vptr_, pointing
+to a [virtual method table](https://en.wikipedia.org/wiki/Virtual_method_table),
+or _vtable_. Any calls to virtual methods will perform
+[dynamic dispatch](https://en.wikipedia.org/wiki/Dynamic_dispatch) by calling
+the method using the function pointer in the vtable, to get the overridden
+implementation from the most derived class that implements the method.
+
+Since a final class may not be extended, the compiler can bypass the vtable and
+use [static dispatch](https://en.wikipedia.org/wiki/Static_dispatch). In
+general, you can use a combination of an abstract base class and a final class
+instead of an extensible class if you need to distinguish between exactly a type
+and possibly a subtype.
 
-**Future work:** We will add support for `protected` access when inheritance is
-added to this design. We will also define a convenient way for tests that belong
-to the same library to get access to private members.
+```
+base class Extensible { ... }
 
-**Future work:** `private` will give the member internal linkage unless it needs
-to be external because it is used in an inline method or template. We may in the
-future
-[add a way to specify internal linkage explicitly](/proposals/p0722.md#specifying-linkage-as-part-of-the-access-modifier).
+// Can be replaced by:
 
-**Open questions:** Using `private` to mean "restricted to this class" matches
-C++. Other languages support restricting to different scopes:
+abstract class ExtensibleBase { ... }
+class ExactlyExtensible extends ExtensibleBase { ... }
+```
 
--   Swift supports "restrict to this module" and "restrict to this file".
--   Rust supports "restrict to this module and any children of this module", as
-    well as "restrict to this crate", "restrict to parent module", and "restrict
-    to a specific ancestor module".
+#### Constructors
+
+Like for classes without inheritance, constructors for a derived class are
+ordinary functions that return an instance of the derived class. Generally
+constructor functions should return the constructed value without copying, as in
+proposal
+[#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257).
+This means either
+[creating the object in the return statement itself](/proposals/p0257.md#function-returns-and-initialization),
+or in
+[a `returned var` declaration](/proposals/p0257.md#declared-returned-variable).
+As before, instances can be created using by casting a struct value into the
+class type, this time with a `.base` member to initialize the members of the
+immediate base type.
 
-**Comparison to other languages:** C++, Rust, and Swift all make class members
-private by default. C++ offers the `struct` keyword that makes members public by
-default.
+```
+class MyDerivedType extends MyBaseType {
+  fn Create() -> MyDerivedType {
+    return {.base = MyBaseType.Create(), .derived_field = ...};
+  }
+}
+```
+
+There are two cases that aren't well supported with this pattern:
+
+-   Users cannot create a value of an abstract class, which is necessary when it
+    has private fields or otherwise requires initialization.
+-   Users may want to reduce the chance of mistakes from calling a method on a
+    partially constructed object. Of particular concern is calling a virtual
+    method prior to forming the derived class and so it uses the base class
+    implementation.
+
+While expected to be relatively rarely needed, we will address both of these
+concerns with a specialized type just used during construction of base classes,
+called the partial facet type for the class.
+
+##### Partial facet
+
+The partial facet for a base class type like `MyBaseType` is written
+`partial MyBaseType`.
+
+-   Only methods that take the partial facet type may be called on the partial
+    facet type, so methods have to opt in to being called on an object that
+    isn't fully constructed.
+-   No virtual methods may take the partial facet type, so there is no way to
+    transitively call a virtual method on an object that isn't fully
+    constructed.
+-   `partial MyBaseClass` and `MyBaseClass` have the same fields in the same
+    order with the same data layout. The only difference is that
+    `partial MyBaseClass` doesn't use (look into) its hidden vptr slot. To
+    reliably catch any bugs where virtual function calls occur in this state,
+    both fast and hardened release builds will initialize the hidden vptr slot
+    to a null pointer. Debug builds will initialize it to an alternate vtable
+    whose functions will abort the program with a clear diagnostic.
+-   Since `partial MyBaseClass` has the same data layout but only uses a subset,
+    there is a subtyping relationship between these types. A `MyBaseClass` value
+    is a `partial MyBaseClass` value, but not the other way around. So you can
+    cast `MyBaseClass*` to `partial MyBaseClass*`, but the other direction is
+    not safe.
+-   When `MyBaseClass` may be instantiated, there is a conversion from
+    `partial MyBaseClass` to `MyBaseClass`. It changes the value by filling in
+    the hidden vptr slot. If `MyBaseClass` is abstract, then attempting that
+    conversion is an error.
+-   `partial MyBaseClass` is considered final, even if `MyBaseClass` is not.
+    This is despite the fact that from a data layout perspective,
+    `partial MyDerivedClass` will have `partial MyBaseClass` as a prefix if
+    `MyDerivedClass` extends `MyBaseClass`. The type `partial MyBaseClass`
+    specifically means "exactly this and no more." This means we don't need to
+    look at the hidden vptr slot, and we can instantiate it even if it doesn't
+    have a virtual destructor.
+-   The keyword `partial` may only be applied to a base class. For final
+    classes, there is no need for a second type.
+
+##### Usage
+
+The general pattern is that base classes can define constructors returning the
+partial facet type.
+
+```
+base class MyBaseClass {
+  fn Create() -> partial Self {
+    return {.base_field_1 = ..., .base_field_2 = ...};
+  }
+  // ...
+}
+```
+
+Extensible classes can be instantiated even from a partial facet value:
+
+```
+var mbc: MyBaseClass = MyBaseClass.Create();
+```
+
+The conversion from `partial MyBaseClass` to `MyBaseClass` only fills in the
+vptr value and can be done in place. After the conversion, all public methods
+may be called, including virtual methods.
+
+The partial facet is required for abstract classes, since otherwise they may not
+be instantiated. Constructor functions for abstract classes should be marked
+[protected](#protected-access) so they may only be accessed in derived classes.
+
+```
+abstract class MyAbstractClass {
+  protected fn Create() -> partial Self {
+    return {.base_field_1 = ..., .base_field_2 = ...};
+  }
+  // ...
+}
+// ❌ Error: can't instantiate abstract class
+var abc: MyAbstractClass = ...;
+```
+
+If a base class wants to store a pointer to itself somewhere in the constructor
+function, there are two choices:
+
+-   An extensible class could use the plain type instead of the partial facet.
+
+    ```
+    base class MyBaseClass {
+      fn Create() -> Self {
+        returned var result: Self = {...};
+        StoreMyPointerSomewhere(&result);
+        return var;
+      }
+    }
+    ```
+
+-   The other choice is to explicitly cast the type of its address. This pointer
+    should not be used to call any virtual method until the object is finished
+    being constructed, since the vptr will be null.
+
+    ```
+    abstract class MyAbstractClass {
+      protected fn Create() -> partial Self {
+        returned var result: partial Self = {...};
+        // Careful! Pointer to object that isn't fully constructed!
+        StoreMyPointerSomewhere(&result as Self*);
+        return var;
+      }
+    }
+    ```
+
+The constructor for a derived class may construct values from a partial facet of
+the class' immediate base type or the full type:
+
+```
+abstract class MyAbstractClass {
+  protected fn Create() -> partial Self { ... }
+}
+
+// Base class returns a partial type
+base class Derived extends MyAbstractClass {
+  protected fn Create() -> partial Self {
+    return {.base = MyAbstractClass.Create(), .derived_field = ...};
+  }
+  ...
+}
+
+base class MyBaseClass {
+  fn Create() -> Self { ... }
+}
+
+// Base class returns a full type
+base class ExtensibleDerived extends MyBaseClass {
+  fn Create() -> Self {
+    return {.base = MyBaseClass.Create(), .derived_field = ...};
+  }
+  ...
+}
+```
+
+And final classes will return a type that does not use the partial facet:
+
+```
+class FinalDerived extends MiddleDerived {
+  fn Create() -> Self {
+    return {.base = MiddleDerived.Create(), .derived_field = ...};
+  }
+  ...
+}
+```
+
+Observe that the vptr is only assigned twice in release builds if you use
+partial facets:
+
+-   The first class value created, by the factory function creating the base of
+    the class hierarchy, initialized the vptr field to nullptr. Every derived
+    type transitively created from that value will leave it alone.
+-   Only when the value has its most-derived class and is converted from the
+    partial facet type to its final type is the vptr field set to its final
+    value.
+
+In the case that the base class can be instantiated, tooling could optionally
+recommend that functions returning `Self` that are used to initialize a derived
+class be changed to return `partial Self` instead. However, the consequences of
+returning `Self` instead of `partial Self` when the value will be used to
+initialize a derived class are fairly minor:
+
+-   The vptr field will be assigned more than necessary.
+-   The types won't protect against calling methods on a value while it is being
+    constructed, much like the situation in C++ currently.
+
+#### Assignment with inheritance
+
+Since the assignment operator method should not be virtual, it is only safe to
+implement it for final types. However, following the
+[maxim that Carbon should "focus on encouraging appropriate usage of features rather than restricting misuse"](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write),
+we allow users to also implement assignment on extensible classes, even though
+it can lead to [slicing](https://en.wikipedia.org/wiki/Object_slicing).
+
+### Access control
+
+By default, all members of a class are fully publicly accessible. Access can be
+restricted by adding a keyword, called an
+[access modifier](https://en.wikipedia.org/wiki/Access_modifiers), prior to the
+declaration. Access modifiers are how Carbon supports
+[encapsulation](#encapsulated-types).
+
+The [access modifier](https://en.wikipedia.org/wiki/Access_modifiers) is written
+before any [virtual override keyword](#virtual-override-keywords).
 
 **Rationale:** Carbon makes members public by default for a few reasons:
 
@@ -1095,6 +1433,102 @@ included the decision that
 originally asked in issue
 [#665](https://github.com/carbon-language/carbon-lang/issues/665).
 
+#### Private access
+
+As in C++, `private` means only accessible to members of the class and any
+[friends](#friends).
+
+```carbon
+class Point {
+  fn Distance[me: Self]() -> f32;
+  // These are only accessible to members of `Point`.
+  private var x: f32;
+  private var y: f32;
+}
+```
+
+A `private virtual` or `private abstract` method may be implemented in derived
+classes, even though it may not be called. This allows derived classes to
+customize the behavior of a function called by a method of the base class, while
+still preventing the derived class from calling it. This matches the behavior of
+C++ and is more orthogonal.
+
+**Future work:** `private` will give the member internal linkage unless it needs
+to be external because it is used in an inline method or template. We may in the
+future
+[add a way to specify internal linkage explicitly](/proposals/p0722.md#specifying-linkage-as-part-of-the-access-modifier).
+
+**Open questions:** Using `private` to mean "restricted to this class" matches
+C++. Other languages support restricting to different scopes:
+
+-   Swift supports "restrict to this module" and "restrict to this file".
+-   Rust supports "restrict to this module and any children of this module", as
+    well as "restrict to this crate", "restrict to parent module", and "restrict
+    to a specific ancestor module".
+
+**Comparison to other languages:** C++, Rust, and Swift all make class members
+private by default. C++ offers the `struct` keyword that makes members public by
+default.
+
+#### Protected access
+
+Protected members may only be accessed by members of this class, members of
+derived classes, and any [friends](#friends).
+
+```
+base class MyBaseClass {
+  protected fn HelperClassFunction(x: i32) -> i32;
+  protected fn HelperMethod[me: Self](x: i32) -> i32;
+  protected var data: i32;
+}
+
+class MyDerivedClass extends MyBaseClass {
+  fn UsesProtected[addr me: Self*]() {
+    // Can access protected members in derived class
+    var x: i32 = HelperClassFunction(3);
+    me->data = me->HelperMethod(x);
+  }
+}
+```
+
+#### Friends
+
+Classes may have a _friend_ declaration:
+
+```
+class Buddy { ... }
+
+class Pal {
+  private var x: i32;
+  friend Buddy;
+}
+```
+
+This declares `Buddy` to be a friend of `Pal`, which means that `Buddy` can
+access all members of this class, even the ones that are declared `private` or
+`protected`.
+
+The `friend` keyword is followed by the name of an existing function, type, or
+parameterized family of types. Unlike C++, it won't act as a forward declaration
+of that name. The name must be resolvable by the compiler, and so may not be a
+member of a template.
+
+#### Test friendship
+
+**Future work:** There should be a convenient way of allowing tests in the same
+library as the class definition to access private members of the class. Ideally
+this could be done without changing the class definition itself, since it
+doesn't affect the class' public API.
+
+#### Access control for construction
+
+A function may construct a class, by casting a struct value to the class type,
+if it has access to (write) all of its fields.
+
+**Future work:** There should be a way to limit which code can construct a class
+even when it only has public fields. This will be resolved in question-for-leads
+issue [#803](https://github.com/carbon-language/carbon-lang/issues/803).
+
 ## Future work
 
 This includes features that need to be designed, questions to answer, and a
@@ -1192,25 +1626,57 @@ implementing corresponding interfaces, see
 
 ### Inheritance
 
-Carbon will need ways of saying:
+#### Destructors
 
--   this `class` type has a virtual method table
--   this `class` type extends a base type
--   this `class` type is "final" and may not be extended further
--   this method is "virtual" and may be overridden in descendents
--   this method is "pure virtual" or "abstract" and must be overridden in
-    descendants
--   this method overrides a method declared in a base type
+We need a syntax for declaring destructors. Provisionally we are considering
+allowing a couple of variations:
 
-Multiple inheritance will be limited in at least a couple of ways:
+```carbon
+class MyClass {
+  destructor [me: Self] { ... }
+}
+```
 
--   At most one supertype may define data members.
--   Carbon types can't access data members of C++ virtual base classes.
+or:
 
-There is a
-[document considering the options for constructing objects with inheritance](https://docs.google.com/document/d/1GyrBIFyUbuLJGItmTAYUf9sqSDQjry_kjZKm5INl-84/edit).
+```carbon
+class MyClass {
+  destructor [addr me: Self*] { ... }
+}
+```
+
+Destructors may be declared `virtual`, or `impl` in the case that a base class
+declares it `virtual`.
+
+```carbon
+base class MyBaseClass {
+  virtual destructor [addr me: Self*] { ... }
+}
 
-### C++ abstract base classes interoperating with object-safe interfaces
+class MyDerivedClass {
+  impl destructor [addr me: Self*] { ... }
+}
+```
+
+Destructors may be declared out-of-line:
+
+```carbon
+class MyClass {
+  destructor [addr me: Self*];
+}
+destructor MyClass [addr me: Self*] { ... }
+```
+
+It isn't safe to delete an instance of a base class through a pointer unless it
+has a
+[virtual destructor](https://en.wikipedia.org/wiki/Virtual_function#Virtual_destructors).
+
+An alternative is the Rust approach is there is some interface that is only
+implemented for types with non-trivial destructors. It allows metaprogramming to
+distinguish whether the type needs clean up. Rust allows you to declare `Self`
+as being moved into the destructor, which nicely captures the semantics.
+
+#### C++ abstract base classes interoperating with object-safe interfaces
 
 We want four things so that Carbon's object-safe interfaces may interoperate
 with C++ abstract base classes without data members, matching the
@@ -1231,6 +1697,91 @@ different type than `DynPtr(MyInterface)` since the receiver input to the
 function members of the vtable for the former does not match those in the
 witness table for the latter.
 
+#### Overloaded methods
+
+We allow a derived class to define a [class function](#class-functions) with the
+same name as a class function in the base class. For example, we expect it to be
+pretty common to have a constructor function named `Create` at all levels of the
+type hierarchy.
+
+Beyond that, we may want some rules or restrictions about defining methods in a
+derived class with the same name as a base class method without overriding it.
+There are some opportunities to improve on and simplify the C++ story:
+
+-   We don't want to silently hide methods in the base class because of a method
+    with the same name in a derived class. There are uses for this in C++, but
+    it also causes problems and without multiple inheritance there isn't the
+    same need in Carbon.
+-   Overload resolution should happen before virtual dispatch.
+-   For evolution purposes, you should be able to add private members to a base
+    class that have the same name as member of a derived class without affecting
+    overload resolution on instances of the derived class, in functions that
+    aren't friends of the base class.
+
+**References:** This was discussed in
+[the open discussion on 2021-07-12](https://docs.google.com/document/d/1QCdKQ33rki-kCDrxi8UHy3a36dtW0WdMqpUzluGSrz4/edit?resourcekey=0-bZmNUiueOiH_sysJNqnT9A#heading=h.40jlsrcgp8mr).
+
+#### Interop with C++ inheritance
+
+This design directly supports Carbon classes inheriting from a single C++ class.
+
+```
+class CarbonClass extends C++.CPlusPlusClass {
+  fn Create() -> Self {
+    return {.base = C++.CPlusPlusClass(...), .other_fields = ...};
+  }
+  ...
+}
+```
+
+To allow C++ classes to extend Carbon classes, there needs to be some way for
+C++ constructors to initialize their base class:
+
+-   There could be some way to export a Carbon class that identifies which
+    factory functions may be used as constructors.
+-   We could explicitly call the Carbon factory function, as in:
+
+    ```
+    // `Base` is a Carbon class which gets converted to a
+    // C++ class for interop purposes:
+    class Base {
+    public:
+        virtual ~Base() {}
+        static auto Create() -> Base;
+    };
+
+    // In C++
+    class Derived : public Base {
+    public:
+        virtual ~Derived() override {}
+        // This isn't currently a case where C++ guarantees no copy,
+        // and so it currently still requires a notional copy and
+        // there appear to be implementation challenges with
+        // removing them. This may require an extension to make work
+        // reliably without an extraneous copy of the base subobject.
+        Derived() : Base(Base::Create()) {}
+    };
+    ```
+
+    However, this doesn't work in the case where `Base` can't be instantiated,
+    or `Base` does not have a copy constructor, even though it shouldn't be
+    called due to RVO.
+
+##### Virtual base classes
+
+FIXME: Ask zygoloid to fill this in.
+
+Carbon won't support declaring virtual base classes, and the C++ interop use
+cases Carbon needs to support are limited. This will allow us to simplify the
+C++ interop by allowing Carbon to delegate initialization of virtual base
+classes to the C++ side.
+
+This requires that we enforce two rules:
+
+-   No multiple inheritance of C++ classes with virtual bases
+-   No C++ class extending a Carbon class that extends a C++ class with a
+    virtual base
+
 ### Mixins
 
 We will need some way to declare mixins. This syntax will need a way to
@@ -1243,31 +1794,46 @@ Open questions include whether a mixin is its own type that is a member of the
 containing type, and whether mixins are templated on the containing type. Mixins
 also complicate how constructors work.
 
-### Non-virtual inheritance
-
-We need some way of addressing two safety concerns created by non-virtual
-inheritance:
-
--   Unclear how to safely run the right destructor.
--   [Object slicing](https://en.wikipedia.org/wiki/Object_slicing) is a danger
-    when dereferencing a pointer of a base type.
-
-These concerns would be resolved by distinguishing between pointers that point
-to a specified type only and those that point to a type or any subtype. The
-latter case would have restrictions to prevent misuse. This distinction may be
-more complexity than is justified for a relatively rare use case. An alternative
-approach would be to forbid destruction of non-final types without virtual
-destructors, and forbid assignment of non-final types entirely.
-
-This open question is being considered in
-[question-for-leads issue #652](https://github.com/carbon-language/carbon-lang/issues/652).
-
 ### Memory layout
 
 Carbon will need some way for users to specify the memory layout of class types
 beyond simple ordering of fields, such as controlling the packing and alignment
 for the whole type or individual members.
 
+We may allow members of a derived class like to put data members in the final
+padding of its base class prefix. Tail-padding reuse has both advantages and
+disadvantages, so we may have some way for a class to explicitly mark that its
+tail padding is available for use by a derived class,
+
+Advantages:
+
+-   Tail-padding reuse is sometimes a nice layout optimization (eg, in Clang we
+    save 8 bytes per `Expr` by reusing tail padding).
+-   No class size regressions when migrating from C++.
+-   Special case of reusing the tail padding of a class that is empty other than
+    its tail padding is very important, to the extent that we will likely need
+    to support either zero-sized types or tail-padding reuse in order to have
+    acceptable class layouts.
+
+Disadvantages:
+
+-   Cannot use `memcpy(p, q, sizeof(Base))` to copy around base class subobjects
+    if the destination is an in-lifetime, because they might overlap other
+    objects' representations.
+-   Somewhat more complex model.
+-   We need some mechanism for disabling tail-padding reuse in "standard layout"
+    types.
+-   We may also have to use narrowed loads for the last member of a base class
+    to avoid accidentally creating a race condition.
+
+However, we can still use `memcpy` and `memset` to initialize a base class
+subobject, even if its tail padding might be reused, so long as we guarantee
+that no other object lives in the tail padding and is initialized before the
+base class. In C++, that happens only due to virtual base classes getting
+initialized early and laid out at the end of the object; if we disallow virtual
+base classes then we can guarantee that initialization order is address order,
+removing most of the downside of tail-padding reuse.
+
 ### No `static` variables
 
 At the moment, there is no proposal to support

+ 1 - 0
proposals/README.md

@@ -69,5 +69,6 @@ request:
 -   [0680 - And, or, not](p0680.md)
 -   [0722 - Nominal classes and methods](p0722.md)
 -   [0731 - Generics details 2: adapters, associated types, parameterized interfaces](p0731.md)
+-   [0777 - Inheritance](p0777.md)
 
 <!-- endproposals -->

+ 498 - 0
proposals/p0777.md

@@ -0,0 +1,498 @@
+# Inheritance
+
+<!--
+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/777)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Classes are final by default](#classes-are-final-by-default)
+    -   [Allow keywords to be written when they would have no effect](#allow-keywords-to-be-written-when-they-would-have-no-effect)
+        -   [Allow `final class`](#allow-final-class)
+        -   [Allow `partial FinalClass`](#allow-partial-finalclass)
+    -   [Different virtual override keywords](#different-virtual-override-keywords)
+    -   [Different virtual override keyword placement](#different-virtual-override-keyword-placement)
+    -   [Final methods](#final-methods)
+    -   [Constructors](#constructors)
+        -   [Different keyword than `partial`](#different-keyword-than-partial)
+        -   [Partial facet for extensible classes](#partial-facet-for-extensible-classes)
+        -   [Derived constructors set base fields](#derived-constructors-set-base-fields)
+        -   [No partial facet](#no-partial-facet)
+        -   [Only mixins and interfaces](#only-mixins-and-interfaces)
+        -   [Swift approach](#swift-approach)
+        -   [C# approach](#c-approach)
+        -   [Construct function](#construct-function)
+    -   [Implicit abstract classes](#implicit-abstract-classes)
+    -   [No extensible objects with non-virtual destructors](#no-extensible-objects-with-non-virtual-destructors)
+    -   [Separate "exact" and "or derived" variations on types](#separate-exact-and-or-derived-variations-on-types)
+    -   [Separate "exact" and "or derived" variations on pointers](#separate-exact-and-or-derived-variations-on-pointers)
+
+<!-- tocstop -->
+
+## Problem
+
+We would like to address the use cases for inheritance described in proposal
+[#561: Basic classes: use cases, struct literals, struct types, and future work](https://github.com/carbon-language/carbon-lang/pull/561),
+including providing a migration path for C++ types and programmers currently
+using inheritance.
+
+## Background
+
+This is a follow up to these previous proposals defining classes:
+
+-   [#561: Basic classes: use cases, struct literals, struct types, and future work](https://github.com/carbon-language/carbon-lang/pull/561)
+-   [#722: Nominal classes and methods](https://github.com/carbon-language/carbon-lang/pull/722)
+
+## Proposal
+
+The proposal is to update [docs/design/classes.md](docs/design/classes.md) as
+described in [this PR](https://github.com/carbon-language/carbon-lang/pull/777).
+
+## Rationale based on Carbon's goals
+
+This particular proposal is focusing on these Carbon goals:
+
+-   [That code is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write),
+    particularly addressing mechanisms for writing object-oriented code familiar
+    to C++ programmers. We have attempted to include support for most C++ usage
+    patterns, rather than a lot of safety restrictions following the maxim that
+    Carbon should "focus on encouraging appropriate usage of features rather
+    than restricting misuse".
+-   [That Carbon supports writing performance-critical software](/docs/project/goals.md#performance-critical-software).
+    This includes removing cruft from the produced binaries by limiting support
+    for multiple and virtual inheritance, avoiding redundantly setting the vptr
+    when constructing objects, and making classes final by default.
+-   [That Carbon has practical safety and testing mechanisms](/docs/project/goals.md#practical-safety-and-testing-mechanisms).
+    This proposal addresses safety concerns with non-virtual destructors by
+    making the unsafe case syntactically visible, and providing the tools for
+    safer alternative approaches by using
+    [final classes](<https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#Non-subclassable_classes>).
+
+## Alternatives considered
+
+### Classes are final by default
+
+This is a divergence from C++, but has a number of benefits:
+
+-   Classes are not in general safe for derivation unless they are explicitly
+    designed to be. One example is that a class `X` may assume that any value of
+    type `X*` should be treated as a pointer to exactly that type.
+-   Final classes are easier to evolve, since there are no concerns that a newly
+    added name will conflict with one in a derived class.
+-   It is only safe to delete a pointer to a class that is final or has a
+    virtual destructor. Making classes final by default means we can provide
+    good ergonomics without sacrificing safety.
+-   We want to encourage users to use composition or interfaces instead of
+    inheritance unless they consciously decide that is the right solution for
+    their use case.
+-   Labelling a class that supports inheritance as a `base class` puts
+    information about the class important to readers up front, rather than
+    leaving them wondering whether the class supports inheritance or just
+    accidentally used the default.
+-   The compiler can easily diagnose that a class is mistakenly final when you
+    attempt to extend it. It is much more difficult to determine that a class is
+    mistakenly a base.
+-   We expect there are some performance and code size benefits.
+
+### Allow keywords to be written when they would have no effect
+
+In both of these cases, we decided it was better that there was only one way to
+write the code, than allow a keyword to be written in a situation where it only
+acted as a comment without changing the meaning of the code.
+
+#### Allow `final class`
+
+We considered allowing `final class` as a synonym for `class` without a `base`
+prefix, but we didn't feel it would provide benefit justifying the additional
+complexity.
+
+#### Allow `partial FinalClass`
+
+We considered allowing `partial` to be used for all constructor functions. For a
+final class, `partial FinalClass` would be an alias for `FinalClass`. FIXME
+**Answer: No**
+
+### Different virtual override keywords
+
+Instead of `virtual` we considered `base`. This would create a parallel
+structure between `abstract` and `base` classes on one hand, and `abstract` and
+`base` methods on the other. However, we felt like this was an important case to
+maintain continuity with C++.
+
+Instead of `abstract` we considered:
+
+-   `virtual` ... `= 0`
+-   `required`
+-   `pure virtual`
+-   `virtual` ... `pure`
+
+We didn't like using a suffix like `= 0` or `= pure`, since it is in place of an
+implementation but we wouldn't put it out of line like an implementation. We
+didn't like `= 0` despite it being consistent with C++ because it didn't reflect
+the meaning in the way a keyword could, and keywords are easier to look up in
+search engines. We might reconsider `required` if we decide that we want to use
+that keyword in other places, such as in a mixin. In the end, we went with
+`abstract` since it is used in other languages, such as Java, and could stand on
+its own without having to be paired with `virtual`.
+
+Instead of `impl` we considered using `override` as done in C++, with the
+difference that the keyword would be mandatory in Carbon. There were a few
+concerns with using `override`:
+
+-   It doesn't match the case where the base class doesn't have an
+    implementation to override because it is abstract or pure virtual.
+-   Concern about confusion between overriding and overloading.
+
+The choice of `impl` is intended to draw a parallel with implementing
+interfaces.
+
+If we went with `override`, we might change the other keywords to match, using
+`must_override` instead of `abstract` and `overridable` instead of `virtual`. We
+might consider switching to `overridable` if we decide that is a keyword we
+would use in other contexts that allow overriding without using runtime dispatch
+using a virtual table, for example interfaces or mixins.
+
+### Different virtual override keyword placement
+
+We considered putting the virtual override keyword after the function's
+signature:
+
+```
+base class MyBaseClass {
+  fn Overridable[me: Self]() -> i32 virtual { return 7; }
+}
+```
+
+Rationale for putting the keyword to the right:
+
+-   This is less salient information than the name and signature of the
+    function, particularly for callers of the API.
+-   This choice allows the function names to line up vertically.
+-   This keyword is about the implementation. For example, it says whether there
+    is an implementation of this method in this class at all.
+
+Unless you are extending the class, callers would not notice replacing a virtual
+function with a non-virtual function calling a private virtual function.
+
+The concern was that while this choice makes the API easier to read for users
+calling methods on the base class, it makes it significantly harder to read for
+users extending the base class. And extending the base class was a common enough
+and important enough use case that this change was not worth also trading off
+familiarity from C++.
+
+**Reference:** This was decided in issue
+[#754: Placement of the word virtual](https://github.com/carbon-language/carbon-lang/issues/754).
+
+### Final methods
+
+We considered allowing `final` to be used as a virtual override keyword, to mark
+[non-overridable methods](<https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)#Non-overridable_methods>).
+This is something we might change in the future, based on demonstrated need, but
+for now we didn't see the use cases for it occurring in practice that would
+justify its addition to the language. This was based on a few reasons.
+
+-   Even though this exists in C++ code, it can be dropped without changing
+    meaning.
+-   We expect you can get similar performance benefits from profile guided
+    optimizations and devirtualization.
+-   We imagined that we might use this keyword in the future with a different
+    meaning, such as "no shadow".
+-   We saw little harm in omitting this for now, even if we decide to add it in
+    later if and when we see that it would be useful for Carbon programmers.
+
+Note that if we were to add final methods, they would be allowed to be
+implemented in the partial facet type of a base class.
+
+### Constructors
+
+[Perils of Constructors](https://matklad.github.io/2019/07/16/perils-of-constructors.html)
+gives a great overview of the challenges with constructors. It expresses the
+advantages of the factory function approach used by Rust, but observes that
+there are some difficulties making it work with inheritance and placement.
+Proposal
+[#257: Initialization of memory and variables](https://github.com/carbon-language/carbon-lang/pull/257/files)
+addresses the placement component of construction, and this proposal extends
+that approach to work with inheritance using the `partial` facet. This approach
+has some benefits:
+
+-   Simplicity by not having constructors with different rules from other
+    functions.
+-   No initializer list
+    [shadow world](https://gbracha.blogspot.com/2014/09/a-domain-of-shadows.html).
+-   No distinction between constructors and other factory functions.
+-   No need for rules and syntax for
+    [delegating](https://docs.microsoft.com/en-us/cpp/cpp/delegating-constructors?view=msvc-160)
+    or
+    [convenience](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID217)
+    constructors.
+-   No need to have special handling of errors.
+-   Ability to write code in a derived constructor before calling its base
+    constructor.
+-   No static analysis of code, potentially with control flow, to ensure that
+    all fields are initialized.
+
+We considered several alternatives, particularly in issue
+[#741: Constructing an object of a derived type](https://github.com/carbon-language/carbon-lang/issues/741).
+
+#### Different keyword than `partial`
+
+In issue [#741](https://github.com/carbon-language/carbon-lang/issues/741), we
+considered other keywords instead of `partial` to designate the facet of the
+type for construction.
+
+-   `base`: Intended to indicate a
+    [base class subobject](https://en.cppreference.com/w/cpp/language/derived_class),
+    but was confusing with other uses of the word "base" to mean "the base class
+    of a type."
+-   `as_base`: Intended to address the confusion around using `base` by adding a
+    preposition that indicates this isn't the "base of the type." However, it
+    introduces confusion with the `as` operator used to cast.
+-   `bare`: Too far from the intended meaning.
+-   `impl`: This keyword is already being used for other things that are too
+    different from this use.
+-   `novirt`: Describes something about the effect of this keyword, but not why
+    you are using it.
+-   `exact`: Intended to suggest this is the is a use of the exact type, not a
+    possibly derived type. This, like `novirt`, was too focused on the effect of
+    the keyword and wasn't suggestive enough of why it was being used. Also this
+    didn't capture why this keyword would allow you to instantiate an abstract
+    base class.
+-   `ctor`, `construct`, `constructor`: These were the wrong part of speech. The
+    type is not the constructor, the function returning this type is.
+-   `under_construction`: Too long.
+
+For the construction-related options, there were also concerns that we might
+also use this type during destruction of an object.
+
+#### Partial facet for extensible classes
+
+In issue [#741](https://github.com/carbon-language/carbon-lang/issues/741), we
+considered recommending using the `partial` facet in constructors of extensible
+classes more strongly than the current proposal. Ultimately we decided it wasn't
+necessary:
+
+-   The behavior was more consistent with C++.
+-   The consequences of not using `partial` are small enough, matching C++
+    instead of a possible improvement.
+-   The rule for when to use `partial` was too subtle and hard to explain.
+-   Ending up with a `partial` type because you declared a variable with type
+    `auto` seemed like a bad user experience.
+-   Writing both a `protected` constructor returning a `partial` type for
+    descendants and a public constructor returning the full type improved the
+    ergonomics for using the class but seemed like painful boilerplate for
+    authors of the class.
+
+#### Derived constructors set base fields
+
+In issue [#741](https://github.com/carbon-language/carbon-lang/issues/741), we
+considered making the constructor of a derived class explicitly set the fields
+of the base class without delegating to the base constructor, avoiding the
+problem of trying to instantiate a base class that might be abstract.
+
+It had some clear disadvantages including:
+
+-   There would be no way to make members of a base class private, particularly
+    their names.
+-   It wasn't clear how to interoperate with C++.
+
+#### No partial facet
+
+In issue [#741](https://github.com/carbon-language/carbon-lang/issues/741), we
+considered allowing instantiating abstract base classes so they could be used to
+initialize derived classes, but this was a safety regression from C++.
+
+#### Only mixins and interfaces
+
+In issue [#741](https://github.com/carbon-language/carbon-lang/issues/741), we
+considered splitting inheritance into separate mechanisms for subtyping and
+implementation reuse. Interfaces would represent APIs for subtyping purposes and
+implementations would be defined in mixins. This was a major divergence from C++
+and would likely cause problems for both programmers and interoperation.
+
+#### Swift approach
+
+[Swift initialization](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html)
+requires the user to define a special `init` method that initializes the fields
+of the object before calling any methods on it. For a
+[derived class](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID216),
+this is then followed by a call to the base's `init` method. After that is done,
+there is a
+[second phase of initialization](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#ID220)
+that can operate on an object that at least has all fields initialized. This
+means method calls are allowed, even though it is possible that not all
+invariants of the class have been established for the object.
+
+```
+class MyClass extends BaseClass {
+  fn init(...) {
+    me.derived_field = ...;
+    super.init(base_arguments);
+    phase_2_after_fields_are_set();
+  }
+}
+```
+
+This approach has some nice properties, for example it supports calling virtual
+methods in the base class' `init` method and getting the derived implementation.
+However it has some disadvantages for our purposes:
+
+-   Relies on potentially fragile static analysis of the code to determine that
+    all fields are initialized.
+-   Init methods have a number of restrictions, such as no method calls in the
+    first phase, to avoid potentially unsafe use of a partially initialized
+    value. So init methods are not ordinary method calls even though they
+    superficially look quite similar.
+-   Unclear what destructors to run if there is a failure partway through
+    construction.
+-   Would not interoperate well with C++, since derived fields are initialized
+    before base fields. This also means that the initial value for derived
+    fields can't be set using the values of the base fields set in the base's
+    init method.
+
+#### C# approach
+
+[C# Constructors](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors)
+have names that match their class, and the constructor of a derived class starts
+with a call to the base class' constructor using this `: base(...)` syntax
+between the parameter list and function body:
+
+```
+class MyClass extends BaseClass {
+  fn MyClass(...) : base(base_arguments) {
+    me.derived_field = ...;
+    phase_2_after_fields_are_set();
+  }
+}
+```
+
+Alternatively, a constructor can delegate to another constructor using
+`: this(...)` syntax instead.
+
+Disadvantages for our purposes:
+
+-   Doesn't allow you to write code before calling the base class' constructor.
+-   Constructors have a special syntax and are not ordinary functions. However
+    those differences would be familiar to C++ programmers.
+-   Relies on potentially fragile static analysis of the code to determine that
+    all fields are initialized and that it is safe to call methods.
+-   Unclear what destructors to run if there is a failure partway through
+    construction.
+
+#### Construct function
+
+We rejected prior Carbon proposal
+[#98](https://github.com/carbon-language/carbon-lang/pull/98), where the user's
+initialization function called a compiler-provided function to create the object
+once the base constructor arguments and derived field values were known.
+
+```
+class MyClass extends BaseClass {
+  fn operator create(...) -> Self {
+    ...
+    returned var result: Self =
+        construct(base_arguments, {.derived_field = ...});
+    phase_2_after_fields_are_set();
+    return result;
+  }
+}
+```
+
+This avoids giving a name to the object being constructed until its fields have
+been initialized, without relying on static analysis, making it clearer what
+destructors should run in the case of failure, though the current proposal is
+still clearer.
+
+Disadvantages for our purposes:
+
+-   Complexity when initializing fields that depended on the address of the
+    object being constructed.
+-   Constructors are special, not ordinary functions.
+
+Note that this prevents using the values assigned to the fields in the base's
+constructor to determine the initial values for the derived fields. We could
+address this concern by splitting the special `construct` function into two
+pieces:
+
+```
+class MyClass extends BaseClass {
+  fn operator create(...) -> Self* {
+    ...
+    var parent: BaseClass* = create_base(base_arguments);
+    // Can determine the values for derived fields here.
+    var result: Self* = construct(parent, {.derived_field = ...});
+    phase_2_after_fields_are_set();
+    return result;
+  }
+}
+```
+
+This adds some complexity, but interoperates better with C++.
+
+### Implicit abstract classes
+
+We considered following C++'s approach of making classes abstract based on
+having any pure virtual methods. This leads to awkward workarounds where you
+might mark a class' destructor as pure virtual even though it is still
+implemented. We decided to use a different introducer for abstract classes since
+this is very important for readers, helping them determine the role of the class
+and whether this is the class they are looking for.
+
+We thought that if you were to change a class to being abstract, you would
+likely also update its description and rename it at the same time, since that
+was such an important change to the interface of the class.
+
+### No extensible objects with non-virtual destructors
+
+We considered forbidding constructing extensible objects with non-virtual
+destructors. This was to avoid getting into a state where a type could be used
+as a local variable but not allocated on the heap. It was also identified as an
+advanced use case that didn't need to be as convenient to write, and so the
+overhead of using both a final and an abstract type in place of an extensible
+type might be more acceptable and would give much more clarity to what a given
+type represented.
+
+However, this was a noticeable divergence from C++ where extensible objects are
+the default. We decided that consistency with both C++ and extensible classes
+with virtual methods was more valuable. The error when deleting a base class
+with a non-virtual destructor would be very clear and offer useful alternatives:
+making the destructor virtual, making a final class, or using `unsafe_delete`.
+This matched the idea that
+[Carbon should "focus on encouraging appropriate usage of features rather than restricting misuse"](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write).
+
+This topic was discussed in issue
+[#652: Extensible classes with or without vtables](https://github.com/carbon-language/carbon-lang/issues/652)
+and
+[on Discord](https://discord.com/channels/655572317891461132/708431657849585705/880471907407888404).
+
+### Separate "exact" and "or derived" variations on types
+
+Issue [#652](https://github.com/carbon-language/carbon-lang/issues/652)
+considered many variations on ways to have two different types for values
+depending on whether they represented a value with an exact type, or a value
+that could be a derived type. We ultimately decided that asking users to use
+both types would be too much congnitive overhead, and would be a usability
+regression from C++.
+
+### Separate "exact" and "or derived" variations on pointers
+
+Issue [#652](https://github.com/carbon-language/carbon-lang/issues/652)
+considered instead having two kinds of pointers. One would point to a value of a
+specific known type, and the other would point to a value of some derived type.
+This has two disadvantages compared to having the variations be on the types of
+the values.
+
+-   The distinction between pointer types is meaningless for non-extensible
+    types.
+-   We still need the distinction for value types to give the right type to the
+    result of dereferencing the pointer.