diff --git a/docs/project/principles/static_open_extension.md b/docs/project/principles/static_open_extension.md new file mode 100644 index 000000000000..efa30a0e7dc2 --- /dev/null +++ b/docs/project/principles/static_open_extension.md @@ -0,0 +1,89 @@ +# Principle: One static open extension mechanism + + + + + +## Table of contents + +- [Background](#background) +- [Principle](#principle) +- [Alternatives considered](#alternatives-considered) + + + +## Background + +In C++, a single function may be overloaded with definitions in multiple files. +The [ADL](https://en.wikipedia.org/wiki/Argument-dependent_name_lookup) name +lookup rule even allows an unqualified call to resolve to functions defined in +different namespaces. These rules are used to define extension points with +static dispatch for operator overloading and functions like +[`swap`](https://www.cplusplus.com/reference/algorithm/swap/). + +Nothing in C++ restricts the signatures of function overloads. This means that +if overloading is used as an extension point to define an operation for a +variety of types, there is no way to type check generic code that tries to +invoke that operation over those types. + +Further, in C++, all non-member functions can be found in this way, if they are +declared in the same namespace as a type that could be associated with an +argument list in a call. There is no straightforward opt-out mechanism in a +function declaration, and while there are opt-out mechanisms at call sites, they +are rarely used. As a consequence, many non-member functions with the same name +can form part of an overload set, even if they provide unrelated functionality, +and there is no indication in the code of which functions in different +namespaces are intended to expose the same capability. + +## Principle + +In Carbon, [`interface`s](/docs/design/generics/overview.md) are the only static +open extension mechanism. + +Each type may define its own implementation of each interface. Generic code can +be written that works with any type implementing the interface. That code can be +type checked independent of which type the generic code is instantiated with by +using the fact that the interface specifies the signatures of the calls. + +To keep the language simple, this is the only static open extension mechanism in +Carbon. This means that function overloading is limited in Carbon to only +signatures defined together in the same library. It also means that to +interoperate with C++, the operators and `swap` need to have corresponding +interfaces on the Carbon side. + +The main advantage of interfaces as an open extension mechanism over open +overloading is allowing generics to be type checked separately. In addition, +they are less [context sensitive](low_context_sensitivity.md). Generics are +[coherent](/docs/design/generics/terminology.md#coherence), while open function +overloading can resolve names differently depending on what is imported. Closed +overloading in Carbon also simplifies what gets exported to C++ from Carbon. +Interface implementations express intent by being explicit, in contrast to how +adding a function to a cross-file overload set can be accidental. + +Interfaces provide an way to group functions together, and express the +constraint that all of the functions in the group are implemented. Consider a +random-access iterator, which has a number of methods. If a C++ template +function only accesses some of those methods which happens to match the subset +defined for a type, the code will work temporarily but fail later when the code +is changed to use a different subset. + +This helps achieve the Carbon Goal of +[code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write). + +## Alternatives considered + +Another approach to operator overloading is to use methods with a specific name. +In C++ these start with the +[`operator` keyword](https://en.cppreference.com/w/cpp/language/operators). +[Python uses method with names starting and ending with double underscores](https://docs.python.org/3/reference/datamodel.html#special-method-names). +Interfaces are more flexible about where implementations may be defined. For +example, with special method names, `+` on a `Vector(T)` class could only be +defined as part of the `Vector(T)` definition. With interfaces, additionally `+` +for `Vector(MyType)` could be implemented with `MyType`. C++ provides this +flexibility by also permitting non-method operator overloads, but this brings +with it the cost of selecting a best-matching operator from a potentially very +large open overload set. diff --git a/proposals/p0998.md b/proposals/p0998.md new file mode 100644 index 000000000000..b0998b375ab6 --- /dev/null +++ b/proposals/p0998.md @@ -0,0 +1,58 @@ +# Principle: One static open extension mechanism + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/998) + + + +## Table of contents + +- [Problem](#problem) +- [Proposal](#proposal) +- [Details](#details) +- [Rationale based on Carbon's goals](#rationale-based-on-carbons-goals) +- [Alternatives considered](#alternatives-considered) + + + +## Problem + +There are a few ways of approaching open extension, such as defining how +operators are overload for every type. For Carbon, with its +[focus on performance](/docs/project/goals.md#performance-critical-software), we +are particularly interested in those that support static dispatch, to avoid the +runtime overhead of dynamic dispatch. The three main options are: + +- Open function overloading, where new overloads for a given name can be + defined broadly, as is done in C++. +- Interfaces, as is done in + [Rust](https://doc.rust-lang.org/rust-by-example/trait/ops.html). +- Special method names, as are used in + [C++](https://en.cppreference.com/w/cpp/language/operators) and + [Python](https://docs.python.org/3/reference/datamodel.html#special-method-names). + +We would prefer to use a single mechanism, if possible, for simplicity. + +## Proposal + +Proposal is to use interfaces as the single open extension mechanism. + +## Details + +Details are in the added principle doc: +[docs/project/principles/static_open_extension.md](docs/project/principles/static_open_extension.md). + +## Rationale based on Carbon's goals + +This proposal is pursuing Carbon's goal of having +[code that is easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write). + +## Alternatives considered + +Early arguments for this approach were put forth in +[this document](https://docs.google.com/document/d/1uvX_hmw5DVs1SFjnehUUizGnI6C099vqIGfUhfCwBIo/edit#).