# 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 cognitive 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.
