Allow matching `callable()` in match-case statements

I’m just mumbling about cause I’ve clearly not gotten the point yet, but I think it’s possible to use __match_args__ in a callable class to add items that can appear in a pattern match.

There’s something about match args on that pep.

Using collections.abc.Callable works fine as long as we are sticking to the non-signature matching.

As for a better proposed syntax, what about this one, which is in line with type hints for callables:

match f:
    case Callable[[int, float], str]():
        print("matches when args are annotated as (int, float), return type is annotated as str")
    case Callable[[2], any]():
        print("matches any function that takes exactly 2 args")
    case Callable[[..., "key"], any]():
        print("matches when last arg is called 'key'")

Admittedly, the parentheses at the end are a little bit ugly, but I still like the concept.

Multiple dispatching has been discussed a few times on this discourse alone, and while mailing list was still a thing, I remember at least 1 topic in the past 5 years since I’ve started my python journey.

Rather than a decorator based dispatch mechanism…

Could a mechanism be devised that special cases pattern matching for callables where it inspects the type annotations and selects the appropriate case block?

I believe this is essentially what OP is asking for.

Some questions from me are

  1. What’s the difficulties with a decorator based multiple dispatch?
  2. Why does functools still not have this while multiple 3rd party packages on pypi support it?
  3. How does providing this functionality in pattern matching help with any previous problems?
  4. Do languages with pattern matching support anything like this? If not, is it because they already have a builtin function dispatching mechanism?

Lots of follow ups depending on the answer of #4. For example, If another language’s pattern matching does not support this but has a built-in function dispatching system then how should we interpret that? Or if doesn’t support and doesn’t have the dispatching mechanism builtin?

I think #1 and #2 could be found in previous discussions and if OP feels strongly about this maybe start there to start presenting an argument in favor of their suggestion.

The main one is actually defining what the correct behaviour is, specifically when dealing with subclasses. For example, if Sub is a subclass of Super, and we have two multiple dispatch cases:

def f(x: Sub, y: Super):
    return "Something"

def f(x: Super, y: Sub):
    return "Something else"

then which should be used for a call f(Sub(), Sub())?

That’s probably the simplest possible case of ambiguity, I’m sure there are worse ones that need to be considered (try adding multiple inheritance into that mix).

Because of the above. Third party packages can be opinionated or limited, because “if you don’t like our choice, use another library” is a valid response. But the stdlib needs to be (as near as practical) the right choice for everyone - favouring one group of users over another isn’t an option for a stdlib feature.

I’m not sure it does. Pattern matching seems to be orthogonal to multiple dispatch - similar, but with different trade-offs. In particular, pattern matching doesn’t allow one of the key advantages of function dispatch - you can add implementations for additional types without needing access to the original source code.

I don’t know. Some languages have multiple dispatch, certainly, and they may also have pattern matching. Lisp does, but then again lisp has everything, so that doesn’t prove much :slightly_smiling_face: As I say, I view the two things as largely independent features.