Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unpack .args for Structural Pattern Matching against Exceptions #105393

Open
1mikegrn opened this issue Jun 6, 2023 · 0 comments
Open

Unpack .args for Structural Pattern Matching against Exceptions #105393

1mikegrn opened this issue Jun 6, 2023 · 0 comments
Labels
type-feature A feature request or enhancement

Comments

@1mikegrn
Copy link

1mikegrn commented Jun 6, 2023

Feature or enhancement

match_class in ceval.c should default to match the positional arguments in the .args attribute for Exceptions

Pitch

By default, the BaseException object in Python defines an args attribute which is assigned the tuple of the arguments given to Exception objects at instantiation.

>>> err = ValueError("error msg")
>>> err.args
('error msg', )

Matching this object in structural pattern matching (SPM) requires knowledge of this implementation detail and results in the match statement being overly verbose for developers who prefer return-ing errors instead of raise-ing them.

def fn(x: int) -> int|ValueError:
    if not x:
        return ValueError("x is falsy", 1)
    return x

match fn(0):
    case ValueError(args=(str as msg, int as code)):
        print(f"Error {code}: {msg}")

the match_class function in ceval.c allows for passing positional arguments to the match for classes. The function uses a __match_args__ class attribute to compare positional values against attributes of the instance. These attributes are packed into a PyList object, and the values are then compared against for SPM.

The proposal here is to, for Exception objects, unpack the .args attribute by default into the list of values used for SPM. The result would be a cleaner syntax more aligned with how exception objects are constructed.

match fn(0):
    case ValueError(str as msg, int as code):
        print(f"Error {code}: {msg}")

A proof-of-concept implementation can be found here:
https://github.com/1mikegrn/cpython

Previous discussion

https://discuss.python.org/t/add-structural-pattern-matching-to-exception-objects/27389/22
https://www.reddit.com/r/Python/comments/13zq790/add_match_args_to_baseexception/

Originally this idea was framed as adding a __match_args__ = ("args", ) class attribute to the BaseException class. The downside there is that you are then required to pass a tuple of args to the case. After further investigation and discussion, changing match_class to unpack the args attribute for Exception objects seems the better approach.

The purpose of this change is to better support the notion of errors as values in Python. Keeping errors out of the global error state and in the local stack provides for more granular control flow and explicitness in error handling. Static type checkers like mypy can validate type safety more effectively for errors that are returned instead of raised. It's an approach that has been seen in multiple other languages as a first-class citizen, and major projects in languages with try/catch functionality have been known to emulate the approach so as to derive its benefits.

@1mikegrn 1mikegrn added the type-feature A feature request or enhancement label Jun 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-feature A feature request or enhancement
Projects
None yet
Development

No branches or pull requests

1 participant