# Clarify rules around `Self` and `.Self`

<!--
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/2107)

<!-- toc -->

## Table of contents

-   [Abstract](#abstract)
-   [Problem](#problem)
-   [Background](#background)
-   [Proposal](#proposal)
-   [Details](#details)
-   [Rationale](#rationale)
-   [Alternatives considered](#alternatives-considered)
    -   [`Self` not a keyword](#self-not-a-keyword)
    -   [Make `Self` a member of all types](#make-self-a-member-of-all-types)
    -   [`where` operator could be associative](#where-operator-could-be-associative)

<!-- tocstop -->

## Abstract

A number of smaller changes grouped together in one proposal:

-   Make `Self` a keyword.
-   Clarify that `Self` refers to the current type in a base class and in impl
    declarations.
-   Clarify when `.Self` is legal, and what type it has.
-   Also specify that `where` is not an associative operator.

## Problem

There were a number of gaps found in the design when @zygoloid went to implement
these features in [the explorer codebase](/explorer), for example
[#1311: Basic support for `.Self` within `:!` bindings and `where` expressions](https://github.com/carbon-language/carbon-lang/pull/1311).

## Background

`Self` was introduced for interfaces and implementations in
[#524: Generics overview](https://github.com/carbon-language/carbon-lang/pull/524)
and
[#553: Generics details part 1](https://github.com/carbon-language/carbon-lang/pull/553).
`Self` was introduced for class types and methods in
[#494: Method syntax](https://github.com/carbon-language/carbon-lang/issues/494)
and
[#722: Nominal classes and methods](https://github.com/carbon-language/carbon-lang/pull/722).

Constraints using `where` and `.Self` were introduced in
[#818: Constraints for generics (generics details 3)](https://github.com/carbon-language/carbon-lang/pull/818).
The use of `where` to set associated types was introduced in
[#1013: Generics: Set associated constants using `where` constraints](https://github.com/carbon-language/carbon-lang/pull/1013).

The type of `.Self` and where it would be introduced grammatically was discussed
[#generics channel on Discord on 2022-06-07](https://discord.com/channels/655572317891461132/708431657849585705/1013904969335836732).

## Proposal

This proposal implements a number of changes and clarifications about the use of
`Self` and `.Self` with generics:

-   `Self` is now a keyword, and may not be used as an identifier even in
    contexts where `Self` has no meaning. If `Self` is used in a C++ API, Carbon
    will use the same mechanism for interop as other Carbon keywords.
-   Clarify that `Self` always refers to the current type, even for virtual
    functions implemented in a derived class, not the type implementing the
    method.
-   `Self` in an `impl` declaration may be used after the `as` to refer to the
    type being implemented. This could be the type named before `as` when
    specified, otherwise it is the enclosing type.
-   Clarify that `.Self` is legal after `:!` and `where`, as long as it only
    refers to a single type variable.
-   Specify the type of `.Self` as `Type` after `:!`, or `MyConstraint` after
    `MyConstraint where`.

In addition, this proposal specifies that `where` is not an associative
operator.

## Details

`Self` was added as a keyword to
[`docs/design/lexical_conventions/words.md`](/docs/design/lexical_conventions/words.md).
The other rules were added to
[`docs/design/classes.md`](/docs/design/classes.md) and
[`docs/design/generics/details.md`](/docs/design/generics/details.md).

## Rationale

This proposal fills in gaps with an aim to make things consistent and simplify
by having fewer rules where possible. For example, the rule saying that it is an
error if `.Self` could mean two different things is consistent with other name
lookup rules, such as those from
[#989: Member access expressions](https://github.com/carbon-language/carbon-lang/pull/989)
and
[#2070: Always `==` not `=` in `where` clauses](https://github.com/carbon-language/carbon-lang/pull/2070).
Simplicity benefits Carbon's
[language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem)
and consistency leads to
[code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write).

## Alternatives considered

### `Self` not a keyword

An alternative considered was forbidding identifiers to be equal to `Self`. The
big concern with that approach is that we would need some other way to
interoperate with C++ code, particularly classes, that had a `Self` member. If
we were adding `Self` to the language later as part of evolution, we would make
it a keyword. That would allow us to use the same evolution strategy as other
keywords -- we would automatically update the code to change existing uses of
`Self` to the raw identifier syntax.

Note that at this time
[no raw identifier syntax has been approved](https://github.com/carbon-language/carbon-lang/pull/93),
but Rust uses a `r#` prefix. If Carbon used the same syntax, existing uses of
`Self` would be changed to `r#Self`, and so `r#Self` should still be a legal
identifier.

### Make `Self` a member of all types

We considered making `Self` a member of all types. From this uses of `Self` and
`.Self` would follow naturally. It would have other consequences as well:

-   `T.Self == T` for all types `T`.
-   `x.Self`, where `x` is a non-type value with type `T`, would be `T`. This is
    because under the normal member-access rules, since `Self` is not a member
    of `x`, it would look in `T` and find `T.Self`.

This raised the question of whether `Self` is a member of type-of-types like
`Type`. That would seem to introduce an ambiguity for `i32.Self`. Furthermore,
using `x.Self` to get the type of `x` seemed tricky, it would be better to have
something that used the word "type" to do that.

Since [`Self` is a keyword](#self-not-a-keyword), we don't need to make it
follow the normal member-access rules. So we instead only define what it means
in places where we have a use case.

This was discussed
[on 2022-08-29 in the #typesystem channel in Discord](https://discord.com/channels/655572317891461132/708431657849585705/1013904969335836732).

### `where` operator could be associative

We considered making the `where` operator associative, since an expression like

```
Interface1 where .AssocType1 is Interface2 where .AssocType2 == i32
```

would more usefully be interpreted as:

```
Interface1 where .AssocType1 is (Interface2 where .AssocType2 == i32)
```

than the alternative. However, this is expected to be a rare case and so it
seemed much friendlier to humans to require parentheses or a separate named
constraint declaration. This way they can easily visually disambiguate how it is
interpreted without having to remember a rule that won't commonly be relevant.

This was discussed in
[the #syntax channel on Discord on 2022-05-27](https://discord.com/channels/655572317891461132/709488742942900284/979869282903130153)
and
[the weekly sync meeting on 2022-06-01](https://docs.google.com/document/d/1dwS2sJ8tsN3LwxqmZSv9OvqutYhP71dK9Dmr1IXQFTs/edit?resourcekey=0-NxBWgL9h05yD2GOR3wUisg#heading=h.qarzfirrcrgf).
