Skip to content
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

Closed
wants to merge 17 commits into from
Closed

First draft of Carbon pattern matching design doc. #87

wants to merge 17 commits into from

Conversation

josh11b
Copy link
Contributor

@josh11b josh11b commented Jun 19, 2020

Describe how matching of structured values may work

@googlebot googlebot added the cla: yes PR meets CLA requirements according to bot. label Jun 19, 2020

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
Copy link
Contributor

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Pattern matching as function overload resolution
### Function overload resolution as pattern matching


### Pattern matching as function overload resolution

The argument list to a function in Carbon is a pattern. Functions may be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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?

Comment on lines +465 to +468
**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.
Copy link
Contributor

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
Copy link
Contributor

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.

@chandlerc chandlerc changed the base branch from master to trunk July 2, 2020 03:20
parameters, any may have defaults, and the caller may skip specifying any
optional argument and still specify later arguments.

### Deduced parameters
Copy link
Contributor

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:
Copy link
Contributor

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?

Comment on lines +520 to +524
if (T != Bool) {
return Vec(T);
} else {
return BitVec;
}
Copy link
Contributor

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:** [ `[`&lt;type> `:` [ `$` | `$$` ] &lt;id>`,` ... `]`
Copy link
Contributor

@jsiek jsiek Sep 16, 2020

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 &lt;value pattern> can either be:

- &lt;value>
Copy link
Contributor

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?

@jonmeow jonmeow marked this pull request as draft April 20, 2021 16:20
@jonmeow jonmeow removed the WIP label Apr 20, 2021
@github-actions
Copy link

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 inactive label.
This PR is labeled inactive because the last activity was over 90 days ago. This PR will be closed and archived after 14 additional days without activity.

@github-actions github-actions bot added the inactive Issues and PRs which have been inactive for at least 90 days. label Aug 14, 2021
@github-actions
Copy link

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.
This PR was closed and archived because there has been no new activity in the 14 days since the inactive label was added.

@github-actions github-actions bot closed this Aug 29, 2021
@github-actions github-actions bot added the proposal deferred Decision made, proposal deferred label Jul 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cla: yes PR meets CLA requirements according to bot. inactive Issues and PRs which have been inactive for at least 90 days. proposal deferred Decision made, proposal deferred proposal A proposal
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants