Pattern Matching Focus

Document #: xxx
Date: 2022-09-22
Project: Programming Language C++
Reply-to: Mihail Naydenov

1 Abstract

This paper proposes to significantly reduce the scope of Pattern Matching (PM), with an aim to ensure C++26 release.

2 Motivation

Modern, post C++11, PM has been in development for almost a decade1,2,3. The progress was quite slow already and now with a completely alternative proposal present (introducing “is” and “as” into the language4), we might and up slowing down even further. Considering our experience so far with both PM itself as well as previous big additions to the language (concepts, coroutines), it does not seem realistic to have a “feature complete” PM in the next 3 years. And let’s not forget, there are many other major C++ features that will need attention also (executors, contracts, reflection, etc).

As a proof of the above one can see no further then the status report after each the C++ committee meeting - Pattern Matching slides. From the optimistic “C++23” few years back to the conservative “C++29” now. This papers argues, C++26 is late enough. Other “C++ like” languages, will have PM for years if not decades at that point.

Part of the problem is the task at hand itself. PM is prone to feature creep - there is always “one more pattern” to add and one more user case to cover. We could however use this to our advantage, cutting the list to an acceptable minimum with the understanding, we can always add more later! Doing so will allow us to focus on parts of PM where we have overlap b/w alternative proposals (to the extend it is possible) increasing both productivity and polish.

3 Proposal

The listed below patterns are proposed as the scope for a future PM systemm with an explicit aim for a C++26 release. Developments outside this scope should be in the interest of “futureproofing” and “future directions”, not “improving” the proposal in the works.
If the proposed reduced scope becomes unreachable for a C++26 release, proposed is dropping functionality even further, based on a coarse priority scheme, suggested below. And if all top priority items are not deliverable by C++26, the priorities should be revised once more with the intend to not miss the release - a that tiny, limited PM for 26 is better then “almost-complete” PM for 29.

3.1 Type switch

Arguably, the most interesting usage of PM, in the context of C++, is having an uniform type switch. This is one of the main motivation to have PM in the first place5,6, as well as the fucus of development for both alternative designs. Uniform type switch is exactly the kind of feature, which makes C++ both easier and more powerful! The ability to define conditions, based on type alone and have them work uniformly across multitude of polymorphism paradigms (virtual classes, std::variant, std::any, etc) allows for a generic programming, accessible by any level of expertise, including by people outside the language.

In a way PM is pseudo-code, not tightly related to the language syntax. This can ease people with experience in languages other then C++.

Having a type switch is a top priority, it is also the hardest features to develop, both design and implementation.

3.2 Bindings

No PM is practically possible without binding support. Without the ability to name what is matched, there is little to no way to interact with the rest of the code. Top priority.
Further, we should make an effort to have bindings work in tandem with other patterns, not just as the sole entity (the “Identifier pattern” in P1371). What is more, we will often need to bind at multiple levels, inside a recursive pattern structure. For example binding both the pointer and the pointee, or bind just the pointer, but continuing pattern matching to make sure, the pointer is valid and/or points to the desired value. Without explicit and expressive bindings neither of these are possible.

3.3 Dereference

In the context of C++ we can’t get around of dealing with dereferencable types, be it pointers or optionals. Top priority.

It might be tempting to have automatic dereference and treat “optional” types as value-or-empty, automatically matching on value, if not empty. After all, we can always add the empty state as a separate value to match against. However, because of nesting (“pointer to pointer”, “optional of pointer”, etc), as well as the desire to have binding at any level (see prev. point), we will still need a way to denote “a pointer” or at least “a level” in order to create such bindings as well as matching to a value at any stage.

3.4 Expressions

Values are matched against expressions, no way around that fact. Top priority.
However, in order to reduce the scope and leave room for future improvements, proposed is to limit the expressions to only literals and identifiers, no arbitrary expressions like a + b, c | d or &p. PM could eat up a lot of syntax and we really don’t want to write ourselves into a corner from the get go.

3.5 Destructuring

We already have structured bindings, understandably there is an expectation to have a form of destructuring in PM as well. High priority.
In general, destructuring is integral part of PM systems, however in C++ it is arguably of lesser value because of class encapsulation. There is so much one can do with simple struct-s and with the lack of class member properties (or some similar uniform interface) destructuring will not be as central part as in other languages, hence a bit lower priority. Also, proposed is positional only destructuring, no designators for the initial release. What is more, we must be extremely carful to not allow designators support, without a customization point, otherwise we will damage current encapsulation practices, as people will be tempted to use public-fields-only structs just to be able to destruct them!!!

3.6 Guard

An if check alongside a pattern alleviates the need for more advanced patterns. High priority.

Other then the listed above core features, there is a lot other groundwork remaining in order to have PM ready. These include decision on general syntax, introducer keyword, placeholder/wildcard definition, expression and statement details, exhaustiveness, refutability, etc.
This proposal argues, the presented here is just enough to make initial PM release both attractive and doable in the next 3 years. One major advantage of the above mix of features is that the two current alternative proposals do agree on their importance and even, to some degree, on their syntax as well.
What they, the current alternatives, don’t agree on is how customization is done. This paper advocates no customization for the initial release, outside of what is already available in the language. In other words, PM will be just a syntax sugar over current customization points, without introducing new ones. For example, if a user has her/his class available for structured binding, it will work with destructuring inside PM. It must be stressed, customization points themselves are currently under investigation for improvement7. Combined with the fact any customization in principle comes with high design time const, we should really be conservative on that front for now.

As this point it is evident, most of what is proposed by the current PM proposals is not included here, and that’s the point. Not having to spend much time on “what” will give us more time for “how”, and there are plenty of open questions that need to be solved already. We can always add stuff later.

  1. Pattern Matching for C++:↩︎

  2. Pattern Matching and Language Variants:↩︎

  3. Pattern Matching:↩︎

  4. Pattern matching using is and as:↩︎

  5. Open Pattern Matching for C++:↩︎

  6. Thoughts on pattern matching:↩︎

  7. We need a language mechanism for customization points:↩︎