-
Notifications
You must be signed in to change notification settings - Fork 14
Add support for matching using context managers. #37
Comments
Ok, so after a few months of having a look at this every once in awhile, I've decided to change directions. The main reason is because I'm not confident that the method I'm using to skip the code inside the context manager is reliable. It may fail depending on the interpreter (compile) setting, will probably mess with some debugger, and uses a function that is not part of the python standard and thus only guaranteed to be there for CPython. So I've been trying to come up with new ideas for a nice looking match syntax and this is the best I've come up so far which I think won't require questionable workarounds. @adt
class ContextMatching:
EMPTY: Case
INTEGER: Case[int]
STRINGS: Case[str, str]
foo = ContextMatching.INTEGER(1)
with foo:
if case(foo.empty):
print("Is empty")
if case(value := foo.integer):
print("Is integer:", value)
if case(x := foo.strings):
string_1, string_2 = x
print("Is strings:", string_1, string_2) The main disadvantage of this, is that it requires python>=3.8. But I would make sure that the current API is still supported. So this feature would in the end only be available to those running on python 3.8 or higher. Is this an issue? The walrus operator does not support unpacking, so you'll need to do the unpacking inside the The way I'm thinking of implementing this is by using the context manager to activate a "case access tracker", it would essentially throw an exception if one or more of the assessors where not accessed within the context manager. I would be implementing the descriptor protocol to track access to the assessors. If accessing the case of the ADT, the accessor returns the value. If accessing the others, it returns a singleton object, lets call it Since I'm using the context manager, the assessors will know whether they need to return the I'll work on this during the holidays. Do any of have a suggestion or some feedback? |
Wow, didn't realize you were working on this the whole time! Just to set expectations, I am not very active in maintaining this project--I think you are probably investing more than me at this point. 😅 That being said, I'm happy to support you in this, and can add you as a direct collaborator to the project. I think this proposal that you've laid out makes a lot of sense, and I have no qualms about restricting to Python 3.8+. The one suggestion I would have is to make sure this is re-entrant (so caller and callee can both be pattern-matching at the same time, or a recursive function can have a pattern-match, or async/await code... etc). This is probably most relevant for the "case access tracker." If you would like help with this bit, I can try to offer some on a pull request. Thanks for your contributions! |
@jspahrsummers I think I might change to a completely different approach that takes advantage of the new pattern matching in Python 3.10, so I'm probably starting a new project. However I have the feeling I'll have to "borrow" some code from here, mainly the mypy plugin stuff which I don't have much experience with. Do you have any issues? Here's a gist with what I already tried: https://gist.github.com/aarondewindt/1cb0af45f05c0da03bfbec6f050f5b58 |
Please feel free! This project is licensed under MIT to support things like that. |
One issue I have with the match function is that it relies on either using lambdas (which can only contain one line) or if you need multiple lines, first defining the handler function and then passing it to the match function.
An option that I think is worth considering is using context managers for pattern matching. The main drawback is that it would not allow returning a value like with the match function, but the syntax is nicer when the case handlers contain more than one statement. As a proof of concept I have implemented this new interface while keeping the library backwards compatible.
Here is some example code of the new proposed syntax.
This example will end up printing out
Is integer: 1
This opens up the possibility for matching values as well. Although not implemented yet I believe code such as this is possible to implement while keeping the current API intact.
The text was updated successfully, but these errors were encountered: