Kaynağa Gözat

Principle: Errors are values (#301)

A Carbon function that needs to report recoverable failures should return a sum type whose alternatives represent the success case and failure cases, such as Optional(T), Result(T, Error), or Bool. The function's successful return
value, and any metadata about the failure, should be embedded in the alternatives of the sum type, rather than reported by way of output parameters or other side channels. Carbon's design will prioritize making this form of error handling efficient and ergonomic.

Co-authored-by: josh11b <josh11b@users.noreply.github.com>
Geoff Romer 5 yıl önce
ebeveyn
işleme
6639a915dc

+ 54 - 0
docs/project/principles/error_handling.md

@@ -0,0 +1,54 @@
+# Principle: Errors are values
+
+<!--
+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
+-->
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Background](#background)
+-   [Principle](#principle)
+-   [Applications of these principles](#applications-of-these-principles)
+
+<!-- tocstop -->
+
+## Background
+
+Most nontrivial programs contain functions that can _fail_, meaning that even if
+all their preconditions are met, they may not be able to perform their primary
+behavior. For example, a function that reads data from a remote server may fail
+if the server is unreachable, and a function that parses a string to return an
+integer may fail if the input string is not a properly-formatted integer.
+
+In many cases, the function author wants these failures to be _recoverable_,
+meaning that a direct or transitive caller can respond to the failure in some
+way that enables the program to continue running.
+
+## Principle
+
+A Carbon function that needs to report recoverable failures should return a sum
+type whose alternatives represent the success case and failure cases, such as
+`Optional(T)`, `Result(T, Error)`, or `Bool`. The function's successful return
+value, and any metadata about the failure, should be embedded in the
+alternatives of the sum type, rather than reported by way of output parameters
+or other side channels. Carbon's design will prioritize making this form of
+error handling efficient and ergonomic.
+
+## Applications of these principles
+
+Carbon errors, unlike exceptions in C++ and similar languages, will not be
+propagated implicitly. Instead, Carbon will very likely need to provide some
+explicit but syntactically lightweight means of propagating errors, such as
+Rust's `?` operator, so that error-propagation boilerplate doesn't make it hard
+for readers to follow the logic of the success path.
+
+Carbon will not have a special syntax for specifying what kind of errors a
+function can emit, such as `noexcept` or
+[dynamic exception specifications](https://en.cppreference.com/w/cpp/language/except_spec)
+in C++, or `throws` in Java, because that information will be embedded in the
+function's return type. Similarly, Carbon errors will be statically typed,
+because Carbon return values are statically typed.

+ 1 - 0
proposals/README.md

@@ -44,6 +44,7 @@ request:
 -   [0199 - String literals](p0199.md)
 -   [0253 - 2021 Roadmap](p0253.md)
 -   [0285 - if/else](p0285.md)
+-   [0301 - Principle: Errors are values](p0301.md)
 -   [0340 - while loops](p0340.md)
 -   [0426 - Governance & evolution revamp](p0426.md)
 

+ 92 - 0
proposals/p0301.md

@@ -0,0 +1,92 @@
+# Principle: Errors are values
+
+<!--
+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/301)
+
+<!-- toc -->
+
+## Table of contents
+
+-   [Problem](#problem)
+-   [Background](#background)
+-   [Proposal](#proposal)
+-   [Alternatives considered](#alternatives-considered)
+    -   [Decouple errors from return values](#decouple-errors-from-return-values)
+    -   [Implicit error propagation](#implicit-error-propagation)
+
+<!-- tocstop -->
+
+## Problem
+
+Carbon needs a coherent, consistent approach to handling and propagating errors.
+
+## Background
+
+The handling and propagation of errors is a pervasive concern in almost every
+nontrivial codebase, and every language provides some form of support for it.
+Whether that takes the form of direct language support for errors, or emerges as
+a special case of more general-purpose language features, it always has a
+powerful effect on the performance, safety, and ergonomics of the language.
+Consequently, Carbon's ability to meet its goals will be strongly influenced by
+how it supports errors.
+
+## Proposal
+
+I propose establishing as a design principle that Carbon's error handling will
+be based on return values, and specifically return values of sum types, rather
+than exceptions or other non-return side channels.
+
+## Alternatives considered
+
+### Decouple errors from return values
+
+Rather than representing errors using function return values, we could convey
+errors by way of a separate "channel", as in Swift. This would require a
+separate syntax for indicating whether a function can raise errors, and unless
+we want to follow Swift in making errors dynamically typed, that syntax would
+also need to indicate the type of those errors. We would additionally need a
+separate syntax for stopping error propagation and resuming normal control flow,
+such as Swift's `do`/`catch`, because the error "channel" is invisible to
+ordinary code.
+
+This approach may have some performance advantages, because the compiler always
+statically knows whether a given object represents an error or a successful
+return value, although it's not clear how significant that advantage will be in
+Carbon. It would also make it easier to explore different implementation
+strategies, such as table-driven stack unwinding, that generate very different
+code for propagating errors than for handling ordinary return values.
+
+This approach will make it harder for Carbon code to interoperate with C++ code
+that uses error returns, and harder to migrate such code to Carbon. It might be
+an easier migration/interoperation target for C++ code that uses exceptions, but
+that's less certain, because this approach still differs from C++ exceptions in
+fairly important ways, such as the fact that typing is static and propagation is
+explicit. By the same token, this approach is somewhat less likely to feel
+familiar to C++ programmers.
+
+I recommend against this approach for the present, because the need for
+something like `do`/`catch` makes it more complex to design, and because the
+potential advantages, particularly with respect to performance, are speculative.
+It seems better to start with the simpler approach, and let subsequent design
+changes be driven by concrete experience with whatever problems it has.
+
+### Implicit error propagation
+
+As an extension of the previous option, we could treat errors as a separate
+channel from return values, and allow them to propagate across stack frames
+implicitly, without an explicit `?` or `try` at the callsite. This is basically
+how C++ exceptions work, so this would ease migration and interoperation with
+C++ code that uses them. However, this entails a readability tradeoff:
+error-propagating code can be distracting boilerplate, but it can also be a
+vital signal about what the code actually does, depending on the needs of the
+reader.
+
+I recommend against this approach for the present. Instead, we should
+investigate ways to make explicit error propagation as syntactically lightweight
+as possible, in order to address the second kind of reader use case, while
+minimizing the burden on the first.