Thanks for your questions, @malemburg.
How would the proposal deal with literals which are defined via a function calls or constants ?
Simply put: the results of those function calls and the values of those constants would need to be put in a qualified namespace.
>>> class YN:
... YES = gettext("yes")
... NO = gettext("no")
...
>>> match "ja":
... case YN.YES: ...
... case YN.NO: ...
...
(You can also use guards for more complicated cases).
Anything ācalledā basically works as an isinstance
check, with the possibility for further destructuring. Youāll get a nice error message if you try to match on something other than a type at run-time:
>>> match "ja":
... case gettext("yes"): ...
... case gettext("no"): ...
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
TypeError: called match pattern must be a type
Similarly, you can have at most one irrefutable pattern. So in practice, trying to use pattern matching as a switch statement on unqualified constants will guide you in the right direction as well (with a SyntaxError
at compile-time):
>>> match "ja":
... case YES: ...
... case NO: ...
...
File "<stdin>", line 2
SyntaxError: name capture 'YES' makes remaining patterns unreachable
In PEP 636, the āAppendix Aā gives a good example: you would not put literal 404 into a case block, but rather use HTTP_NOT_FOUND.
Or, even better: HTTPStatus.NOT_FOUND
from the http
module.
Since this kind of literal matching is likely going to be the most common use case of the syntax, I think the PEPs should give more attention to this case, not just mention it in an appendix.
The rejections of PEPs 275 and 3103 were our first hint that this would not be the most common use case of the new syntax. Itās clear that the community needs a different feature - one that canāt be replaced by a dictionary or a trivial if
-elif
-else
ladder. We found, based on a survey of other languages and past discussions, that a destructuring approach (where you match the shape of the object and extract interesting parts from it) was the most promising. We provide the ability to match on equality with a literal or constant as a convenience, not as a core feature.
In fact, the first draft of PEP 622 (superseded by PEP 634) allowed you to use .YES
(note the leading dot) to indicate an equality comparison, rather than a capture. It also had the nice effect of having an easy-to-remember rule that āany dotted name in a pattern is a load, not a storeā. Unfortunately, this got probably the most pushback of anything in the proposal (too different from the rest of the language, too hard to see, doesnāt make automatic refactoring better, etc.). So we dropped it. If we wanted to add something similar in the future, though, the door is always open to do so. So we can see if this really does cause problems in practice, and respond if necessary.
Under āMatching builtin classesā, why do you have to write str() in {"text": str() as message, "color": str() as c}
and not just str (without the parens, giving the type object) ?
Because otherwise it would be ambiguous with capture patterns. The call syntax also allows you to destructure the match subject further by attributes (which, again, is where pattern matching really shines).
Itās sort of the same reason why we canāt just omit the parentheses of zero-argument function/method calls. f
would be ambiguous, while f()
is not.
Also, note that this is more simply spelled as {"text": str(message), "color": str(c)}
.
The str() would evaluate to an empty string (at least intuitively), just like str(āā), but the matching really is about the type and not the string value.
Yes, but itās about more than just the type. While str()
is a bit boring, you can zoom out and look to the mapping pattern used in this same example to see why the internal structure can be just as important (if not more important) than the actual type.
Would it be possible to add the syntax only with a from __future__ import pattern_matching_v1
marker to experiment with it for a release or two before making it final ?
This would give the syntax a chance to mature in practice and at the same make it obvious to readers of the code that the syntax may in fact still change in an upcoming release.
The way I see it, thatās what development, alphas, and betas are for. You can even play with it now, if you want to!