Co-authored by: chandlerc - Based on [PR 22](https://github.com/carbon-language/carbon-lang/pull/83) - [Idea topic](https://forums.carbon-lang.dev/t/proposal-for-an-incomplete-rough-high-level-overview-ready-for-early-feedback/52) - [RFC](https://forums.carbon-lang.dev/t/rfc-an-incomplete-early-and-in-progress-overview-of-the-language-design/73) - [Decision announcement](https://forums.carbon-lang.dev/t/accepted-an-incomplete-early-and-in-progress-overview-of-the-language-design/110) This proposal should be considered a starting point of the language design. It's not intended to be final; language details may change. This is intended to offer a reasonable starting point for: - Example code. - Conceptualizing Carbon at a high level. - Reasonable, but not necessarily final, approaches to features in README.md. - If any idea is obviously bad, we can clean it up here. This proposal is not intended to achieve: - A whole language design. - This is way too much work for a single proposal; this is a skeletal framework only. - As we work on feature-specific designs, we may decide to use other approaches. That's fine: we only need somewhere to start. - The summaries in README.md may be expected to change over time. - Feature-specific files aren't intended to be well-written or comprehensive. They are a quick jot of prior thoughts. - We want to avoid getting stuck on language details that we should consider more carefully regardless. If you're passionate about a feature, please feel free to start a new proposal for it. - Each and every aspect of the suggested overview should be subject to careful examination and justification before it becomes a settled plan of record. Chandler started this with https://github.com/carbon-language/carbon-lang/pull/22. I've taken it over with the following changes: - More of a directory hierarchy. - Trying to thin out the main file (now README.md) to lighter summaries of features. - Details/rationale/alternatives should be in feature-specific files. - Draft files are linked as references where added. For an example of how we may proceed with feature-specific designs, see https://github.com/carbon-language/carbon-lang/pull/80. In this structure: - docs/design/README.md mentions interoperability, with a light overview. - The light overview is not yet in https://github.com/carbon-language/carbon-lang/pull/80. - docs/design/interoperability/README.md goes into more depth on interoperability, covering key points of the approach. - Individual files in docs/design/interoperability/* go into more depth on interoperability. Simple designs may not have a subdirectory. All current feature-specific designs do not -- they may be moved later.
4.5 KiB
Pattern matching
Table of contents
TODO
This is a skeletal design, added to support the overview. It should not be treated as accepted by the core team; rather, it is a placeholder until we have more time to examine this detail. Please feel welcome to rewrite and update as appropriate.
Overview
The most prominent mechanism to manipulate and work with types in Carbon is pattern matching. This may seem like a deviation from C++, but in fact this is largely about building a clear, coherent model for a fundamental part of C++: overload resolution.
Pattern match control flow
The most powerful form and easiest to explain form of pattern matching is a
dedicated control flow construct that subsumes the switch of C and C++ into
something much more powerful, match. This is not a novel construct, and is
widely used in existing languages (Swift and Rust among others) and is currently
under active investigation for C++. Carbon's match can be used as follows:
fn Bar() -> (Int, (Float, Float));
fn Foo() -> Float {
match (Bar()) {
case (42, (Float: x, Float: y)) => {
return x - y;
}
case (Int: p, (Float: x, Float: _)) if (p < 13) => {
return p * x;
}
case (Int: p, auto: _) if (p > 3) => {
return p * Pi;
}
default => {
return Pi;
}
}
}
There is a lot going on here. First, let's break down the core structure of a
match statement. It accepts a value that will be inspected, here the result of
the call to Bar(). It then will find the first case that matches this
value, and execute that block. If none match, then it executes the default
block.
Each case contains a pattern. The first part is a value pattern
((Int: p, auto: _) for example) followed by an optional boolean predicate
introduced by the if keyword. The value pattern has to match, and then the
predicate has to evaluate to true for the overall pattern to match. Value
patterns can be composed of the following:
- An expression (
42for example), whose value must be equal to match. - An optional type (
Intfor example), followed by a:and either an identifier to bind to the value or the special identifier_to discard the value once matched. - A destructuring pattern containing a sequence of value patterns
(
(Float: x, Float: y)) which match against tuples and tuple like values by recursively matching on their elements. - An unwrapping pattern containing a nested value pattern which matches against a variant or variant-like value by unwrapping it.
In order to match a value, whatever is specified in the pattern must match.
Using auto for a type will always match, making auto: _ the wildcard
pattern.
Pattern matching in local variables
Value patterns may be used when declaring local variables to conveniently destructure them and do other type manipulations. However, the patterns must match at compile time which is why the boolean predicate cannot be used directly.
fn Bar() -> (Int, (Float, Float));
fn Foo() -> Int {
var (Int: p, auto: _) = Bar();
return p;
}
This extracts the first value from the result of calling Bar() and binds it to
a local variable named p which is then returned.
Open questions
Slice or array nested value pattern matching
An open question is how to effectively fit a "slice" or "array" pattern into nested value pattern matching, or whether we shouldn't do so.
Generic/template pattern matching
An open question is going beyond a simple "type" to things that support generics and/or templates.
Pattern matching as function overload resolution
Need to flesh out specific details of how overload selection leverages the pattern matching machinery, what (if any) restrictions are imposed, etc.