C++ Logo

std-proposals

Advanced search

Re: [std-proposals] [DRAFT] Another Pattern Matching Proposal

From: Михаил Найденов <mihailnajdenov_at_[hidden]>
Date: Fri, 13 Jan 2023 19:19:14 +0200
Hello, it seems I missed P2688!
This definitely changes some things and must be taken into account.

On Thu, Dec 1, 2022 at 5:24 AM Barry Revzin via Std-Proposals <
std-proposals_at_[hidden]> wrote:

>
>
> On Tue, Nov 29, 2022 at 1:04 PM Jason McKesson via Std-Proposals <
> std-proposals_at_[hidden]> wrote:
>
>> On Tue, Nov 29, 2022 at 12:12 PM Михаил Найденов via Std-Proposals
>> <std-proposals_at_[hidden]> wrote:
>> >
>> > Hello,
>> > This is a soft followup of
>> https://lists.isocpp.org/std-proposals/2022/10/4787.php
>> > which advertised limiting the scope of PM.
>> >
>> > In the attached proposal draft a new PM is presented, one with a
>> limited scope and heavy reuse of syntax (no new syntax actually).
>>
>> Your proposal starts off with this sentence:
>>
>> > Current proposal aims to be conservative in its goals in order to make
>> it in C++26.
>>
>> But the importance of that goal presupposes that the current proposals
>> can't make C++26. I haven't been following anything in the pattern
>> matching domain much. Is there some reason to believe that syntax is
>> the primary thing that is holding these proposals back? And I mean
>> more than just the fact that they introduce new keywords which could
>> in theory break code. If that's a show-stopping problem, then it will
>> prevent these proposals from making it into *any* version of C++26.
>>
>> So what's the evidence that these proposals are stalling out?
>
>
> I *have* been following pattern matching pretty closely over the years,
> so let me chime in. While the design at the moment (the P1371 one, from
> Michael Park, David Sankel, et. al) still has some subtle and annoying
> issues to work out (for instance, with exhaustiveness), on the whole it's
> doing quite well, and I'm not sure that this paper really helps (it also
> repeatedly references some other PXXXX paper for motivation?).
>


> To pick just the first proposal: pattern matching is not a switch, it has
> different semantics and it is a different feature. Reusing the switch
> keywords and the syntax around case labels and default, with different
> semantics, would be a mistake.
>

Many languages extend switch to account for PM, C# comes to mind, but there
are others. I don't see how it is a "different feature", outside not
being an expression. Even the fallthrough is just an OR applied to the
patterns by default (for better or worse).
Considering, we do want the switch behaviour in some case, it makes sense
to reuse the switch building blocks instead of inventing alien new syntax
(!{}, noreturn{}) for something that is 95% the same and we can get the
rest 5% via other means like attributes [[noreturn]].


> That's why the existing proposals don't do that. The proposal for handling
> identifiers vs expressions is not even something I understand - why do I
> have to write "n= __", and why does "&n= __" affect the mutability? The
> analogy with lambdas doesn't make much sense to me - this is a very
> different kind of thing. In the latest suggestion in P2688, we have "x"
> matching an existing variable vs "let x" introducing a binding, you're
> suggesting "x" and "x="? Having a postfix differentiator seems like a bad
> idea. Note that all the patterns in P1371 are prefix and nest from
> left-to-right, which I think is fairly essential for comprehension (for
> humans).
>

Identifiers are a massive problem one way or another. One major problem w/
current solutions is the introduction of a language-inside-the-language by
using let or by using is / as, for patterns alone and being part of the
language.
This is in contrast to other languages and looks bad.
This proposal gets around that by reusing existing syntax, most of which is
already used in lambdas.

The lambda analogy is important because it is the only place in the
language where we introduce identifiers w/o mentioning the type (w/o a
hint). Considering, this is exactly what is needed for PM as well, it makes
sense to reuse it here as well.

Identifiers also play a major role on how matching by type looks. By having
all use of variable identifiers covered by dedicated syntax, we open the
possibility to use "naked" ids for types; w/o requiring special syntax like
<> and as/is.

Lastly, even in the revised P2688, I still dont see how one can bind an
arbitrary pattern, short of using helper functions like `at`:

 <Point> (at!) [let p, let[x, y]]

Compared to the proposed

Point p=[x=, y=]

I doubt the parse-ahead will be an issue as it is very short, stopping
right away if the char is not space or =. The patterns themselves are
always "prefix", with the result being to the right (*pattern* *result*)


> Ultimately though, I really don't think that what pattern matching needs
> to succeed are *more *designs. I think P1371 is an excellent paper, it
> has wide support, and Michael has some very good suggestions in P2688 that
> resolve a few issues and also address what to me was one of P1371's
> shortcomings - the ability to use patterns in a few more important
> contexts.
>

I don't consider this paper an alternative design and I tried to make use
of what is already agreed upon.
In fact, some of the P2688 is in the paper as well, like having simple
identifiers be used for comparison to existing variables by default, and
not doing introduction, like most PM systems do.
Also, the use of ? for optionals, in place of *, was suggested here and is
also in the P2688.

I do think, we must polish (and simplify) the hell out of P1371 and that
is why I also propose the limit the scope for the initial release (the
https://lists.isocpp.org/std-proposals/2022/10/4787.php paper)
I just don't think some of the advanced stuff is desirable the way it looks
(extractors and matchers) and could easily be an iteration.

Using `switch` is also one such simplification. Even the newly proposed
postscript `match` will have parsing problems when multiple arguments are
involved.

More interestingly, by updating `switch` we can re-use another already
reserved keyword - case. This would allow us to use patterns outside
`switch`, more or less naturally

// if(opt match let ?x) // 2688
// if(auto *x is _ = opt) // as is

if(case(?x=) = opt) // future direction

// if(expr match [0, let foo]) // 2688

if(case [0, foo=] = expr) // future direction

// or, if we want them postscript

if(opt case ?x=) // future direction
if(expr case [0, foo=]) // future direction

In any case, I will have to update the paper because I was not
aware of 2688.
Thanks for the feedback


> Barry
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>

Received on 2023-01-13 17:19:27