mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 15:10:12 +01:00
Generics overview (#524)
This adds an overview of a generics feature that attempts to achieve the goals from #24 . It has been summarized in these presentations: - [non-type params](https://docs.google.com/presentation/d/1IZaDxP5Y3Wqprkyjzagv48tyxEeIcfz8FZS3Namsvew/edit#slide=id.p) - [basic usage](https://docs.google.com/presentation/d/1OZiMTVW2Ommop5WTs9RyEwnGxy9yzaAPF7Cj5KUfDsY/edit?resourcekey=0-Nya0Soz3ZNs3hJan8VIrTA#slide=id.p) - [more advanced usage](https://docs.google.com/presentation/d/1bg6q0Q9Sk4YpRbNA3D3H34xYtaEO8ScAUNUZK2UTi80/edit?resourcekey=0-6-Y6e1mfRUmHg-Zk65Gc5A#slide=id.p) Co-authored-by: Jon Meow <46229924+jonmeow@users.noreply.github.com> Co-authored-by: Chandler Carruth <chandlerc@gmail.com> Co-authored-by: Wolff Dobson <wolffg@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
Jon Meow
Chandler Carruth
Wolff Dobson
parent
8082791c54
commit
978e27f484
@@ -9,7 +9,9 @@ SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
This directory contains the collection of documents describing the generics
|
||||
feature of Carbon:
|
||||
|
||||
- ~~Overview~~ - not implemented yet
|
||||
- [Overview](overview.md) - A high-level description of the generics design,
|
||||
with pointers to other design documents that dive deeper into individual
|
||||
topics.
|
||||
- [Goals](goals.md) - The motivation and principles guiding the design
|
||||
direction.
|
||||
- [Terminology](terminology.md) - A glossary establishing common terminology
|
||||
|
||||
@@ -0,0 +1,506 @@
|
||||
# Carbon generics overview
|
||||
|
||||
<!--
|
||||
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
|
||||
-->
|
||||
|
||||
This document is a high-level description of Carbon's generics design, with
|
||||
pointers to other design documents that dive deeper into individual topics.
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [Goals](#goals)
|
||||
- [Summary](#summary)
|
||||
- [What are generics?](#what-are-generics)
|
||||
- [Interfaces](#interfaces)
|
||||
- [Defining interfaces](#defining-interfaces)
|
||||
- [Contrast with templates](#contrast-with-templates)
|
||||
- [Implementing interfaces](#implementing-interfaces)
|
||||
- [Qualified and unqualified access](#qualified-and-unqualified-access)
|
||||
- [Type-of-types](#type-of-types)
|
||||
- [Generic functions](#generic-functions)
|
||||
- [Deduced parameters](#deduced-parameters)
|
||||
- [Generic type parameters](#generic-type-parameters)
|
||||
- [Requiring or extending another interface](#requiring-or-extending-another-interface)
|
||||
- [Combining interfaces](#combining-interfaces)
|
||||
- [Structural interfaces](#structural-interfaces)
|
||||
- [Type erasure](#type-erasure)
|
||||
- [Future work](#future-work)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Goals
|
||||
|
||||
The goal of Carbon generics is to provide an alternative to Carbon (or C++)
|
||||
templates. Generics in this form should provide many advantages, including:
|
||||
|
||||
- Function calls and bodies are checked independently against the function
|
||||
signatures.
|
||||
- Clearer and earlier error messages.
|
||||
- Fast builds, particularly development builds.
|
||||
- Support for both static and dynamic dispatch.
|
||||
|
||||
For more detail, see [the detailed discussion of generics goals](goals.md) and
|
||||
[generics terminology](terminology.md).
|
||||
|
||||
## Summary
|
||||
|
||||
Summary of how Carbon generics work:
|
||||
|
||||
- _Generics_ are parameterized functions and types that can apply generally.
|
||||
They are used to avoid writing specialized, near-duplicate code for similar
|
||||
situations.
|
||||
- Generics are written using _interfaces_ which have a name and describe
|
||||
methods, functions, and other items for types to implement.
|
||||
- Types must explicitly _implement_ interfaces to indicate that they support
|
||||
its functionality. A given type may implement an interface at most once.
|
||||
- Implementations may be part of the type's definition, in which case you can
|
||||
directly call the interface's methods on those types. Or, they may be
|
||||
external, in which case the implementation is allowed to be defined in the
|
||||
library defining the interface.
|
||||
- Interfaces are used as the type of a generic type parameter, acting as a
|
||||
_type-of-type_. Type-of-types in general specify the capabilities and
|
||||
requirements of the type. Types define specific implementations of those
|
||||
capabilities. Inside such a generic function, the API of the type is
|
||||
[erased](terminology.md#type-erasure), except for the names defined in the
|
||||
type-of-type.
|
||||
- _Deduced parameters_ are parameters whose values are determined by the
|
||||
values and (most commonly) the types of the explicit arguments. Generic type
|
||||
parameters are typically deduced.
|
||||
- A function with a generic type parameter can have the same function body as
|
||||
an unparameterized one. Functions can freely mix generic, template, and
|
||||
regular parameters.
|
||||
- Interfaces can require other interfaces be implemented, or
|
||||
[extend](terminology.md#extendingrefining-an-interface) them.
|
||||
- The `&` operation on type-of-types allows you conveniently combine
|
||||
interfaces. It gives you all the names that don't conflict.
|
||||
- You may also declare a new type-of-type directly using
|
||||
["structural interfaces"](terminology.md#structural-interfaces). Structural
|
||||
interfaces can express requirements that multiple interfaces be implemented,
|
||||
and give you control over how name conflicts are handled.
|
||||
- Alternatively, you may resolve name conflicts by using a qualified syntax to
|
||||
directly call a function from a specific interface.
|
||||
|
||||
## What are generics?
|
||||
|
||||
Generics are a mechanism for writing parameterized code that applies generally
|
||||
instead of making near-duplicates for very similar situations, much like C++
|
||||
templates. For example, instead of having one function per type-you-can-sort:
|
||||
|
||||
```
|
||||
fn SortInt32Vector(a: Vector(Int32)*) { ... }
|
||||
fn SortStringVector(a: Vector(String)*) { ... }
|
||||
...
|
||||
```
|
||||
|
||||
You might have one generic function that could sort any array with comparable
|
||||
elements:
|
||||
|
||||
```
|
||||
fn SortVector(T:$ Comparable, a: Vector(T)*) { ... }
|
||||
```
|
||||
|
||||
The syntax above adds a `$` to indicate that the parameter named `T` is generic.
|
||||
|
||||
Given an `Int32` vector `iv`, `SortVector(Int32, &iv)` is equivalent to
|
||||
`SortInt32Vector(&iv)`. Similarly for a `String` vector `sv`,
|
||||
`SortVector(String, &sv)` is equivalent to `SortStringVector(&sv)`. Thus, we can
|
||||
sort any vector containing comparable elements using this single `SortVector`
|
||||
function.
|
||||
|
||||
This ability to generalize makes `SortVector` a _generic_.
|
||||
|
||||
**NOTE:** The `$` syntax is a placeholder. The syntax is being decided in
|
||||
[question-for-leads issue #565](https://github.com/carbon-language/carbon-lang/issues/565).
|
||||
|
||||
### Interfaces
|
||||
|
||||
The `SortVector` function requires a definition of `Comparable`, with the goal
|
||||
that the compiler can:
|
||||
|
||||
- completely type check a generic definition without information from where
|
||||
it's called.
|
||||
- completely type check a call to a generic with information only from the
|
||||
function's signature, and not from its body.
|
||||
|
||||
In this example, then, `Comparable` is an _interface_.
|
||||
|
||||
Interfaces describe all the requirements needed for the type `T`. Given that the
|
||||
compiler knows `T` satisfies those requirements, it can type check the body of
|
||||
the `SortVector` function. This includes checking that the `Comparable`
|
||||
requirement covers all of the uses of `T` inside the function.
|
||||
|
||||
Later, when the compiler comes across a call to `SortVector`, it can type check
|
||||
against the requirements expressed in the function's signature. Using only the
|
||||
types at the call site, the compiler can check that the member elements of the
|
||||
passed-in array satisfy the function's requirements. There is no need to look at
|
||||
the body of the `SortVector` function, since we separately checked that those
|
||||
requirements were sufficient.
|
||||
|
||||
#### Defining interfaces
|
||||
|
||||
Interfaces, then, have a name and describe methods, functions, and other items
|
||||
for types to implement.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
interface Comparable {
|
||||
// Placeholder method syntax
|
||||
// `Less` is an associated method.
|
||||
method (this: Self) Less(that: Self) -> Bool;
|
||||
}
|
||||
```
|
||||
|
||||
[Question-for-leads issue #494](https://github.com/carbon-language/carbon-lang/issues/494)
|
||||
is on method syntax.
|
||||
|
||||
Interfaces describe functionality, but not data; no variables may be declared in
|
||||
an interface.
|
||||
|
||||
#### Contrast with templates
|
||||
|
||||
Contrast these generics with a C++ template, where the compiler may be able to
|
||||
do some checking given a function definition, but more checking of the
|
||||
definition is required after seeing the call sites once all the
|
||||
[instantiations](terminology.md#instantiation) are known.
|
||||
|
||||
Note: The doc on [Generics terminology](terminology.md) goes into more detail
|
||||
about the
|
||||
[differences between generics and templates](terminology.md#generic-versus-template-parameters).
|
||||
|
||||
### Implementing interfaces
|
||||
|
||||
Interfaces themselves only describe functionality by way of method descriptions.
|
||||
A type needs to _implement_ an interface to indicate that it supports its
|
||||
functionality. A given type may implement an interface at most once.
|
||||
|
||||
Consider this interface:
|
||||
|
||||
```
|
||||
interface Printable {
|
||||
method (this: Self) Print();
|
||||
}
|
||||
```
|
||||
|
||||
The `interface` keyword is used to define a
|
||||
[_nominal interface_](terminology.md#nominal-interfaces). That means that types
|
||||
need to explicitly implement them, using an `impl` block, such as here:
|
||||
|
||||
```
|
||||
struct Song {
|
||||
// ...
|
||||
|
||||
// Implementing `Printable` for `Song` inside the definition of `Song`
|
||||
// means all names of `Printable`, such as `F`, are included as a part
|
||||
// of the `Song` API.
|
||||
impl as Printable {
|
||||
// Could use `Self` in place of `Song` here.
|
||||
method (this: Song) Print() { ... }
|
||||
}
|
||||
}
|
||||
|
||||
// Implement `Comparable` for `Song` without changing the API of `Song`
|
||||
// using an `external impl` declaration. This may be defined in either
|
||||
// the library defining `Song` or `Comparable`.
|
||||
external impl Song as Comparable {
|
||||
// Could use either `Self` or `Song` here.
|
||||
method (this: Self) Less(that: Self) -> Bool { ... }
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** The interface implementation syntax was decided in
|
||||
[question-for-leads issue #575](https://github.com/carbon-language/carbon-lang/issues/575).
|
||||
TODO: move this to details and link.
|
||||
|
||||
Implementations may be defined within the struct definition itself or
|
||||
externally. External implementations may be defined in the library defining the
|
||||
interface.
|
||||
|
||||
#### Qualified and unqualified access
|
||||
|
||||
The methods of an interface implemented within the struct definition may be
|
||||
called with the unqualified syntax. All methods of implemented interfaces may be
|
||||
called with the qualified syntax, whether they are defined internally or
|
||||
externally.
|
||||
|
||||
```
|
||||
var song: Song;
|
||||
// `song.Print()` is allowed, unlike `song.Play()`.
|
||||
song.Print();
|
||||
// `Less` is defined in `Comparable`, which is implemented
|
||||
// externally for `Song`
|
||||
song.(Comparable.Less)(song);
|
||||
// Can also call `Print` using the qualified syntax:
|
||||
song.(Printable.Print)();
|
||||
```
|
||||
|
||||
### Type-of-types
|
||||
|
||||
To type check a function, the compiler needs to be able to verify that uses of a
|
||||
value match the capabilities of the value's type. In `SortVector`, the parameter
|
||||
`T` is a type, but that type is a generic parameter. That means that the
|
||||
specific type value assigned to `T` is not known when type checking the
|
||||
`SortVector` function. Instead it is the constraints on `T` that let the
|
||||
compiler know what operations may be performed on values of type `T`. Those
|
||||
constraints are represented by the type of `T`, a
|
||||
[**_type-of-type_**](terminology.md#type-constraints).
|
||||
|
||||
In general, a type-of-type describes the capabilities of a type, while a type
|
||||
defines specific implementations of those capabilities.
|
||||
|
||||
An interface, like `Comparable`, may be used as a type-of-type. In that case,
|
||||
the constraint on the type is that it must implement the interface `Comparable`.
|
||||
A type-of-type also defines a set of names and a mapping to corresponding
|
||||
qualified names. You may combine interfaces into new type-of-types using
|
||||
[the `&` operator](#combining-interfaces) or
|
||||
[structural interfaces](#structural-interfaces).
|
||||
|
||||
### Generic functions
|
||||
|
||||
We want to be able to call generic functions just like ordinary functions, and
|
||||
write generic function bodies like ordinary functions. There are only a few
|
||||
differences, like that you can't take the address of generic functions.
|
||||
|
||||
#### Deduced parameters
|
||||
|
||||
This `SortVector` function is explicitly providing type information that is
|
||||
already included in the type of the second argument. To eliminate the argument
|
||||
at the call site, use a _deduced parameter_.
|
||||
|
||||
```
|
||||
fn SortVectorDeduced[T:$ Comparable](a: Vector(T)*) { ... }
|
||||
```
|
||||
|
||||
The `T` parameter is defined in square brackets before the explicit parameter
|
||||
list in parenthesis to indicate it should be deduced. This means you may call
|
||||
the function without the type argument, just like the ordinary functions
|
||||
`SortInt32Vector` or `SortStringVector`:
|
||||
|
||||
```
|
||||
SortVectorDeduced(&anIntVector);
|
||||
// or
|
||||
SortVectorDeduced(&aStringVector);
|
||||
```
|
||||
|
||||
and the compiler deduces that the `T` argument should be set to `Int32` or
|
||||
`String` from the type of the argument.
|
||||
|
||||
Deduced arguments are always determined from the call and its explicit
|
||||
arguments. There is no syntax for specifying deduced arguments directly at the
|
||||
call site.
|
||||
|
||||
```
|
||||
// ERROR: can't determine `U` from explicit parameters
|
||||
fn Illegal[Type:$ T, Type:$ U](x: T) -> U { ... }
|
||||
```
|
||||
|
||||
#### Generic type parameters
|
||||
|
||||
A function with a generic type parameter can have the same function body as an
|
||||
unparameterized one.
|
||||
|
||||
```
|
||||
fn PrintIt[T:$ Printable](p: T*) {
|
||||
p->Print();
|
||||
}
|
||||
|
||||
fn PrintIt(p: Song*) {
|
||||
p->Print();
|
||||
}
|
||||
```
|
||||
|
||||
Inside the function body, you can treat the generic type parameter just like any
|
||||
other type. There is no need to refer to or access generic parameters
|
||||
differently because they are defined as generic, as long as you only refer to
|
||||
the names defined by [type-of-type](#type-of-types) for the type parameter.
|
||||
|
||||
You may also refer to any of the methods of interfaces required by the
|
||||
type-of-type using the [qualified syntax](#qualified-and-unqualified-access), as
|
||||
shown in the following sections.
|
||||
|
||||
A function can have a mix of generic, template, and regular parameters.
|
||||
Likewise, it's allowed to pass a template or generic value to a generic or
|
||||
regular parameter. _However, passing a generic value to a template parameter is
|
||||
future work._
|
||||
|
||||
### Requiring or extending another interface
|
||||
|
||||
Interfaces can require other interfaces be implemented:
|
||||
|
||||
```
|
||||
interface Equatable {
|
||||
method (this: Self) IsEqual(that: Self) -> Bool;
|
||||
}
|
||||
|
||||
// `Iterable` requires that `Equatable` is implemented.
|
||||
interface Iterable {
|
||||
impl as Equatable;
|
||||
method (this: Self*) Advance();
|
||||
}
|
||||
```
|
||||
|
||||
The `extends` keyword is used to
|
||||
[extend](terminology.md#extendingrefining-an-interface) another interface. If
|
||||
interface `Child` extends interface `Parent`, `Parent`'s interface is both
|
||||
required and all its methods are included in `Child`'s interface.
|
||||
|
||||
```
|
||||
// `Hashable` extends `Equatable`.
|
||||
interface Hashable {
|
||||
extends Equatable;
|
||||
method (this: Self) Hash() -> UInt64;
|
||||
}
|
||||
// `Hashable` is equivalent to:
|
||||
interface Hashable {
|
||||
impl as Equatable;
|
||||
alias IsEqual = Equatable.IsEqual;
|
||||
method (this: Self) Hash() -> UInt64;
|
||||
}
|
||||
```
|
||||
|
||||
A type may implement the parent interface implicitly by implementing all the
|
||||
methods in the child implementation.
|
||||
|
||||
```
|
||||
struct Key {
|
||||
// ...
|
||||
impl as Hashable {
|
||||
method (this: Key) IsEqual(that: Key) -> Bool { ... }
|
||||
method (this: Key) Hash() -> UInt64 { ... }
|
||||
}
|
||||
// No need to separately implement `Equatable`.
|
||||
}
|
||||
var k: Key = ...;
|
||||
k.Hash();
|
||||
k.IsEqual(k);
|
||||
```
|
||||
|
||||
### Combining interfaces
|
||||
|
||||
The `&` operation on type-of-types allows you conveniently combine interfaces.
|
||||
It gives you all the names that don't conflict.
|
||||
|
||||
```
|
||||
interface Renderable {
|
||||
method (this: Self) GetCenter() -> (Int, Int);
|
||||
// Draw the object to the screen
|
||||
method (this: Self) Draw();
|
||||
}
|
||||
interface EndOfGame {
|
||||
method (this: Self*) SetWinner(player: Int);
|
||||
// Indicate the game was a draw
|
||||
method (this: Self*) Draw();
|
||||
}
|
||||
|
||||
fn F[T:$ Renderable & EndOfGame](game_state: T*) -> (Int, Int) {
|
||||
game_state->SetWinner(1);
|
||||
return game_state->Center();
|
||||
}
|
||||
```
|
||||
|
||||
Names with conflicts can be accessed using the
|
||||
[qualified syntax](#qualified-and-unqualified-access).
|
||||
|
||||
```
|
||||
fn BothDraws[T:$ Renderable & EndOfGame](game_state: T*) {
|
||||
game_state->(Renderable.Draw)();
|
||||
game_state->(GameState.Draw)();
|
||||
}
|
||||
```
|
||||
|
||||
#### Structural interfaces
|
||||
|
||||
You may also declare a new type-of-type directly using
|
||||
["structural interfaces"](terminology.md#structural-interfaces). Structural
|
||||
interfaces can express requirements that multiple interfaces be implemented, and
|
||||
give you control over how name conflicts are handled. Structural interfaces have
|
||||
other applications and capabilities not covered here.
|
||||
|
||||
```
|
||||
structural interface Combined {
|
||||
impl as Renderable;
|
||||
impl as EndOfGame;
|
||||
alias Draw_Renderable = Renderable.Draw;
|
||||
alias Draw_EndOfGame = EndOfGame.Draw;
|
||||
alias SetWinner = EndOfGame.SetWinner;
|
||||
}
|
||||
|
||||
fn CallItAll[T:$ Combined](game_state: T*, int winner) {
|
||||
if (winner > 0) {
|
||||
game_state->SetWinner(winner);
|
||||
} else {
|
||||
game_state->Draw_EndOfGame();
|
||||
}
|
||||
game_state->Draw_Renderable();
|
||||
// Can still use qualified syntax for names
|
||||
// not defined in the structural interface
|
||||
return game_state->(Renderable.Center)();
|
||||
}
|
||||
```
|
||||
|
||||
#### Type erasure
|
||||
|
||||
Inside a generic function, the API of a type argument is
|
||||
[erased](terminology.md#type-erasure) except for the names defined in the
|
||||
type-of-type.
|
||||
|
||||
For example: If there were a class `CDCover` defined this way:
|
||||
|
||||
```
|
||||
struct CDCover {
|
||||
impl as Printable {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
it can be passed to this `PrintIt` function:
|
||||
|
||||
```
|
||||
fn PrintIt[T:$ Printable](p: T*) {
|
||||
p->Print();
|
||||
}
|
||||
```
|
||||
|
||||
At that point, two erasures occur:
|
||||
|
||||
- All of `CDCover`'s API _except_ `Printable` is erased during the cast from
|
||||
`CDCover` to `Printable`, which is the [facet](terminology.md#facets) type
|
||||
`CDCover as Printable`.
|
||||
- When you call `PrintIt`, the type connection to `CDCover` is lost. Outside
|
||||
of `PrintIt` you can cast a `CDCover as Printable` value back to `CDCover`.
|
||||
Inside of `PrintIt`, you can't cast `p` or `T` back to `CDCover`.
|
||||
|
||||
## Future work
|
||||
|
||||
- Be able to have non-type generic parameters like the `UInt` size of an array
|
||||
or tuple.
|
||||
- A "newtype" mechanism called "adapting types" may be provided to create new
|
||||
types that are compatible with existing types but with different interface
|
||||
implementations. This could be used to add or replace implementations, or
|
||||
define implementations for reuse.
|
||||
- Associated types and interface parameters will be provided to allow function
|
||||
signatures to vary with the implementing type. The biggest difference
|
||||
between these is that associated types ("output types") may be deduced from
|
||||
a type, and types can implement the same interface multiple times with
|
||||
different interface parameters ("input types").
|
||||
- Other kinds of constraints will be finalized.
|
||||
- Implementations can be parameterized to apply to multiple types. These
|
||||
implementations would be restricted to various conditions are true for the
|
||||
parameters. When there are two implementations that can apply, there is a
|
||||
specialization rule that picks the more specific one.
|
||||
- Support functions should have a way to accept types that types that vary at
|
||||
runtime.
|
||||
- You should have the ability to mark items as `upcoming` or `deprecated` to
|
||||
support evolution.
|
||||
- Types should be able to define overloads for operators by implementing
|
||||
standard interfaces.
|
||||
- There should be a way to provide default implementations of methods in
|
||||
interfaces and other ways to reuse code across implementations.
|
||||
- There should be a way to define generic associated and higher-ranked/kinded
|
||||
types.
|
||||
@@ -55,6 +55,7 @@ request:
|
||||
- [0438 - Functions](p0438.md)
|
||||
- [0444 - GitHub Discussions](p0444.md)
|
||||
- [0447 - Generics terminology](p0447.md)
|
||||
- [0524 - Generics overview](p0524.md)
|
||||
- [0538 - `return` with no argument](p0538.md)
|
||||
- [0555 - Operator precedence](p0555.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Generics overview
|
||||
|
||||
<!--
|
||||
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/524)
|
||||
|
||||
<!-- 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)
|
||||
|
||||
<!-- tocstop -->
|
||||
|
||||
## Problem
|
||||
|
||||
We want to Carbon to have a high quality generics feature that achieves the
|
||||
goals set out in [#24](https://github.com/carbon-language/carbon-lang/pull/24).
|
||||
This is too big a feature to land in a single proposal. This proposal specifies
|
||||
the feature at the level of an overview description. This overview document is
|
||||
intended to act as a starting point for people interested in the generics
|
||||
feature by providing:
|
||||
|
||||
- a high-level description of the generics feature, and
|
||||
- pointers to documents that go deeper into individual topics.
|
||||
|
||||
## Background
|
||||
|
||||
This is a follow on to these previous generics proposals:
|
||||
|
||||
- [Generics goals #24](https://github.com/carbon-language/carbon-lang/pull/24)
|
||||
- [Generics terminology #447](https://github.com/carbon-language/carbon-lang/pull/447)
|
||||
|
||||
The content for this proposal was extracted from a larger
|
||||
[Generics combined draft proposal](https://github.com/carbon-language/carbon-lang/pull/36).
|
||||
|
||||
## Proposal
|
||||
|
||||
This is a proposal to add
|
||||
[this overview document](/docs/design/generics/overview.md).
|
||||
|
||||
## Rationale based on Carbon's goals
|
||||
|
||||
Much of this rationale was captured in the
|
||||
[Generics goals proposal](https://github.com/carbon-language/carbon-lang/pull/24).
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
Alternatives considered will be in a future proposal. Some of them can be seen
|
||||
in a rough form in
|
||||
[#36](https://github.com/carbon-language/carbon-lang/pull/36).
|
||||
Reference in New Issue
Block a user