Author jack__d
Recipients jack__d
Date 2021-07-16.20:31:59
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1626467520.14.0.17639663764.issue44658@roundup.psfhosted.org>
In-reply-to
Content
Consider the following code:

class A:
    a = 'a'

# runs without error
match {'a': 1}:
    case {'a': 1, A.a: 1}:
        pass

# raises ValueError
match {'a': 1, 'b': 1}:
    case {'a': 1, A.a: 1}:
        pass

In both cases, the mapping pattern is the same (and both are not valid due to duplicate key values). However, the pattern is only evaluated in the second case. This is because a key-length optimization provides a shortcut around pattern evaluation. The docs gives users a hint that things like this might happen, which is a good thing:

> Users should generally never rely on a pattern being evaluated. Depending on > implementation, the interpreter may cache values or use other optimizations > which skip repeated evaluations. 

> https://docs.python.org/3.10/reference/compound_stmts.html#overview

However, I can't help but think that these ergonomics are strange. Consider if some other code is mutating the value of `A.a`. This could create some very strange and flaky bugs where the state of `A.a` can change and make the pattern invalid, but nonetheless not cause an exception until much later, or not at all.

There is mapping pattern validation code in the `match_keys` function in ceval.c. I haven't looked, but I assume there is some other runtime validation for other match case types. I propose factoring Exception-raising validation into a separate procedure that is called before any optimization jumps occur.

This trades speed for consistent behavior, and I'm interested to hear what others think!
History
Date User Action Args
2021-07-16 20:32:00jack__dsetrecipients: + jack__d
2021-07-16 20:32:00jack__dsetmessageid: <1626467520.14.0.17639663764.issue44658@roundup.psfhosted.org>
2021-07-16 20:32:00jack__dlinkissue44658 messages
2021-07-16 20:31:59jack__dcreate