Photo by Steve Harvey on Unsplash

Photo by Steve Harvey on Unsplash

Pattern matching dispute in Python 3.10

Seeking Patterns

Article from ADMIN 63/2021
By
A controversial change is taking place in Python version 3.10 known mainly from functional languages: pattern matching.

Pattern matching is a symbol processing technique that uses a pattern to identify discrete structures or subsets, such as strings, trees, or graphs. It is found in functional or logic programming languages that use a match expression to process data on the basis of its structure (e.g., in Scala [1], Rust [2], and F# [3]). A match statement takes an expression and compares it with successive patterns, which the programmer specifies in terms of one or more cases. This method is superficially similar to a switch statement in C, Java, or JavaScript, but far more powerful.

Python 3.10 is now also set to receive such a match expression. The Python enhancement proposal (PEP) 634 [4] describes the implementation. More information about the plans can be found in PEP 635 [5] and PEP 636 [6]. How pattern matching is intended to work in Python 3.10 is demonstrated by the simple example in Listing 1, which compares a value with multiple literals.

Listing 1

Intended Pattern Matching

def http_error(status):
      match status:
          case 400:
              return "Bad request"
          case 401:
              return "Unauthorized"
          case 403:
              return "Forbidden"
          case 404:
              return "Not found"
          case 418:
              return "I'm a teapot"
          case _:
              return "Something else"

In the last case of the match statement, an underscore acts as a placeholder that intercepts everything. This has caused irritation among developers, because in Python it is common to use an underscore before variable names to declare them for internal use. Although Python does not distinguish between private and public variables as strictly as Java, it is a widely used convention that is also specified in the Style Guide for Python Code [7].

However, the proposed match statement can do more than just check patterns (i.e., detect a match between the value of a variable and a given pattern); it also rebinds the variables that match the given pattern. As a result, in Python you suddenly find yourself dealing with Schrödinger constants that remain constant only until you take a closer look at them in a match statement. The example in Listing 2 explains this problem, which produces the output:

not found
Current value of NOT_FOUND=200

Listing 2

Schrödinger Constants

NOT_FOUND = 404
retcode = 200
match retcode:
  case NOT_FOUND:
    print('not found')
print(f"Current value of {NOT_FOUND=}")

This behavior has prompted experienced Python developers like Brandon Rhodes, author of Foundations of Python Network Programming, among others, to voice harsh criticism [8] of the proposal: "If this poorly-designed feature is really added to Python, we lose a principle I've always taught students: 'if you see an undocumented constant, you can always name it without changing the code's meaning.' The Substitution Principle, learned in algebra? It'll no longer apply."

Many long-time Python developers, however, don't just quibble with the structural pattern matching that's coming in Python 3.10, they generally regret developments in recent years in which more and more syntactic icing has been layered over the language. Original principles, as laid down in The Zen of Python [9], are being forgotten and functional stability sacrificed. Although Python has defined a sophisticated process in the form of PEPs [10], with which the further development of Python can be controlled collaboratively, criticism always pops up on Twitter and other social media, as now with structural pattern matching.

In fact, the topic has already been discussed intensively in the Python community. The Python steering council [11] already recommended the adoption of the proposal in December 2020. Nevertheless, the topic only really boiled up with the adoption of the proposal, certainly because of the size and diversity of the Python community. Most programmers are probably only interested in discussions about extensions that solve their own problems. They ignore the other developments until the PEPs are accepted.

That's probably the case with structural pattern matching. It enables problem solving in ways that were almost impossible before in Python. For example, data scientists can write matching parsers and compilers for which they would have previously turned to functional or logical programming languages. A simple example can be found in PEP 635 (Listing 3).

Listing 3

New Options

# previously
if (isinstance(node, BinOp) and node.op == "+"
and isinstance(node.right, BinOp) and node.right.op == "*"):
    a, b, c = node.left, node.right.left, node.right.right
# Handle a + b*c
# new and more easily readable:
match node:
    case BinOp("+", a, BinOp("*", b, c)):
# Handle a + b*c

With the adoption of the PEP, the discussion has now spread to the wider Python community. Brett Cannon, a member of the Python steering council, pointed out in an interview that the last word has not yet been spoken: If problems arise in practical code you still have time to request changes until the first beta version. He also raised the possibility of changing the meaning of the underscore once again, so maybe you will be spared Schrödinger's constants.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy ADMIN Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus