Recent discussion on the store vs. load syntax issues of PEP 622
prompted a (yet unripe) idea that could hopefully spur some progress.
What if cases required some sort of MatchCase (name pending) object
which could be preconstructed by the user if needed, but also inferred
on the fly if absent? I think an example would clarify what I mean.
Consider the following block (with & to mark "load" just for
demonstration purposes):
match some_point:
case Point(x, y, _) if x > y:
print(f"Tridimensional point with x > y")
case Point(_, _, _):
print("Some other 3D point.")
case Point(_, &my_y) as pt:
print(f"{pt} has y=={my_y}.")
case Point(10, _):
print("Some bidimensional point with x==10.")
case Point(_, y):
print(f"Bidimensional point with {y=}.")
case _:
print("Something else.")
This is admittedly simple enough that it wouldn't require what I'm about
to show, but it does require marking my_y in some way to prevent it from
being interpreted as a "store" identifier, or to namespace it for the
same reason. Now consider the following refactor:
3d_point = MatchCase("Point(x, y, z)")
other_3d_point = MatchCase("Point(_, _, _)")
point_with_my_y = MatchCase("Point(_, {})", my_y) # syntax with {} is
debatable.
other_2d_point = MatchCase("Point(_, y)")
match some_point:
case 3d_point if 3d_point[0] > 3d_point[1]:
# 3d_point exposes x, y, and zwith the names given
# in the declaration, as well as numerically,
# through __getitem__ or perhaps also through attributes
# like .args and .kwargs.
...
case other_3d_point:
# other_3d_point[0] through [2] are available, while
# other_3d_point["_"] == other_3d_point[2] because it's the last
# one that was given. Presumably the programmer wouldn't care
about it.
...
case point_with_my_y as pt:
# pt still exposes positional arguments like pt[0], pt[1] or
pt.args
# as well as pt["_"] (== pt[0] in this case), but pt[1] has no
# equivalent in pt.kwargs because no name was given.
...
case Point(10, _):
# Python would construct its own MatchCase here and behave as
expected.
...
case other_2d_point:
print(f"Bidimensional point with y={other_2d_point['y']}.")
case _:
...
Every case above could be constructed in the same way as in the example
without MatchCase, except for point_with_my_y, which contains a lookup:
every identifier inside the match is interpreted as "store" unless it's
namespaced; the others are included for demonstration purposes.
As seen in case Point(10, _), patterns that contain no "load"
identifiers can be written without using MatchCase instances. In effect,
its usage would be a sort of "plug-in" for when complex or verbose
functionality is needed, allowing to load identifiers or encode patterns
for readability and/or reuse through the match block.
The value of the identifiers to load would be read at MatchCase
instantiation and internally converted to a constant value.
Guard clauses could optionally be included in the MatchCase
instantiation. If both it and the case: provide guards, they are anded
together.
If deemed appropriate, a special meaning could be given to MatchCase()
(no arguments, or with "" or even any falsy value as argument) to
represent the default case to appease those who don't like _.
Note that the above examples assume at least _ (and possibly any
identifier) can be repeated. My proposed MatchCase idea is compatible
with the possibility of disallowing repeated identifiers, while still
allowing them in MatchCase()'s first argument with the behaviour seen in
the other_3d_point case.
The constructor MatchCase could be either provided as a builtin or in a
stdlib module that must be imported. I think the latter would be more
reasonable.
Any specific syntax or name presented above (MatchCase, the {}s in its
first argument, the names of the MatchCase.args and MatchCase.kwargs
attributes) is debatable.
I hope I haven't missed any important point that would make the above
demonstration invalid. Any thoughts?
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/python-dev@python.org/message/DDYISJOZPJOD2C2RY4HH2XS3YMHBVYWX/
Code of Conduct: http://python.org/psf/codeofconduct/