`match-case`: checking with negation (≠)

Match case is great, especially for matching node-structure inside an AST. However, sometimes I find myself wanting to match something by exclusion, for example, consider the task of matching all function definitions that are not @overload-decorated.

The proposal is simply to allow negative assignment patterns via !=.

Examples:

match node:
     case FunctionDef(decorator_list != [Name(id="overload"), *_]):
             ...

(or even better using decorator_list != {Name(id="overload"), *_})

vs

match node:
    case FunctionDef() as func:
        if all(
            not isinstance(deco, Name) or deco.id != "overload"
            for deco in func.decorator_list
        ):
            ...

A more generalised way of customising pattern-matching was proposed at this year’s Language Summit. You might find the proposal interesting. I would prefer to go with a generalised solution to this genre of problems, as was proposed there, than with what you’re proposing here.

2 Likes

I imagine it would be pretty hard to implement this, and the functionality is already available using a guard clause on the case. I haven’t personally needed this level of complexity in a match, and if I did, I think I’d be happy with what’s already possible. But maybe negative patterns would be useful (I don’t find your example particularly intuitive, but that might just be lack of familiarity).

I think someone would need to demonstrate how this would be implemented (basically, that would mean a full, unambiguous specification of the proposal, almost certainly combined with at least a proof of concept implementation) for it to get anywhere. Otherwise “just use guards” seems like a reasonable solution.

1 Like

You could also consider using nested match/case clauses:

match node:
    case FunctionDef(decorator_list=decorators):
        match decorators:
            case [Name(id="overload"), *_]):
                ...  # @overload is in the decorator list
            case _:
                ...  # @overload isn't in the decorator list
    case _:
        ... # it isn't a function node
2 Likes

That’s a beautiful idea. Randolph’s case would be a good motivating example for it.