From bc40bdc279f871fb0edb2ba9225dfcc1fa6500f4 Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Mon, 13 Jun 2022 13:10:43 -0700 Subject: [PATCH] Principle: All APIs are library APIs (#1280) Co-authored-by: Chandler Carruth Co-authored-by: Richard Smith --- docs/project/principles/library_apis_only.md | 104 +++++++++++++++++++ proposals/p1280.md | 84 +++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 docs/project/principles/library_apis_only.md create mode 100644 proposals/p1280.md diff --git a/docs/project/principles/library_apis_only.md b/docs/project/principles/library_apis_only.md new file mode 100644 index 000000000000..7029b4a49e68 --- /dev/null +++ b/docs/project/principles/library_apis_only.md @@ -0,0 +1,104 @@ +# Principle: All APIs are library APIs + + + + + +## Table of contents + +- [Background](#background) +- [Principle](#principle) +- [Applications of this principle](#applications-of-this-principle) +- [Exceptions](#exceptions) +- [Alternatives considered](#alternatives-considered) + + + +## Background + +Every major modern programming language comes with a standard library, which +consists of APIs that are not part of the core language, but instead are written +in the language (although their implementations may not be). However, different +languages draw the boundary between language and library in different places. +For example, Go's `map` type is built into the core language, whereas the C++ +equivalent, `std::unordered_map`, is part of the standard library. In Swift, +even fundamental types like integers and pointers are part of the standard +library; there are no truly "built in" types. + +These decisions can have important consequences for the design of the language. +For example, many important features of C++, such as move semantics, variadics, +and coroutines, were motivated largely by their anticipated uses in a small set +of standard library types. In a language with a different design philosophy, +those types could have been built into the core language. This would probably +have substantially simplified the language, and made those types available +faster. However, that would have come at the cost of less flexibility for users +outside the common case. + +## Principle + +In Carbon, every public function is declared in some Carbon `api` file, and +every public `interface`, `impl`, and first-class type is defined in some Carbon +`api` file. In some cases, the bodies of public functions will not be defined as +Carbon code, or will be defined as hybrid Carbon code using intrinsics that +aren't available to ordinary Carbon code. However, we will try to minimize those +situations. + +Thus, even "built-in" APIs can be used like user-defined APIs, by importing the +appropriate library and using qualified names from that library, relying on the +ordinary semantic rules for Carbon APIs. + +## Applications of this principle + +We expect Carbon to have a special "prelude" library that is implicitly imported +by all Carbon source files, and there might be a special name lookup rule to +allow the names in the prelude to be used unqualified. However, in accordance +with this principle, they will remain available to ordinary qualified name +lookup as well. + +According to the resolutions of +[#543](https://github.com/carbon-language/carbon-lang/issues/543) and +[#750](https://github.com/carbon-language/carbon-lang/issues/543), Carbon will +have a substantial number of type keywords, such as `i32`, `f64`, and `bool`. +However, these keywords will all be aliases for ordinary type names, such as +`Carbon.Int(32)`, `Carbon.Float(64)`, and `Carbon.Bool`. Furthermore, all +arithmetic and logical operators will be overloadable, so that those types can +be defined as class types. The member function bodies for these types will be +probably not be implemented in Carbon, but this principle applies only to +function declarations, not function definitions. + +Similarly, a pointer type such as `Foo*` will be an alias for some library class +type, for example `Carbon.Ptr(Foo)`. As a result, Carbon will support +overloading pointer operations like `->` and unary `*`. + +All Carbon operations that use function-style syntax, such as `sizeof()` and +`decltype()` in C++, will be standard library functions. As above, in some cases +we may choose to alias those functions with keywords, and the function bodies +may not be defined in Carbon. + +## Exceptions + +This principle applies to types only if they are _first-class_, meaning that +they can be the types of run-time variables, function parameters, and return +values. Carbon's type system will probably also include some types whose usage +is more restricted, and this principle will not apply to them. Most importantly, +function types might not be first-class types, in which case they need not be +library types. + +The logic for translating a literal expression to a value of the appropriate +type is arguably part of that type's public API, but will not be part of that +type's class definition. + +Tuple types will probably not fully conform to this principle, because doing so +would be circular: there is no way to name a tuple type that doesn't rely on +tuple syntax, and no way to define a class body for a tuple type that doesn't +contain tuple patterns. However, we will strive to ensure that it is possible to +define a parameterized class type within Carbon that supports all the same +operations as built-in tuple types. + +## Alternatives considered + +- [Built-in primitive types](/proposals/p1280.md#built-in-primitive-types) diff --git a/proposals/p1280.md b/proposals/p1280.md new file mode 100644 index 000000000000..3451dabdc609 --- /dev/null +++ b/proposals/p1280.md @@ -0,0 +1,84 @@ +# Principle: All APIs are library APIs + + + +[Pull request](https://github.com/carbon-language/carbon-lang/pull/1280) + + + +## Table of contents + +- [Problem](#problem) +- [Background](#background) +- [Proposal](#proposal) +- [Details](#details) +- [Rationale](#rationale) +- [Alternatives considered](#alternatives-considered) + - [Built-in primitive types](#built-in-primitive-types) + + + +## Problem + +We need a clear and consistent "division of labor" between the core language and +the standard library. + +## Background + +See +[the principle doc](/docs/project/principles/library_apis_only.md#background). + +See also [#57](https://github.com/carbon-language/carbon-lang/pull/57), a +previous iteration of a similar idea. + +## Proposal + +In Carbon, every public function will be declared in some Carbon `api` file, and +every public `interface`, `impl`, and first-class type will be defined in some +Carbon `api` file. In some cases, the bodies of public functions will not be +defined as Carbon code, or will be defined as hybrid Carbon code using +intrinsics that aren't available to ordinary Carbon code. However, we will try +to minimize those situations. + +Thus, even "built-in" APIs can be used like user-defined APIs, by importing the +appropriate library and using qualified names from that library, relying on the +ordinary semantic rules for Carbon APIs. + +## Details + +See [the principle doc](/docs/project/principles/library_apis_only.md). + +## Rationale + +This principle facilitates +[software evolution](/docs/project/goals.md#software-and-language-evolution), by +helping to ensure that code written in terms of a Carbon-provided type can be +migrated to use a suitable user-defined type instead. It also facilitates +evolution of the language itself, by enabling more of that evolution to take +place in library code, which doesn't require compiler expertise. + +This principle helps make Carbon code +[easy to read, understand, and write](/docs/project/goals.md#code-that-is-easy-to-read-understand-and-write), +because user-defined APIs can match the ergonomics of language-defined APIs, and +the syntax, language rules, and core concepts are consistent between the two. + +This principle indirectly helps Carbon support +[performance-critical software](/docs/project/goals.md#performance-critical-software): +by using Carbon's API abstraction mechanisms for even the most fundamental +types, we ensure that those mechanisms do not impose any performance overhead. + +## Alternatives considered + +### Built-in primitive types + +We could follow the general outline of C++, where arithmetic and pointer types +are built-in. However, that would substantially erode the advantages outlined +above. We expect Carbon to have multiple kinds of pointers (for example, to +represent different kinds of ownership), and multiple kinds of arithmetic types +(for example, to handle overflow in different ways). They can't all be built-in, +so putting even the common-case types in the library helps ensure that Carbon +has enough expressive power for the uncommon-case library types.