On 10 Jul 2020, at 01:51, Jim Baker <jim.baker@python.org> wrote:


On Thu, Jul 9, 2020 at 1:42 PM Eric Nieuwland <eric.nieuwland@gmail.com> wrote:
Much of the discussion seems to focus on how to distinguish between a variable as a provider of a value and a variable as receiver of a matched value.

In normal Python syntax a variable in an expression provides a value, please let’s keep that unchanged.

For patterns, these are no different than parameters for a function (either a lambda expression or with `def`); or target assignments in unpacking assignments. So just like I wouldn't wonder where `a` and `b` materialized in the parameters for the function definition below

def sum2(a, b):
  return a + b 

I think it will be straightforward to understand this in the context of a `case` using a capture pattern:

match x:
  case (a, b): 
     return a + b
   ...

(This commonality between cases and function definitions is further used in Scala for example, but I don't see that approach for defining an idea of partial functions -- not like functools.partial functions! -- as being that useful in Python.)


So it seems to me we should explicitly mark a variable to receive a matched value.
I have seen ‘?’ suggested as a prefix to do this, ‘\’ would also do fine.

This would solve the single variable issue, too:
        case foo:
matches the value of ‘foo’, while
        case \foo:
matches anything and stores it in ‘foo’.


Explicit namespacing (if a constant) or using a guard (if a variable) seems to be the right solution, as Ethan demonstrated earlier. No need for . or ^ or  \ or ... to disambiguate. Also it seems to me that structural pattern matching will build on two common usages of namespaces for constants:

1. Constants used from other modules are almost always used in the module namespace. Eg, socket.AF_UNIX or signal.SIGTERM.
2. New code often tends to use constants defined within an Enum namespace. Hopefully we will see more of this convention in usage.

(Very much an aside: Interestingly with the socket module we see both used - it defines its constants with IntEnum and exports them traditionally. The namespace specifics it uses with IntEnum._convert_ to make this happen  -- strictly speaking EnumMeta._convert, not documented, and a bit hard to follow -- might be possibly debatable, but it works out quite well in practice in providing backwards compatibility while continuing to work with a C source of these constants.)
 
This would also mean
        case Point(x=\x, y=\y):
should be used to obtain x and y from the Point instance.

This approach makes deeper nesting of the structure much more cumbersome, I think.

How to match Polygon(Point(x0,y0), Point(x1, y1), Point(x2, y2)) based on its structure?
And Polygon(Point(x0,y0), p1, Point(x2, y2))?