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/

Reply via email to