-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
First draft of Carbon pattern matching design doc. #87
Conversation
docs/design/pattern-matching.md
Outdated
|
||
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fact that match
uses the first match, whereas overload resolution uses the best match, will somewhat erode the consistency/simplicity benefits of treating them as two aspects of the same system. I wonder if it would work to use order only as a tiebreaker when neither choice is a better match than the other? That way overload resolution would never select a different case than match
pattern matching would, although it can fail in cases where match
would succeed.
that depends on a generic input value (`N` in the example above) and so is not | ||
known when typechecking. | ||
|
||
### Pattern matching as function overload resolution |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### Pattern matching as function overload resolution | |
### Function overload resolution as pattern matching |
docs/design/pattern-matching.md
Outdated
|
||
### Pattern matching as function overload resolution | ||
|
||
The argument list to a function in Carbon is a pattern. Functions may be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument list to a function in Carbon is a pattern. Functions may be | |
The parameter list to a function in Carbon is a pattern. Functions may be |
docs/design/pattern-matching.md
Outdated
operated on. This position is espoused in the | ||
["Carbon closed function overloading" proposal (TODO)](#broken-links-footnote)<!-- T:Carbon closed function overloading proposal -->. | ||
|
||
**Question:** Is there a rule for selecting an overload if there are multiple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm finding it difficult to keep track of the logical structure of this document: sometimes "Question:" seems to denote an open question, and sometimes it's a question that the doc is going to propose an answer to. Similarly, sometimes "Proposal" seems to introduce a new topic, and other times it seems to answer a previous "Question:". I'd recommend making more use of section headings to distinguish separate topics.
I'd also recommend not explicitly labelling things as "Questions" unless you want to flag them as open questions that you don't have a proposed answer for. You may also want to omit the "Proposal" labels, to avoid issues like on line 358, where the "Proposal" label doesn't actually mark the start of the proposal (as evidenced by the fact that the next word is "furthermore").
- Function overloading allows multiple patterns, but at compile time any | ||
function call must be resolved to match a single pattern. | ||
|
||
## Features |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the discussion of keyword, optional, and deduced arguments, and variadics, it would be really helpful to explain how (if at all) these features relate to pattern matching.
declare as keyword arguments in order to match. See | ||
["Carbon struct types" (TODO)](#broken-links-footnote)<!-- T:Carbon struct types -->. | ||
|
||
**Proposal:** Furthermore, I believe we should use keywords in overload |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This phrasing makes it sound like you're talking about keywords like requires
(which controls how a function participates in overload resolution). I'd sort of prefer we use a different term that doesn't have that ambiguity ("named arguments", maybe?), but if that ship has sailed we'll need to be religious about saying "keyword arguments" rather than "keywords".
would be hard to rewrite to avoid using conditions. | ||
|
||
We still intend to support conditions in function overload resolution for | ||
consistency, but the use cases are less clear. Note that in order to satisfy the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't pretty much any use case for std::enable_if
or C++20 requires
be a use case for conditional patterns?
**Proposal:** Conditions will not be used to affect deductions -- since | ||
conditions are arbitrary expressions they will be evaluated as a black box | ||
returning "true" or "false", not as information that can disambiguate tricky | ||
deduction cases. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that C++ tries to peek inside the black box, using structural relationships between requires
clauses to determine when an overload is a better match than another. For example, an overload with requires(A && B)
will generally be considered a better match than an overload with requires(A)
. This aspect of requires
is pretty complicated (Richard probably has all the details), so I wouldn't say that's a good example for Carbon to follow, but the doc should probably note the contrast between Carbon's approach and C++'s.
returning "true" or "false", not as information that can disambiguate tricky | ||
deduction cases. | ||
|
||
## Specification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would really help to have a more extended informal description of the design, before the formal specification. Specifications are good at precision and disambiguation, but they're bad at explanation.
Moved content from tuples doc.
parameters, any may have defaults, and the caller may skip specifying any | ||
optional argument and still specify later arguments. | ||
|
||
### Deduced parameters |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed by chat, I think we should explore the possibility of eliminating the out-of-line square bracket syntax for deduced parameters, because deduction is really just a special case of pattern-matching anyway. For example, the examples in this section seem like they could be rewritten to avoid it:
fn DeducesType(_: a) -> Int {
and
fn DeducesSize(FixedLenArray(Int, Int: size): a) -> Int {
value specification (see above). | ||
|
||
**Question:** Do we want to require that all deductions are resolved at compile | ||
time? This would only be relevant to the `match` statement: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think to put it another way: when you say 'unique' above, do you mean that for all a1 and a2 that match, a1 == a2? Or something else?
if (T != Bool) { | ||
return Vec(T); | ||
} else { | ||
return BitVec; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This particular example uses type equality. In the case where Bool is one side of the equality, it doesn't matter very much. But in general, reasoning about type equality is going to involve an awful lot of questions to answer. There's no single notion of equality. Is Array<N + M> == Array<M + N>
? How high does your type hierarchy go? If it's more than all types are of the same type Type
, then it gets more fun. Can you compare types of different super types for equality, for instance?
Structural pattern matching dodges lots of this; Array<M + N> doesn't match Array<M + N>. But non-structural pattern matching can reintroduce the fun. Conditions and deduced matches are nonstructural, I think.case (Array(X), Array(Y)) if X == Y: ...
.
|
||
Only the value specification is required. | ||
|
||
**Deduced specification:** [ `[`<type> `:` [ `$` | `$$` ] <id>`,` ... `]` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other Carbon documents its stated that types are given by arbitrary expressions.
So I take it that the "type" non-terminal above should instead be "expression".
But that causes a problem... there's an ambiguity in the syntax between patterns
and tuple expressions... my experimental parser complains of reduce-reduce conflicts
(those are the really bad ones). One thought regarding how to fix this conflict is
to flip the id and the type expression, so it goes id :
expression.
|
||
In all three cases, a <value pattern> can either be: | ||
|
||
- <value> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the non-terminal defined somewhere? How does it differ from ? Is it a subset of that only includes things like literals and tuples of literals?
We triage inactive PRs and issues in order to make it easier to find active work. If this PR should remain active, please comment or remove the |
We triage inactive PRs and issues in order to make it easier to find active work. If this PR should remain active or becomes active again, please reopen it. |
Describe how matching of structured values may work