mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:00:11 +01:00
Reduce ambiguity in terminology (#3162)
Change terminology away from terms that are ambiguous: - Reserve "generic type" for types with (compile-time) parameters, like `Vector` in `Vector(T:! type)`. Don't use that term to refer to `T`, as it would with [#2360](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2360.md#terminology). - Use the term "compile-time" instead of "constant" to mean "template or symbolic." Expand the term "constant" to include values, such as from `let` bindings.
This commit is contained in:
+23
-18
@@ -29,7 +29,7 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
- [String literals](#string-literals)
|
||||
- [Values, objects, and expressions](#values-objects-and-expressions)
|
||||
- [Expression categories](#expression-categories)
|
||||
- [Value phases](#value-phases)
|
||||
- [Expression phases](#expression-phases)
|
||||
- [Composite types](#composite-types)
|
||||
- [Tuples](#tuples)
|
||||
- [Struct types](#struct-types)
|
||||
@@ -399,7 +399,7 @@ Some values, such as `()` and `{}`, may even be used as types, but only act like
|
||||
types when they are in a type position, like after a `:` in a variable
|
||||
declaration or the return type after a `->` in a function declaration. Any
|
||||
expression in a type position must be
|
||||
[a constant or symbolic value](#value-phases) so the compiler can resolve
|
||||
[a compile-time constant](#expression-phases) so the compiler can resolve
|
||||
whether the value can be used as a type. This also puts limits on how much
|
||||
operators can do different things for types. This is good for consistency, but
|
||||
is a significant restriction on Carbon's design.
|
||||
@@ -688,18 +688,18 @@ The primitive conversion steps used are:
|
||||
> - Proposal
|
||||
> [#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
|
||||
|
||||
### Value phases
|
||||
### Expression phases
|
||||
|
||||
Value expressions are also broken down into three _value phases_:
|
||||
Value expressions are further broken down into three _expression phases_:
|
||||
|
||||
- A _constant_ has a value known at compile time, and that value is available
|
||||
during type checking, for example to use as the size of an array. These
|
||||
include literals ([integer](#integer-literals),
|
||||
- A _template constant_ has a value known at compile time, and that value is
|
||||
available during type checking, for example to use as the size of an array.
|
||||
These include literals ([integer](#integer-literals),
|
||||
[floating-point](#floating-point-literals), [string](#string-literals)),
|
||||
concrete type values (like `f64` or `Optional(i32*)`), expressions in terms
|
||||
of constants, and values of
|
||||
[`template` parameters](#checked-and-template-parameters).
|
||||
- A _symbolic value_ has a value that will be known at the code generation
|
||||
- A _symbolic constant_ has a value that will be known at the code generation
|
||||
stage of compilation when
|
||||
[monomorphization](https://en.wikipedia.org/wiki/Monomorphization) happens,
|
||||
but is not known during type checking. This includes
|
||||
@@ -707,19 +707,23 @@ Value expressions are also broken down into three _value phases_:
|
||||
expressions with checked-generic arguments, like `Optional(T*)`.
|
||||
- A _runtime value_ has a dynamic value only known at runtime.
|
||||
|
||||
Carbon will automatically convert a constant to a symbolic value, or any value
|
||||
to a runtime value:
|
||||
Template constants together with symbolic constants are referred to as
|
||||
_compile-time constants_.
|
||||
|
||||
Carbon will automatically convert a template constant to a symbolic constant, or
|
||||
any value to a runtime value:
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
A(constant)-->B(symbolic value)-->C(runtime value);
|
||||
A(template constant)-->B(symbolic constant)-->C(runtime value);
|
||||
D(reference expression)-->C;
|
||||
```
|
||||
|
||||
Constants convert to symbolic values and to runtime values. Symbolic values will
|
||||
generally convert into runtime values if an operation that inspects the value is
|
||||
performed on them. Runtime values will convert into constants or to symbolic
|
||||
values if constant evaluation of the runtime expression succeeds.
|
||||
Template constants convert to symbolic constants and to runtime values. Symbolic
|
||||
constants will generally convert into runtime values if an operation that
|
||||
inspects the value is performed on them. Runtime values will convert into
|
||||
template or symbolic constants if constant evaluation of the runtime expression
|
||||
succeeds.
|
||||
|
||||
> **Note:** Conversion of runtime values to other phases is provisional.
|
||||
|
||||
@@ -1006,7 +1010,7 @@ the program's correctness must not depend on which option the Carbon
|
||||
implementation chooses.
|
||||
|
||||
A [generic binding](#checked-and-template-parameters) uses `:!` instead of a
|
||||
colon (`:`) and can only match [constant or symbolic values](#value-phases), not
|
||||
colon (`:`) and can only match [compile-time constant](#expression-phases), not
|
||||
run-time values.
|
||||
|
||||
The keyword `auto` may be used in place of the type in a binding pattern, as
|
||||
@@ -2723,8 +2727,9 @@ templates. Constraints can then be added incrementally, with the compiler
|
||||
verifying that the semantics stay the same. Once all constraints have been
|
||||
added, removing the word `template` to switch to a checked parameter is safe.
|
||||
|
||||
The [value phase](#value-phases) of a checked parameter is a symbolic value
|
||||
whereas the value phase of a template parameter is constant.
|
||||
The [expression phase](#expression-phases) of a checked parameter is a symbolic
|
||||
constant whereas the expression phase of a template parameter is template
|
||||
constant.
|
||||
|
||||
Although checked generics are generally preferred, templates enable translation
|
||||
of code between C++ and Carbon, and address some cases where the type checking
|
||||
|
||||
@@ -583,7 +583,7 @@ fn CallStaticMethod(c: C) {
|
||||
|
||||
// ✅ OK
|
||||
let T:! type = C.Nested;
|
||||
// ❌ Error: value of `:!` binding is not constant because it
|
||||
// ❌ Error: value of `:!` binding is not compile-time because it
|
||||
// refers to local variable `c`.
|
||||
let U:! type = c.Nested;
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
Generally speaking, when we talk about _generics_, either
|
||||
[checked or template](#checked-versus-template-parameters), we are talking about
|
||||
generalizing some language construct by adding a compile-time parameter, called
|
||||
a _generic parameter_, to it. So:
|
||||
generalizing some language construct by adding a _compile-time parameter_, also
|
||||
called a _generic parameter_, to it. So:
|
||||
|
||||
- a _generic function_ is a function with at least one compile-time parameter,
|
||||
which could be an explicit argument to the function or
|
||||
@@ -285,28 +285,28 @@ complete definition checking. This occurs for
|
||||
|
||||
_Binding patterns_ associate a name with a type and a value. This is used to
|
||||
declare function parameters, in `let` and `var` declarations, as well as to
|
||||
declare [generic parameters](#generic-means-compile-time-parameterized). There
|
||||
are three kinds of binding patterns, corresponding to
|
||||
[the three value phases](/docs/design/README.md#value-phases):
|
||||
declare [compile-time parameters](#generic-means-compile-time-parameterized) for
|
||||
classes, interfaces, and so on. There are three kinds of binding patterns,
|
||||
corresponding to
|
||||
[the three expression phases](/docs/design/README.md#expression-phases):
|
||||
|
||||
- A _runtime binding pattern_ binds to a dynamic value at runtime, and is
|
||||
written using a `:`, as in `x: i32`.
|
||||
- A _symbolic constant binding pattern_ or _symbolic binding pattern_ binds to
|
||||
a compile-time value that is not known when type checking, and is used to
|
||||
declare [checked generic](#checked-versus-template-parameters) parameters.
|
||||
These binding use `:!`, as in `T:! type`.
|
||||
- A _template constant binding pattern_ or _template binding pattern_ binds to
|
||||
a compile-time value that is known when type checking, and is used to
|
||||
declare [template](#checked-versus-template-parameters) parameters. These
|
||||
bindings use the keyword `template` in addition to `:!`, as in
|
||||
`template T:! type`.
|
||||
- A _symbolic binding pattern_ binds to a compile-time value that is not known
|
||||
when type checking, and is used to declare
|
||||
[checked generic](#checked-versus-template-parameters) parameters. These
|
||||
binding use `:!`, as in `T:! type`.
|
||||
- A _template binding pattern_ binds to a compile-time value that is known
|
||||
when type checking, and is used to declare
|
||||
[template](#checked-versus-template-parameters) parameters. These bindings
|
||||
use the keyword `template` in addition to `:!`, as in `template T:! type`.
|
||||
|
||||
The last two binding patterns, which are about binding a compile-time value, are
|
||||
called _constant binding patterns_, and correspond to those binding patterns
|
||||
called _compile-time binding patterns_, and correspond to those binding patterns
|
||||
that use `:!`.
|
||||
|
||||
The name being declared, which is the identifier to the left of the `:` or `:!`,
|
||||
is called a _binding_, or more specifically a _runtime binding_, _constant
|
||||
is called a _binding_, or more specifically a _runtime binding_, _compile-time
|
||||
binding_, _symbolic binding_, or _template binding_. The expression to the right
|
||||
defining the type of the binding pattern is called the _binding type
|
||||
expression_, a kind of [type expression](#type-expression). For example, in
|
||||
@@ -368,10 +368,10 @@ cases, we are concerned with the type value after the implicit conversion.
|
||||
## Facet binding
|
||||
|
||||
We use the term _facet binding_ to refer to the name introduced by a
|
||||
[constant binding pattern](#bindings) (using `:!` with or without the `template`
|
||||
modifier) where the declared type is a [facet type](#facet-type). In the binding
|
||||
pattern `T:! Hashable`, `T` is a facet binding, and the value of `T` is a
|
||||
[facet](#facet).
|
||||
[compile-time binding pattern](#bindings) (using `:!` with or without the
|
||||
`template` modifier) where the declared type is a [facet type](#facet-type). In
|
||||
the binding pattern `T:! Hashable`, `T` is a facet binding, and the value of `T`
|
||||
is a [facet](#facet).
|
||||
|
||||
## Deduced parameter
|
||||
|
||||
@@ -848,9 +848,10 @@ that specifies an array bound might have an integer type.
|
||||
|
||||
## Type constraints
|
||||
|
||||
Type constraints restrict which types are legal for generic parameters or
|
||||
associated facets. They help define semantics under which they should be called,
|
||||
and prevent incorrect calls.
|
||||
Type constraints restrict which types are legal for a
|
||||
[facet binding](#facet-binding), like a facet parameter or associated facet.
|
||||
They help define semantics under which they should be called, and prevent
|
||||
incorrect calls.
|
||||
|
||||
In general there are a number of different type relationships we would like to
|
||||
express, for example:
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
# Reduce ambiguity in terminology
|
||||
|
||||
<!--
|
||||
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/3162)
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Abstract](#abstract)
|
||||
- [Problem](#problem)
|
||||
- [Background](#background)
|
||||
- [Proposal](#proposal)
|
||||
- [Details](#details)
|
||||
- [Rationale](#rationale)
|
||||
- [Alternatives considered](#alternatives-considered)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Abstract
|
||||
|
||||
Change terminology away from terms that are ambiguous:
|
||||
|
||||
- Reserve "generic type" for types with (compile-time) parameters, like
|
||||
`Vector` in `Vector(T:! type)`. Don't use that term to refer to `T`, as it
|
||||
would with [#2360](/proposals/p2360.md#terminology).
|
||||
- Use the term "compile-time" instead of "constant" to mean "template or
|
||||
symbolic." Expand the term "constant" to include values, such as from `let`
|
||||
bindings.
|
||||
|
||||
## Problem
|
||||
|
||||
Right now, the term "generic type" has two meanings. In this example:
|
||||
|
||||
```
|
||||
class Vector(T:! type);
|
||||
```
|
||||
|
||||
Both `Vector` and `T` could be called a "generic type." It would be much less
|
||||
confusing if one of those two would have a different name.
|
||||
|
||||
Similarly, "constant" can currently mean multiple things:
|
||||
|
||||
- "evaluation at compile time," as in "constant evaluation"
|
||||
- "not variable," as in `let` instead of `var`
|
||||
- "non-mutating view," as in `const T*`
|
||||
|
||||
In practice, this has resulted in confusion. For example, the term "constant
|
||||
bindings" doesn't include all `let` bindings, even though they are not variable
|
||||
bindings.
|
||||
|
||||
## Background
|
||||
|
||||
The two meanings of "generic type" come from:
|
||||
|
||||
- Proposal [#2360](/proposals/p2360.md#terminology) defines a generic type to
|
||||
be a type or facet introduced by a `:!` binding, such as in a generic
|
||||
parameter or associated constant.
|
||||
- Other uses of the term generic, such as in generic function, mean a language
|
||||
construct with a compile-time parameter (as in
|
||||
[Rust](https://doc.rust-lang.org/rust-by-example/generics.html)). This is
|
||||
the usage in the broader programming language community, and includes
|
||||
calling parameterized types "generic types" (as in
|
||||
[Java](https://docs.oracle.com/javase/tutorial/java/generics/types.html),
|
||||
[.NET](https://learn.microsoft.com/en-us/dotnet/standard/generics/#terminology),
|
||||
[Swift](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics/#Generic-Types)).
|
||||
|
||||
Issue
|
||||
[#1391: New name for "constant" value phase](https://github.com/carbon-language/carbon-lang/issues/1391)
|
||||
implemented in proposal
|
||||
[#2964: Expression phase terminology](https://github.com/carbon-language/carbon-lang/pull/2964),
|
||||
expanded the term "constant" from referring to just template constants to also
|
||||
include symbolic constants from checked generics. Since then proposal
|
||||
[#2006: Values, variables, pointers, and references](https://github.com/carbon-language/carbon-lang/pull/2006)
|
||||
introduced the `const` modifier on types, providing a read-only view.
|
||||
|
||||
## Proposal
|
||||
|
||||
We make these changes:
|
||||
|
||||
- Reserve "generic type" for types with (compile-time) parameters, like
|
||||
`Vector` in `Vector(T:! type)`. Don't use that term to refer to `T`, as it
|
||||
would with
|
||||
[#2360](https://github.com/carbon-language/carbon-lang/blob/trunk/proposals/p2360.md#terminology).
|
||||
- Expand "constant binding" to include all `let` bindings.
|
||||
- Use the term "compile-time binding" to refer to the collection of template
|
||||
and symbolic bindings, such as from generic parameters and associated
|
||||
constants.
|
||||
- Similarly "compile-time constants" to refer to template and symbolic
|
||||
constants, as opposed to just "constants."
|
||||
- The term "compile-time parameter" may be used instead of "generic
|
||||
parameter." For now, both terms will be used, but in the future it might be
|
||||
clearer to only use "generic" to mean "has compile-time parameters."
|
||||
- Only use "symbolic binding" and "template binding" not "symbolic constant
|
||||
binding" nor "template constant binding."
|
||||
- Where applicable, switch from talking about parameters to bindings, since
|
||||
almost everything that applies to compile-time parameters also applies to
|
||||
compile-time bindings. For example, see
|
||||
["binding patterns"](/docs/design/generics/terminology.md#bindings) and
|
||||
["facet binding"](/docs/design/generics/terminology.md#facet-binding) in the
|
||||
generics terminology doc.
|
||||
|
||||
## Details
|
||||
|
||||
The following design documents have been updated in this proposal to reflect
|
||||
these changes:
|
||||
|
||||
- [Language design overview](/docs/design/README.md)
|
||||
- [Generics terminology](/docs/design/generics/terminology.md)
|
||||
- [Member access expressions](/docs/design/expressions/member_access.md)
|
||||
**FIXME:** Need to sync with
|
||||
[#3162](https://github.com/carbon-language/carbon-lang/pull/3162).
|
||||
|
||||
Some of these changes have already been implemented in:
|
||||
|
||||
- [PR #3048: Update Generics terminology document](https://github.com/carbon-language/carbon-lang/pull/3048)
|
||||
- [PR #3061: Update generics overview](https://github.com/carbon-language/carbon-lang/pull/3061)
|
||||
|
||||
## Rationale
|
||||
|
||||
This proposal advances these goals of Carbon:
|
||||
|
||||
- [Language tools and ecosystem](/docs/project/goals.md#language-tools-and-ecosystem):
|
||||
Having clear and unambiguous terminology is important for making a precise
|
||||
language specification and as well as other design and developer
|
||||
documentation.
|
||||
- [Code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write):
|
||||
particularly the sub-goal that "The behavior and semantics of code should be
|
||||
clearly and simply specified whenever possible."
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
The main alternative considered was the status quo. This was discussed:
|
||||
|
||||
- [starting 2023-Jul-14 in #naming](https://discord.com/channels/655572317891461132/963846118964350976/1129542605538074777)
|
||||
- [2023-Jul-27 in open discussion](https://docs.google.com/document/d/1gnJBTfY81fZYvI_QXjwKk1uQHYBNHGqRLI2BS_cYYNQ/edit?resourcekey=0-ql1Q1WvTcDvhycf8LbA9DQ#heading=h.3tki3lncihf)
|
||||
- [2023-Aug-28 in #naming](https://discord.com/channels/655572317891461132/963846118964350976/1145790947083423777)
|
||||
|
||||
During those discussions, we also considered "symbolic type" instead of "generic
|
||||
type". This did not work out, though, since it conflicted with the term
|
||||
"symbolic" used as an expression phase. We considered other possibilities:
|
||||
"figurative type", "computed type", "hole type", "open type", and "placeholder
|
||||
type" (though that might be better applied to `auto`).
|
||||
|
||||
It also came up that we did not want to use the term "generic binding" to mean a
|
||||
compile-time binding, because that term would be better applied to a
|
||||
parameterized binding, see
|
||||
[#naming on 2023-Jul-31](https://discord.com/channels/655572317891461132/963846118964350976/1135704682128494712).
|
||||
Those are not currently supported in Carbon, but are something we are likely to
|
||||
add. For example,
|
||||
[Rust has generic associated types](https://rust-lang.github.io/generic-associated-types-initiative/explainer/motivation.html)
|
||||
as of [v1.65](https://blog.rust-lang.org/2022/10/28/gats-stabilization.html).
|
||||
Reference in New Issue
Block a user