On Thu, Aug 05, 2021 at 09:39:44AM +0100, Sam Frances wrote:

> Following on from PEP 634, it would be good to be able to have Erlang /
> Elixir-style pattern matching in function headers.

This was recently discussed here:

https://mail.python.org/archives/list/python-ideas@python.org/message/ROYZNX4U5VMWZMJJ7AZY6KUGGJ2HYKGX/


> 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.

Let us remember that Python's execution model is not the same as Erlang 
or Elixir. In Python, when you write:

    def fib(a): ...

    def fib(b): ...


that is not a single compile-time declaration, it is a pair of run-time 
statements. In pseudo-code:

    # create a function, bind it to the name "fib"
    fib = make_function( ... )

    # create a new function, bind it to the same name,
    # garbage collecting the first function
    fib = make_function( ... )


So we would need a radical and major change in the execution model of 
Python to turn your example into a single function using pattern- 
matching multiple-dispatch.

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?


The nice thing about Python is that we (mostly) have a very predictable, 
consistent execution model. Syntax is not generally context-dependent, 
so you can usually interpret the meaning of code by considering it in 
isolation, rather than by tracking the context. (With a few simple 
modifiers, such as `global`.)

For example:

    def func(arg): ...

creates a function object named "func", and binds it to the name "func" 
in the local namespace. That applies whether the def statement is inside 
a class, nested inside another function, in the top-level module, inside 
a for-loop or if-statement, etc.

Because of that consistent behaviour, if we want to use generic 
functions, we use the singledispatch decorator. This has the advantage 
of making it explicit and obvious that we're doing generic functions.



> 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'}`?



-- 
Steve
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/OJL2V2Z27L7E4ZZ6Z4BHQTDB3HOAIV3O/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to