
On Fri, Aug 6, 2021 at 9:59 PM Steven D'Aprano steve@pearwood.info wrote:
def fib(0): return 0
def fib(1): return 1
def fib(n): return fib(n-1) + fib(n-2)
I think that there is something rather disturbing about writing a function definition with a constant literal as parameter. It looks wrong and I'm sure it's going to confuse beginners.
Agreed, but that's because Python behaves differently.
But we already have a way to have a function-ish thing that then changes behaviour: a property's .setter/.deleter modifiers. Borrowing an idea from that:
@multidispatch def fib(n): return fib(n-1) + fib(n-2) @fib.specialize(n=0) def fib(n): return 0 @fib.specialize(n=1) def fib(n): return 1
I'm not really a fan, but (a) it does avoid the "literal as parameter" problem, and (b) it fits Python's syntax.
If we did allow the use of literals as parameters, what would happen if we ran some other code in between the cases of the function?
def fib(0): return 0 print("suprise!") def fib(1): return 1
We would, apparently, have two distinct modes:
sometimes re-defining a function replaces the previous binding;
but other times, it extends the function with a new case.
What are the rules for each?
Agreed. Use of a dedicated specialization operation would avoid this problem. Obviously you wouldn't normally want to do it, but if you did, the behaviour in between those steps would be well-defined: specializations not yet applied would not be used, and the function would execute using the generic form.
(Also, I don't think you'd ever want to do it, but you could have a specialization in a different scope from the generic one. The decorator would attach the specialization to the generic.)
def allow_entry({"name": "Bob"}): return "Bob is not allowed in ever!"
I don't know how to interpret that syntax. Does that mean `allow_entry` takes a single argument, which much be a dictionary with a single key, 'name'?
result = allow_entry({'name': 'Bob'}) assert result = "Bob is not allowed in ever!"
If that's not what you mean, then how would I write a function that *actually does* literally match the dict `{'name': 'Bob'}`?
Presumably the behaviour would be the same as the match statement.
https://www.python.org/dev/peps/pep-0622/#mapping-patterns
And that's where any proposal based on current syntax is going to fall down. It's easy enough to build something like singledispatch, but much much harder to make something that can handle the full flexibility of match statements. So you're left with two options: a simpler version that lets you build up the patterns from multiple functions, or the full-power version that has a single master function that can do the dispatching.
To be quite honest, I would usually just write it as a single function with a match statement in it. But there are definitely times when I've wanted to be able to build up pattern matching in a more declarative way (think of what can be done with Flask's request routing, for instance), and maybe there'd be enough to justify something like that.
ChrisA