[Python-Dev] PEP 563: get_type_hints should use closure when available

2021-02-02 Thread Caleb Donovick
The discussion around PEP 649 got me thinking about what I believe is the
largest downside to PEP 563: the inability to evaluate annotations created
with closures.  While this is in general unavoidable,  if the type is ever
referenced in an annotated function (including as an annotation) it should
be resolvable via `__closure__`.

For example:
```
from __future__ import annotations
import typing
def gen(T):
def f(x: T):
y: T = ...
return f

f = gen(int)
nonlocal_vars = {
  var : cell.cell_contents
  for var, cell in zip(f.__code__.co_freevars, f.__closure__)
}
assert typing.get_type_hints(f, localns=nonlocal_vars)  == {'x': int}
```

I would just open a PR to have `get_type_hints` attempt to resolve closure
variables by default.  However, this would require an update to PEP 563 and
I don't know what the protocol is there.

-  Caleb Donovick
___
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/L2XH2EIFCEPT5DQRPRFR6WYEM6M2LM2V/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 563: get_type_hints should use closure when available

2021-02-03 Thread Caleb Donovick
> Here we want to know what the 'C' refers to in g's annotations. But g's
closures are no help (unless g's body were to also reference C, which is
not likely in typical code).

I understand the limitation.  I was proposing changing
https://github.com/python/cpython/blob/3.9/Lib/typing.py#L1431-L1433 to use
the `nonlocal_vars` instead of `globalns` for the default localns (or
possibly a chainmap of the two).  I agree that it may only work on a small
fraction of code but the performance cost seems pretty minimal especially
for a function like `get_type_hints`, so why not?  But I trust judgement,
if you think that creating an apparent inconsistency around when
`get_type_hints` will work and when it won't is not worth being able to
resolve a few extra cases it probably isn't.

- Caleb Donovick

On Wed, Feb 3, 2021 at 8:55 AM Guido van Rossum  wrote:

> Sadly this won't work, because the annotations are "evaluated" (or not) in
> the surrounding scope, not in the function's scope. Example:
> ```
> >>> def f(a: int):
> ...   class C: pass
> ...   def g(b: C): pass
> ...   return g
> ...
> >>> g = f(1)
> >>> g.__annotations__
> {'b': 'C'}
> >>> g.__closure__
> >>>
> ```
> Here we want to know what the 'C' refers to in g's annotations. But g's
> closures are no help (unless g's body were to also reference C, which is
> not likely in typical code).
>
> --Guido
>
> On Tue, Feb 2, 2021 at 6:10 PM Caleb Donovick 
> wrote:
>
>> The discussion around PEP 649 got me thinking about what I believe is the
>> largest downside to PEP 563: the inability to evaluate annotations created
>> with closures.  While this is in general unavoidable,  if the type is ever
>> referenced in an annotated function (including as an annotation) it should
>> be resolvable via `__closure__`.
>>
>> For example:
>> ```
>> from __future__ import annotations
>> import typing
>> def gen(T):
>> def f(x: T):
>> y: T = ...
>> return f
>>
>> f = gen(int)
>> nonlocal_vars = {
>>   var : cell.cell_contents
>>   for var, cell in zip(f.__code__.co_freevars, f.__closure__)
>> }
>> assert typing.get_type_hints(f, localns=nonlocal_vars)  == {'x': int}
>> ```
>>
>> I would just open a PR to have `get_type_hints` attempt to resolve
>> closure variables by default.  However, this would require an update to PEP
>> 563 and I don't know what the protocol is there.
>>
>> -  Caleb Donovick
>> ___
>> 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/L2XH2EIFCEPT5DQRPRFR6WYEM6M2LM2V/
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
>
> --
> --Guido van Rossum (python.org/~guido)
> *Pronouns: he/him **(why is my pronoun here?)*
> <http://feministing.com/2015/02/03/how-using-they-as-a-singular-pronoun-can-change-the-world/>
>
___
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/T7AYBEUPKPZ7QLI3WRPLMSBU6BPPHOMQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 654 -- Exception Groups and except* : request for feedback for SC submission

2021-02-23 Thread Caleb Donovick
What is the motivation for returning `None` on empty splits?  I feel like
this creates an unnecessary asymmetry.  I don't personally have a use
case for the this feature so I may be missing something but it seems like
it would force an annoying pattern:

```
try:
foo()
except ExceptionGroup as eg:
g1, g2 = eg.split(predicate)
for e in g1:
handle_true(e)
for e in g2:
handle_false(e)
```
Would need to be written:
```
try:
foo()
except ExceptionGroup as eg:
g1, g2 = eg.split(predicate)
if g1 is not None:
for e in g1:
handle_true(e)
if g2 is not None:
for e in g2:
handle_false(e)
```

Also this creates an subtle difference with subgroup:

```
g1, g2 = eg.split(predicate)
h1, h2  = eg.subgroup(predicate), eg.subgroup(lambda e: not predicate(e))
assert g1 == h1 and g2 == h2 # only true if `None not in {g1, g2}`
```

On Mon, Feb 22, 2021 at 4:47 PM Irit Katriel via Python-Dev <
python-dev@python.org> wrote:

>
> Hi all,
>
> We would like to request feedback on PEP 654 -- Exception Groups and
> except*.
>
> https://www.python.org/dev/peps/pep-0654/
>
> It proposes language extensions that allow programs to raise and handle
> multiple unrelated
> exceptions simultaneously, motivated by the needs of asyncio and other
> concurrency libraries,
> but with other use cases as well.
>
> * A new standard exception type,  ExceptionGroup, to represent multiple
> exceptions with
>   shared traceback.
> * Updates to the traceback printing code to display (possibly nested)
> ExceptionGroups.
> * A new syntax except* for handling ExceptionGroups.
>
> A reference implementation (unreviewed) can be found at:
> https://github.com/iritkatriel/cpython/pull/10
>
> Thank you for your help
>
> Kind regards
> Irit, Yury & Guido
>
>
> ___
> 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/L5Q27DVKOKZCDNCAWRIQVOZ5DZCZHLRM/
> 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/WWJ6KLJFZ627UBB4MUTIJQVWWO6LRISO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Request for comments on final version of PEP 653 (Precise Semantics for Pattern Matching)

2021-03-31 Thread Caleb Donovick
> Here, `Child` will *not* match as a sequence, even though it probably
should,

Strong disagree,  if I explicitly set `__match_seq__` to `False` in
`Parent` I probably have a good reason for it and would absolutely expect
`Child` to not match as a sequence.

> - Raise at class definition time if it's set to anything other than True

I feel like this is a consenting adults thing.  Yeah you probably won't
need to set a flag to `False` but I don't see why it should be forbidden.

On Wed, Mar 31, 2021 at 3:35 PM Brandt Bucher 
wrote:

> Guido van Rossum wrote:
> > On Wed, Mar 31, 2021 at 2:14 PM Brandt Bucher brandtbuc...@gmail.com
> > wrote:
> > > (One change from my last email: it doesn't allow `__match_map__` /
> > > `__match_seq__` to be set to `False`... only `True`. This prevents some
> > > otherwise tricky multiple-inheritance edge-cases present in both of our
> > > flagging systems that I discovered during testing. I don't think there
> are
> > > actual use-cases for unsetting the flags in subclasses, but we can
> revisit
> > > that later if needed.)
> > That's surprising to me. Just like we can have a class that inherits from
> > int but isn't hashable, and make that explicit by setting `__hash__ =
> > None`, why couldn't I have a class that inherits from something else that
> > happens to inherit from Sequence, and say "but I don't want it to match
> > like a sequence" by adding `__match_sequence__ = False`? AFAIK all Mark's
> > versions would support this by setting `__match_kind__ = 0`.
>
> The issue isn't when *I* set `__match_seq__ = False` or
> `__match_container__ = 0`. It's when *one of my parents* does it that
> things become difficult.
>
> > Maybe you can show an example edge case where this would be undesirable?
>
> Good idea. I've probably been staring at this stuff for too long to figure
> it out myself. :)
>
> As far as I can tell, these surprising cases arise because a bit flag can
> only be either 0 or 1. For us, "not specified" is equivalent to 0, which
> can lead to ambiguity.
>
> Consider this case:
>
> ```
> class Seq:
> __match_seq__ = True
> # or __match_container__ = MATCH_SEQUENCE
>
> class Parent:
> pass
>
> class Child(Parent, Seq):
> pass
> ```
>
> Okay, cool. `Child` will match as a sequence, which seems correct. But
> what about this similar case?
>
> ```
> class Seq:
> __match_seq__ = True
> # or __match_container__ = MATCH_SEQUENCE
>
> class Parent:
> __match_seq__ = False
> # or __match_container__ = 0
>
> class Child(Parent, Seq):
> pass
> ```
>
> Here, `Child` will *not* match as a sequence, even though it probably
> should. The only workarounds I've found (like allowing `None` to mean "this
> is unset, don't inherit me if another parent sets this flag", ditching
> tp_flags entirely, or not inheriting these attributes) feel a bit extreme
> just to allow some users to do the moral equivalent of un-subclassing
> `collections.abc.Sequence`.
>
> So, my current solution (seen on the branch linked in my earlier email) is:
>
> - Set the flag if the corresponding magic attribute is set to True in the
> class definition
> - Raise at class definition time if it's set to anything other than True
> - Otherwise, set the flag if any of the parents set have the flag set
>
> As far as I can tell, this leads to the expected (and current, as of
> 3.10.0a6) behavior in all cases. Plus, it doesn't break my mental model of
> how inheritance works.
> ___
> 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/R3BGDN6NINJMLUWBVMVYIGORSLPJOMJP/
> 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/PRCDAGDDSJGLEVXFEPX26VB7JENYEDAF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Request for comments on final version of PEP 653 (Precise Semantics for Pattern Matching)

2021-03-31 Thread Caleb Donovick
> It's a stronger statement than simply undoing
> the declaration that it's a sequence. There would be no way to reset
> to the default state.

How is this different from anything else that is inherited?

The setting of a flag to `False` is not some irreversible process which
permanently blocks child classes from setting that flag to `True`.
If I want to give priority to `Seq` over `Parent` in Brandt's original
example I need only switch the order of inheritance so that `Seq` is
earlier in `Child` MRO or explicitly set the flag to `True` (or
`Seq.__match_seq__`).  In contrast Brandt's scheme does irreversibly
set flags, there is no way to undo the setting of `__match_seq__` in a
parent class.

This really doesn't seem like an issue to me.  I can't personally think of
a use case for explicitly setting a flag to `False`
 but I also don't see why it should be forbidden. We get "- Otherwise, set
the flag if any of the parents set have the flag set"
for free through normal MRO rules except in the case where there is an
explicit `False` (which I assume will be exceedingly rare
and if it isn't there is clearly some use case).  Why make it more
complicated?

On Wed, Mar 31, 2021 at 6:05 PM Chris Angelico  wrote:

> On Thu, Apr 1, 2021 at 11:54 AM Caleb Donovick 
> wrote:
> >
> > > Here, `Child` will *not* match as a sequence, even though it probably
> should,
> >
> > Strong disagree,  if I explicitly set `__match_seq__` to `False` in
> `Parent` I probably have a good reason for it and would absolutely expect
> `Child` to not match as a sequence.
> >
>
> How much difference is there between:
>
> class Grandparent:
> """Not a sequence"""
> class Parent(Grandparent):
> """Also not a sequence"""
> class Child(Parent):
> """No sequences here"""
>
> and this:
>
> class Grandparent(list):
> """Is a sequence"""
> class Parent(Grandparent):
> """Explicitly not a sequence"""
> __match_seq__ = False
> class Child(Parent):
> """Shouldn't be a sequence"""
>
>
> ? Either way, Parent should function as a non-sequence. But if Child
> inherits from both Parent and tuple, it is most definitely a tuple,
> and therefore should be a sequence.
>
> With your proposed semantics, setting __match_seq__ to False is not
> simply saying "this isn't a sequence", but it's saying "prevent this
> from being a sequence". It's a stronger statement than simply undoing
> the declaration that it's a sequence. There would be no way to reset
> to the default state.
>
> Brandt's proposed semantics sound complicated, but as far as I can
> tell, they give sane results in all cases.
>
> ChrisA
> ___
> 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/GKOUSL2CPMO7NPPTK2E7XE7LXTPDVRDJ/
> 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/UWSPAA27Q2ZE44YHK7ZKQCO5YZ2HG32F/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-21 Thread Caleb Donovick
My personal motivating example for PEP 637 was shorthand for protocols.
`x: Protocol[foo=int, bar=Callable[str, int]]` could say x has attribute
foo which is an int and method bar from str to int.



On Wed, Apr 21, 2021 at 4:23 PM Paul Bryan  wrote:

> I agree, that's duck typing with a protocol, and precisely the tedious
> type style I would want to avoid.
>
> I don't know what would be a good suggestion. Something where you
> reference a "fully equipped" type and cherry pick the attributes you want?
> Something like `Protocol[Duck, ("quack", "waddle")]`?
>
> Paul
>
>
> On Wed, 2021-04-21 at 16:13 -0700, Jelle Zijlstra wrote:
>
>
>
> El mié, 21 abr 2021 a las 15:30, Paul Bryan () escribió:
>
> As demonstrated, protocols don't get us there because duck typing isn't a
> matter of having an object exhibit all of the attributes of a duck, but
> rather some subset of attributes to be used by the consumer. I want this
> duck to quack; someone else will want it to waddle. I don't see how type
> hints could reasonably support "file like object" in the duck type sense
> (unless the consumer were to specify the exact attributes of the duck it's
> interested in, which I fear would become a tedious type writing style). '
>
>
> This approach (a Protocol that declares exactly what you need the
> file-like object to do) is in fact what we've been doing in typeshed, the
> repository that provides type hints for the standard library. For those
> unfamiliar, it would look something like this:
>
> from typing import Protocol
>
> class SupportsRead(Protocol):
> def read(self) -> bytes: ...
>
> def uses_a_file(f: SupportsRead) -> None:
>  f.read()
>
> That's somewhat tedious, to be sure, but it is working duck typing.
>
>
>
> I too have sensed static typing driving the typing development agenda in
> Python recently, causing other typing methods to take a back seat, so to
> speak. I add my voice to those requesting Python handle other typing
> methods.
>
> Barring an innovation to allow a "subset" of a type to be declared in a
> type hint, I would conclude that static typing and duck typing are
> diametrically opposed. If we agree that both are valuable, developers could
> build consensus on that point, and work to ensure that one does not move
> forward at the expense of the other.
>
> What would you suggest? Should the syntax for declaring Protocols be more
> concise?
>
>
>
> Paul
>
> On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote:
>
> Thanks Mark for posting this. I know some of us are uneasy about the pace
> of the typing train 
>
> On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith  wrote:
>
> > If you guarded your code with `isinstance(foo, Sequence)` then I could
> > not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> > forced to use nominal typing; inheriting from Sequence, or explicitly
> > registering as a Sequence.
>
> You say this like it's a bad thing, but how is this avoidable, even in
> principle? Structural typing lets you check whether Foo is duck-shaped
> -- has appropriate attribute names, etc. But quacking like a duck is
> harder: you also have to implement the Sequence behavioral contract,
> and realistically the only way to know that is if the author of Foo
> tells you.
>
>
> But that's not what duck typing is (at least to me :-) ) For a given
> function, I need the passed in object to quack (and yes, I need that quack
> to sound like a duck) -- but I usually don't care whether that object
> waddles like a duck.
>
> So yes, isinstance(obj, Sequence) is really the only way to know that obj
> is a Sequence in every important way -- but if you only need it to do one
> or two things like a Sequence, then you don't care.
>
> And this is not uncommon -- I suspect it's very rare for a single function
> to use most of the methods of a given ABC (or protocol, or whatever).
>
> And a lot of the standard library works exactly this way. Two examples
> (chosen arbitrarily, I just happen to have thought about how they work):
>
> json.load() simply calls ``fp.read()``, and passes the result on down to
> json.loads(). That's it -- no checking of anything.
>
> If fp does not have a read() method, you get an AttributeError. If fp has
> a read() method, but it returns something other than a string, then you get
> some other Exception. And if it returns a string, but that string isn't
> valid JSON, you get yet another kind of error.
>
> In short, json.load(fp, ...) requires fp to have a read() method that
> returns a valid JSON string. But it doesn't check, nor does it need to, if
> it's getting an actual io.TextIOBase object. Is that the right one? I'm not
> totally sure, which I kind of think makes my point -- I've been using
> "file-like" objects for years (decades) without worrying about it.
>
> Example 2:
>
> The str.translate method takes:
>
> "a mapping of Unicode ordinals to Unicode ordinals, strings, or None"
>
> Ok, then you need to pass in a Mapping, yes? Well, no you

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-23 Thread Caleb Donovick
We can add .keys() to Mapping to distinguish Mapping and Sequence.
But it is breaking change, of course. We shouldn’t change it.

We could use the presence of .keys in the subclasses hook only after first
checking
explicit cases (i.e. actual subclass or has been registered). Yes this
would break code
that uses issubclass(X, Mapping) where X looks mapping but isn’t a mapping.
But is this really a concern? What if X had to have all 3 keys, values, and
items
to qualify? Are there really a bunch of classes with __getitem__,
__len__, __iter__, keys, values, and items where the class is expected to
not
be considered a subclass of Mapping?

If there really is a classes like this we could add a warning the subclass
hook about saying
that in a feature version that X is going to be considered a mapping.
Additionally we
could add a black list to the ABCs which would function like the inverse of
register.


On Thu, Apr 22, 2021 at 7:32 PM Inada Naoki songofaca...@gmail.com
 wrote:

On Fri, Apr 23, 2021 at 10:33 AM Chris Angelico  wrote:
> >
> > On Fri, Apr 23, 2021 at 11:22 AM Larry Hastings 
> wrote:
> > >
> > >
> > > On 4/20/21 10:03 AM, Mark Shannon wrote:
> > >
> > > If you guarded your code with `isinstance(foo, Sequence)` then I could
> not use it with my `Foo` even if my `Foo` quacked like a sequence. I was
> forced to use nominal typing; inheriting from Sequence, or explicitly
> registering as a Sequence.
> > >
> > >
> > > If I'm reading the library correctly, this is correct--but, perhaps,
> it could be remedied by adding a __subclasshook__ to Sequence that looked
> for an __iter__ attribute.  That technique might also apply to other ABCs
> in collections.abc, Mapping for example.  Would that work, or am I missing
> an critical detail?
> > >
> >
> > How would you distinguish between a Sequence and a Mapping? Both have
> > __iter__ and __len__. Without actually calling those methods, how
> > would the subclass hook tell them apart?
> >
> > ChrisA
>
> We can add .keys() to Mapping to distinguish Mapping and Sequence.
> But it is breaking change, of course. We shouldn't change it.
>
> I think using ABC to distinguish sequence or mapping is a bad idea.
>
> There are three policies:
>
> a) Use duck-typing; just us it as sequence. No type check at all.
> b) Use strict type checking; isinstance(x, list) / isinstance(x, (list,
> tuple)).
> c) Use ABC.
>
> But (c) is broken by design. It is not fixable.
> IMHO, We should chose (a) or (b) and reject any idea relying on Sequence
> ABC.
>
> Regards,
>
> --
> Inada Naoki  
> ___
> 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/ESLOPO4GLC2QZW4ZDBYEQDPPGB4ZYDWM/
> 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/ZJQMGI7345TC4AU4MQTWZZA2ENK4NWAL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 622 version 2 (Structural Pattern Matching)

2020-07-30 Thread Caleb Donovick
Adding this feature would be a giant quality of life improvement for me and
I really hope it succeeds.  So I have been trying to keep up on the debate
in this and related thread.

While I do want this feature,  I agree with a lot of the issues people are
raising.

First I agree that _ should not be the wildcard symbol.  Or rather the
hobgoblins in my mind think that if _ is to be the wildcard symbol it would
be more consistent with assignment if it was bound to the last value it was
matched with (as should other repeated identifiers) e.g.,

match pt:
   case (x, _, _):
   assert _ == pt[2]

I understand the authors rationalize the decision based on conventions with
the gettext module.  I find these arguments very unconvincing.  It's like
saying the identifier np should be forbidden from appearing in cases
because it's frequently used as the name of numpy.  If there is to be a
wildcard symbol (that does not bind and is repeatable) it should not be a
valid identifier.

Second,  the distinction between a capture and constant value pattern
should be more explicit.  I don't have any great insight into the color of
the shed beyond the numerous suggestions already made (name=, ?name,
etc...), but it  seems quite unintuitive to me that I can't capture into a
namespace nor match a constant without a namespace.  It is also unclear to
me why it would be so terrible to add a new token or abuse an existing one.

> Honestly, it doesn't help the case for `?` that it's been proposed as a
mark for both capture patterns and value patterns (by different people,
obviously :-).

I agree that most of the proposed sheds don't necessarily make it
intuitively clear what is a capture variable vs what is a constant.
However they do give the programmer the ability to choose.

For example if I want to modify the motivating example from the PEP
slightly to copy attributes from one point to another I can't express it
concisely:

def update_point_3d(p: Point3d, pt):
match pt:
case (x, y):
p.x, p.y = x, y
case Point2d(x, y):
p.x, p.y = x, y
...


(Okay I could have just called the original make_point_3d and unpacked the
results but it would require the creation of an unnecessary temporary.)

However if the capture was explicit and any valid target could be used as a
capture variable then I could express this cleanly:

def update_point_3d(p: Point3d, pt):
match pt:
case (p.x=, p.y=):
pass
case Point2d(p.x=, p.y=):
    pass
...


 - Caleb Donovick
___
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/VJ7XJE4JEPK2FGKGB7AG4IHFYKOXFVU5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: PEP 622 version 2 (Structural Pattern Matching)

2020-08-02 Thread Caleb Donovick
 >  `np` analogue is quite a stretch and far-fetched, really.

I don't disagree.  But `_` is a valid identifier so it shouldn't be
special. The solution is incredibly simple: allow repeated identifiers just
like in assignment so there is no need for a special wildcard symbol.

> ..

I disagree but this is philosophical discussion which I would rather not go
down.

> ..

That's reasonable, although I would argue that a match is more like a for
loop (which allows arbitrary assignment) than a function definition.  I do
understand your point though.

However, I still think the inability to match against a constant not in a
namespace is very annoying and could be overcome with some explicit
syntax.   It's reasonable for this syntax to only allow NAME to be bound
(many places in the grammar do this, def, class, as, ...) but I haven't
seen a satisfactory reason why there *shouldn't* be support for NAME
constants; just reasons for why it's tricky.

You (or one of the authors) argue against `.constant` as a matching syntax
by saying:"..., it introduces strange-looking new syntax without making
the pattern syntax any more expressive."  but this is obviously false.   It
clearly does make the syntax more expressive, it allows one to express
something naturally without needing to create an auxiliary structure (or
the match syntax doesn't make the language more expressive either).  Yes
namespaces are a great idea but as a consenting adult I should be free to
have constants that are not in a namespace.  My constant may come in any
number of forms that are not conducive to simply "wrapping it in a
namespace", for example it may be used in other modules (so wrapping it
would require external changes) or it might be a closure variable and so
would require some explicit wrapping step.

Further, you argue elsewhere that the we shouldn't worry about a syntax
being strange because it's new so of course it's going to be different.
Yet for invoke this reasoning as a way to reject solutions to the NAME
constant issue.  Pick one. (preferably the version that includes match
syntax and some strange new syntax for explicit constants because I super
want the match syntax).

Caleb Donovick

On Fri, Jul 31, 2020 at 12:40 AM Tobias Kohn  wrote:

> Hi Caleb,
>
> I will only answer to the second part, as the wildcard issue has
> been brought up and discussed time and again, and the `np`
> analogue is quite a stretch and far-fetched, really.
>
> One thing that stood out a bit to me as I feel to have seen it a
> couple of times is the question of intuition, so I will add a few
> more general thoughts to that...
>
> > [...] but it  seems quite unintuitive to me [...]
>
> > [...] don't necessarily make it intuitively clear [...]
>
>
>
> Intuition (or lack thereof) has already been brought forward
> as an argument a couple of times.  I would just like to briefly
> point out that there is no such thing as universal intuition in
> the field of programming.  We all have different training,
> skills, preferences and experiences, which make up what
> we call 'intuition'.  But what is intuitive is usually something
> completely different to C-programmer than to a Haskell- or
> Lisp-Programmer, say.  And since pattern matching is really
> a new feature to be introduced to Python, a feature that can
> be seen in different lights, there is no 'Python-Programmer
> intuition' that would apply in this case.
>
> As for beginners, virtually every part of programming is
> unintuitive at first.  Even something innocuous-looking like
> assignment is often reason for confusion because `3 + 4 = x`
> would probably be more 'intuitive'.  But there is good reason
> with regards to the bigger picture to stick to `x = 3 + 4`.
>
> A Python-programmer (at any level) not familiar with pattern
> matching will most likely not understand all subtlety of the
> syntax---but this is alos true of features like `async` or the
> `/` in parameters, say.  I would argue, though, that the clear
> choice of keywords allow anyone to quickly look pattern
> matching up and get informed on what it does.  So, we do
> not need to come with something that is entirely 'intuitive'
> and 'self-evident'.  But by sticking to common convention
> like `_` as wildcard, we can help quickly build the correct
> intuition.
>
>
> In your examples, for instance, it is perfectly obvious to me
> that you cannot directly assign to attributes and it would in
> fact look very weird to my eyes if you could.  Your use case
> is quite similar to initialisers and you are arguing that you
> would like being able to write:
> ```
> *class* Point:
> *def* __init__(self, self.x, self.y):
>