[Python-Dev] Re: The semantics of pattern matching for Python

2020-11-22 Thread Guido van Rossum
On Sun, Nov 22, 2020 at 5:03 PM Jim J. Jewett  wrote:

> I think your changed constructor:
>
> class Car:
> def __init__(self, manufacturer, variant):
> self.brand = manufacturer
> self.model = variant
>
> is a particularly good example, and the PEP should specify whether:
> Car("Chrysler", "PT Cruiser")
>
> is matched by:
> Car(brand="Chrysler", mod:=model)
> or:
> Car(manufacturer="Chrysler", mod:=variant)
> or both, or possibly even Frankenstein combinations like:
> Car(brand="Chrysler", mod:=variant)
>

(a) We got rid of the walrus and now spell it using ' as
' instead of ' := ".

(b) All your examples have a positional argument following a keyword
argument and that's invalid syntax, in patterns as in expressions. (This
was the only bug in Steven's example that I found, but I didn't bother to
call it out.)

(c) What Ethan said -- after fixing the syntax this does show that the
keywords in class patterns correspond to attributes, not to constructor
arguments (unless those are the same, as they often are, and always for
dataclasses and named tuples).

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

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


[Python-Dev] Re: The semantics of pattern matching for Python

2020-11-22 Thread Ethan Furman

On 11/22/20 5:00 PM, Jim J. Jewett wrote:

I think your changed constructor:

class Car:
 def __init__(self, manufacturer, variant):
 self.brand = manufacturer
 self.model = variant

is a particularly good example, and the PEP should specify whether:
 Car("Chrysler", "PT Cruiser")

is matched by:
 Car(brand="Chrysler", mod:=model)
or:
 Car(manufacturer="Chrysler", mod:=variant)
or both, or possibly even Frankenstein combinations like:
 Car(brand="Chrysler", mod:=variant)


It could be a good example to include to emphasize that pattern matching is based on attributes, not function headers -- 
so `brand` and `model` would work, whilst `manufacturer` and `variant` would not.


--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/EO2XDZT52MCLNNJUV3PC2HFNC5BWJMUW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The semantics of pattern matching for Python

2020-11-22 Thread Jim J. Jewett
I think your changed constructor:

class Car:
def __init__(self, manufacturer, variant):
self.brand = manufacturer
self.model = variant

is a particularly good example, and the PEP should specify whether: 
Car("Chrysler", "PT Cruiser")

is matched by:
Car(brand="Chrysler", mod:=model)
or:
Car(manufacturer="Chrysler", mod:=variant)
or both, or possibly even Frankenstein combinations like:
Car(brand="Chrysler", mod:=variant)

-jJ
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/HBHBYOG56E75ET732WM7ZBDRTWGBVA25/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Words rather than sigils in Structural Pattern Matching

2020-11-22 Thread Greg Ewing

On 23/11/20 7:49 am, Daniel Moisset wrote:

Look at the following (non-pattern-matching) snippet:

event = datetime.date(x, month=y, day=z)


The only names that are treated as lvalues there are to the left
of an '='. The rules are a lot simpler.

One of the Zen lines says "If it's hard to explain, it's probably
a bad idea." I think the proposed rules for match cases are
objectively harder to explain than those for other expressions,
because they're more complicated.

--
Greg
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/AVXFD6J2LGGTJH5LZKBJ3EAGUPV6QPGX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Questions about about the DLS 2020

2020-11-22 Thread Jim J. Jewett
I suppose that does follow from treating _ specially by not binding to it at 
all; I just hadn't thought through it.  (I think my mental model had it wiping 
out the previous binding even if the "new" one wasn't available.)  So I would 
prefer that this be stated explicitly in the PEP.  (And maybe it is by now; the 
last draft I read was a few versions ago.)

-jJ
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/JDBIZCC4TONZWJPVO2HXXITBNPWFR7EQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Matching syntax and semantics

2020-11-22 Thread Jim J. Jewett
I don't love the way it moves the variable name away from the capture location, 
but it does offer a decent solution for anonymous placeholder variables (other 
than _ or __), and makes it clear which variables are being bound (only those 
in front of an = sign) vs limiting potential matches (anything after the = sign)

-jJ
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/MXVOGT7GSFBRY22OX7RV55ECWPV7FO2H/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Words rather than sigils in Structural Pattern Matching

2020-11-22 Thread Daniel Moisset
On Sun, 22 Nov 2020 at 00:31, Greg Ewing 
wrote:

> On 22/11/20 6:47 am, David Mertz wrote:
> > I'm convinced by Guido,
> > Brandt, and others that the binding  use will be far more common, so
> > adding extra characters for the 90% case does not feel desirable
>
> Minimising the number of characters is not the only consideration.
> Readability counts too, and I think the proposed DWIM rules suffer
> in the readability area.
>
> There are about five different contexts in which a bare name can
> appear as part of a match case:
>
> * As a constructor name
> * As a bare name in an argument position
> * As part of a dotted expression
> * On the left of an =
> * On the right of an =
>
> Only in some of those contexts is it treated as a name to be
> assigned. That's a fairly complex bit of mental parsing to do
> when reading a case.
>
>
Hi Greg,

Look at the following (non-pattern-matching) snippet:

event = datetime.date(x, month=y, day=z)


you have bare names appearing as:
* a constructor name (date)
* bare name in an argument position (x)
* part of a dotted expression (datetime, date)
* left of = (event, month, day)
* right of = (y, z)

some of them are lookups in the namespace (datetime, x, y, z). Others are
targets to write (event). "date" is actually a literal to be used as
attribute lookup, for reading (a key in the module dictionary). "month" and
"day" are literals to lookup in the list of formal parameters of a
function, for writing into the new function stack frame.

I never found Python students struggle too much with the line above, and I
don't expect it to be much different for names in patterns. Names in Python
can appear with a lot of different "roles" in a lot of different contexts,
but the context is usually easy to recognise (is it left or right of a
chain of dots? does it have an = on the left or right? is it in an argument
list? a parameter list?).

Of course I can never deny if you tell me "I find this syntax hard to read"
(only a person can decide what's easy or hard to read for them), but I
don't think this "bare names appear in many contexts" is a solid
explanation.

A hypothesis I have is that many readers of the PEP have been scared of
these semantics because they have been laid bare when explaining them in
detail, but would never notice in day to day life, in the same way that
most Python users would never stop twice to look at the meaning of "a.b.c =
0", even if a semantic description requires us to describe that each of the
three names has a different role ("a" is a lookup in the current scopes,
"b" is a constant name for the purpose of reading attributes, and "c" is a
constant name for the purpose of writing attributes). But looking at the
details description of what's going on under the hood is scarier than the
intuitive look, and when people read the PEP they are looking under the
hood rather than looking at this as users. This is guesswork and could be
absolutely wrong, but I hope it helps read this with a different set of
eyes.



> --
> Greg
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/LMALNSPBLL3MHFOJHBGGO24IDS6CI5R3/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/6VKTXLNWA6ZAXS6TQRT6Z3HS7F2OQLIL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: The semantics of pattern matching for Python

2020-11-22 Thread Daniel Moisset
Others have replied with most of this covering my opinion but there's a
point I'd like to highlight here

On Fri, 20 Nov 2020 at 14:23, Mark Shannon  wrote:

> Hi Daniel,
>
> On 20/11/2020 10:50 am, Daniel Moisset wrote:
> >  (... snipping for brevity ...)
> >
> >  1. You mention a goal about "erroneous patterns" (which I'm still not
> > sure I agree on), and your proposal addresses that by forcing
> > classes to be explicit (via __atributes__ and __deconstruct__) about
> > what attributes are accepted as matches. This is against one design
> > principle that's not in your list but it was (at least implicitly)
> > in PEP622 and 634: "pattern matching must allow matching objects on
> > types not specifically designed for it"; this will allow to apply
> > this feature to classes that you can not modify (like instances
> > created by a 3rd party library ). That's why PEP634 relies on
> > getattr() ; that could be extended in the feature (providing some
> > override using attributes like yours) but that wouldn't be required
> > by default
>
> Why force pattern matching onto library code that was not designed for
> pattern matching? It seems risky.
>
> Fishing arbitrary attributes out of an object and assuming that the
> values returned by attribute lookup are equivalent to the internal
> structure breaks abstraction and data-hiding.
>
> An object's API may consist of methods only. Pulling arbitrary
> attributes out of that object may have all sorts of unintended
> side-effects.
>
> PEP 634 and the DLS paper assert that deconstruction, by accessing
> attributes of an object, is the opposite of construction.
> This assertion seems false in OOP.
>
>
I think your description about what you and I call OOP lies at the center
of why we're unlikely to agree on what's the best approach on class
patterns.

The Python I write and tend to use allows and encourages the use of the dot
operator (aka "Fishing arbitrary attributes out of an object") and the
libraries I use expose through it important parts of the API which
doesn't follow the style you mention where  "An object's API may consist of
methods only.". Of course I rely on properly documented attributes, like
datetime.date.year, Fractional.denominator, JSONDEcodeError.message (in the
stdlib) or fields I defined in my django models, or things like
requests.response.status_code (in 3rd party libraries that I used as is or
by extending). Those are all types of objects that I'd like the proposal to
allow as subjects of a match statement and attributes that I'd like to have
in lookups. Given that I can not force a lot of 3rd party libraries to add
a new special attribute `__attributes__`, our proposal relies on the
standard `getattr()` API (which is the core operation on Python object
model to doing most things with an object, even calling methods).

I've used other OOP languages within that style were attributes have to be
explicitly exposed, and even so that's disencouraged and they follow the
principle of "API=only methods". And I can imagine some people could choose
to write Python like that, even if I don't and most of the libraries I use
don't either. For people with that philosophy about OOP, our pattern
matching proposal will be horrible and useless and they can choose not to
use the match statement, ever. The argumentation behind the proposal is
implicitly based on the assumption that *most* Python developers consider
the dot operator one of the "natural" ways to expose object interfaces in
Python, even if it can pull attributes and use non-method APIs. If you
think that assumption is false, we'll have to agree to disagree but I don't
see how we could get to a common vision on how class patterns should behave.

(...)
> When we added the "with" statement, there was no attempt to force
> existing code to support it. We made the standard library support it,
> and let the community add support as and when it suited them.
>
> We should do the same with pattern matching.
>

With our proposal, nothing forces the existing code to support it, they
support it naturally using their existing attribute access API (through the
dot operator). One advantage that the with statement had is that it's quite
easy to wrap an object that wasn't designed to be used as context manager
in another that can (the stdlib even provides a common example of that with
contextlib.closing). Trying to use something like that (writing "match
wrapper(obj): ..." where obj doesn't support some match protocol and the
wrapper adds it) is non viable in pattern matching, because there are many
cases where the object that needs support might be many levels of
indirection (through item/key/attribute access) behind the subject object.

The current proposals using getattr is useful as is (Even if limited in
some cases). Again that doesn't discard the opportunity of adding an
extended protocol that allows decomposing using other APIs beyond attribute
access (I would 

[Python-Dev] Re: The semantics of pattern matching for Python

2020-11-22 Thread Brian Coleman
Regarding the difficulty which some people have respecting class patterns and 
dictionary patterns, I would like to draw attention to a similar feature in 
JavaScript, object destructuring. JavaScript does not have pattern matching but 
object destructuring is closely related. Take the example of a function to 
compute the distance between two points.

```
function distance(p1, p2) {
  // This is an object destructuring assignment that extracts the x field of p1 
into x1 and the y field of p1 into y1
  const { x: x1, y: y1 } = p1;
  // This is an object destructuring assignment that extracts the x field of p2 
into x2 and the y field of p2 into y2
  const { x: x2, y: y2 } = p2;

  const dx = x2 - x1;
  const dy = y2 - y1;
  return Math.sqrt(dx*dx + dy*dy);
}

// An object literal is assigned to p1 here
const p1 = { x: 0, y: 0 };
// An object literal is assigned to p2 here
const p2 = { x: 1, y: 1 };
const d = distance(p1, p2);
```

Similarly to dictionary patterns in Python, object destructuring in JavaScript 
places the variable names that are the targets of the assignments in the same 
position where a value would be expected in an object literal. This feature has 
existed in JavaScript for several years now and I would like to draw attention 
to it as a counterpoint to the argument that pattern matching is not a good fit 
for languages that are not statically typed. Destructuring can also be found in 
Common Lisp, which is not statically typed. Pattern matching is also a core 
part of Erlang, which is not statically typed..

I would also like to draw attention to the fact that object destructuring was 
added to JavaScript years into it's development. I do not believe this to be a 
reasonable argument against adopting pattern matching in Python.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/6XDXHVT3ZFOK66GVU5UWYGSHJX4UF2CW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Words rather than sigils in Structural Pattern Matching

2020-11-22 Thread Marco Sulla
On Sun, 22 Nov 2020 at 01:27, Greg Ewing  wrote:
> That's a fairly complex bit of mental parsing to do
> when reading a case.

I agree, that's why I wrote pattern matching seems exotical to me. I
was accustomed by Python to read the code as if it's wrote in simple
English. I must admit this is not entirely true for more complex
features (generators, async etc), but I feel pattern matching
particularly less readable. So any effort to make it more readable is
good IMHO. My two cents of a simple programmer.

On Sun, 22 Nov 2020 at 01:43, Greg Ewing  wrote:
>
> On 22/11/20 1:07 pm, Henk-Jaap Wagenaar wrote:
> > On Sat, 21 Nov 2020 at 19:58, Glenn Linderman  > > wrote:
> >
> > Don't () already indicate an expression to be evaluated?
> >
> > Does it?
> >
> > [(a, b)] = [(0, 1)]
>
> Presumably a comma would be needed to match a 1-tuple.
>
> case (x): # matches the value of x
>
> case (x,): # matches any 1-tuple and binds x

I think it could potentially be confused with a programmer style.
Parenthesis are optional for tuples. Someone could think it could also
write
case x:
to match the value of x, but actually it binds to x and it will be
hard to debug.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4B3XUSEZGCYCQMOFCGRQ3H76MT3GGTJ4/
Code of Conduct: http://python.org/psf/codeofconduct/