Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Amit Green
On Thu, Jul 26, 2018 at 1:09 AM, Steven D'Aprano 
wrote:

> On Thu, Jul 26, 2018 at 01:02:47AM -0400, Amit Green wrote:
>
> > 3.  The problem is way deeper than simply adding '?.' and other
> operators.
> > For real use cases, you also need to say "how far" the an operator can
> > "spread" -- and this is real hard to solve.
>
> Why do you think that is the case? No other operators "spread". Why
> should these?
>

If you take 'a?.b.c' then if the first '?.' yields none, logically you
don't want to evaluate the second '.'; otherwise you have to write:

a?.b?.c -- And this starts to look like line noise.

If you also implemented a concept such as use non-aware operators in
function calls: such as:

f(a, b?, c) -- which would mean collapse the whole thing out of
non-existance if 'b' yields none (i.e.: don't call function f) -- how far
does this spread?  Outside of f, if you then write:

f(a, b?, c).d.e

Does this also mean don't evaluate the '.d' & '.e' ?

And both of these examples are from *REAL* uses cases in my code I would
want to use none-aware operators.


>
> > 4.  Coming up with a readable syntax that doesn't look like line noise is
> > really hard; and very subjective.
>
> Define "line noise".
>
> Is a.b.c syntax line noise?
>
> Is a**b**c syntax line noise?
>
> Is a == b == c line noise?
>
>
>
These examples, from python, all look great & are very readable.  Which is
why python is such a great language :)

Simple non-aware operators are also very readable, such as: a?.b

This starts to become unreadable & line noise: a?.b.c.d ?? "hi".

Again, though it is subjective -- as is clearly evident by the discussions
in this group.

My simple point above is -- I really do want this feature -- but having
tried for days, I can't come up with a really clean syntax to capture all
of my *OWN* use cases ... let alone others...

Anyway, as I said, I think we have more important issues to address right
now, than this very difficult issue & I'll write up more tomorrow.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Steven D'Aprano
On Thu, Jul 26, 2018 at 01:02:47AM -0400, Amit Green wrote:

> 3.  The problem is way deeper than simply adding '?.' and other operators.
> For real use cases, you also need to say "how far" the an operator can
> "spread" -- and this is real hard to solve.

Why do you think that is the case? No other operators "spread". Why 
should these?


> 4.  Coming up with a readable syntax that doesn't look like line noise is
> really hard; and very subjective.

Define "line noise".

Is a.b.c syntax line noise?

Is a**b**c syntax line noise?

Is a == b == c line noise?



-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Steven D'Aprano
On Wed, Jul 25, 2018 at 11:09:35PM -0400, David Mertz wrote:

> Chris Angelica provided a more accurate translation.  Do you not see that
> the fact that your *second* try at understanding the actual behavior is
> still wrong suggest that this operator is a HUGE bug magnet?!

Oh what a load of FUD.

The whole point of having an operator do this means that we don't have 
to duplicate the semantics of the operator in plain Python.

Very few people get the semantics of x + y right. If (generic) you think 
that it is:

return x.__add__(y)

you're wrong. If you think it is:

try:
return x.__add__(y)
except AttributeError:
return y.__radd__(x)

you're still wrong. If you think it is something like this:

try:
adder = type(x).__add__
operands = (x, y)
except AttributeError:
try:
adder = type(y).__radd__
operands = (y, x)
except AttributeError:
raise TypeError from None
return adder(*operands)

you're still wrong. But *nobody cares* because outside of some 
incredibly rare and specialised uses, nobody needs to emulate the 
semantics of + in pure Python. They just call the + operator, or at 
worst call the operator.add function.

We have the syntax "yield from" because it is *really complicated* for 
one generator to delegate to another generator. Emulating the yield from 
call isn't necessary, because we have yield from.

(If you think that "yield from" is equivalent to "for x in subgenerator: 
yield x", you're wrong too.)

And likewise, if we have these new operators, that means that those who 
need them won't have to emulate them in pure Python. They can just use 
the operators.

The idea that using the operators will be "a bug magnet" because the 
implementation is (allegedly) complex is ludicrous.


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Amit Green
 On Thu, Jul 26, 2018 at 12:25 AM, Raymond Hettinger <
raymond.hettin...@gmail.com> wrote:

> It probably is the wrong time and probably can hurt (by introducing
> divisiveness when we most need for be focusing on coming together).
>
> This PEP also shares some traits with PEP 572 in that it solves a somewhat
> minor problem with   new syntax and grammar changes that affect the look
> and feel of the language in a way that at least some of us (me for example)
> find to be repulsive.
>
> This PEP is one step further away from Python reading like executable
> pseudo-code.  That trait is currently a major draw to the language and I
> don't think it should get tossed away just to mitigate a minor irritant.
>

+1.

Also this whole none-aware problem is really really complicated, so I'd
like to add a few thoughts:

1.  I spent a few days on it last year, and came to the following
conclusions:

2.  It is a *really* useful feature -- that I want in quite a lot of code
that I write.

3.  The problem is way deeper than simply adding '?.' and other operators.
For real use cases, you also need to say "how far" the an operator can
"spread" -- and this is real hard to solve.

4.  Coming up with a readable syntax that doesn't look like line noise is
really hard; and very subjective.

Based on all that, I have to agree -- now is not the time to try to resolve
these issues, there are more important issues to resolve -- I'll write more
on that tomorrow.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Thu, Jul 26, 2018 at 12:17 AM David Mertz  wrote:

> On Thu, Jul 26, 2018 at 12:00 AM Nicholas Chammas <
> nicholas.cham...@gmail.com> wrote:
>
>> Forgive me for being slow. I'm missing what's different in semantics
>> between the translation above and Chris's translation below:
>>
>
> You are VERY close now.  You have more SPAM, so yours is better:
>



Understood. Thanks for clarifying. I think Chris was referring to this in
an earlier message (when I made my first attempt at translating) when he
said:

> Aside from questions of repeated evaluation/assignment, yes. The broad
> semantics should be the same.

So the meaning of my translation matches the "intention" of the original
PEP 505 expression, but I see the danger in offering up such loose
translations. Getting the meaning right but missing important details (like
repeated evaluation) does not inspire confidence.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Raymond Hettinger


> On Jul 18, 2018, at 10:43 AM, Steve Dower  wrote:
> 
> Possibly this is exactly the wrong time to propose the next big syntax 
> change, since we currently have nobody to declare on it, but since we're 
> likely to argue for a while anyway it probably can't hurt (and maybe this 
> will become the test PEP for whoever takes the reins?).

It probably is the wrong time and probably can hurt (by introducing 
divisiveness when we most need for be focusing on coming together).

This PEP also shares some traits with PEP 572 in that it solves a somewhat 
minor problem with   new syntax and grammar changes that affect the look and 
feel of the language in a way that at least some of us (me for example) find to 
be repulsive.

This PEP is one step further away from Python reading like executable 
pseudo-code.  That trait is currently a major draw to the language and I don't 
think it should get tossed away just to mitigate a minor irritant.

We should also consider a moratorium on language changes for while.  There is 
more going on than just a transition to a post-bdfl world.  The other 
implementations of Python are having a hard time keeping up with our recent, 
ferocious rate of change.  Even among the core developers, most people are not 
fully up to date learning all the new features that have already been added 
(how many of you are competent with typing, data classes, generalized 
unpacking, concurrent futures, async, the scoping rules for exceptions and 
comprehensions, the hundreds of niggling changes in the past few releases, 
__init_subclass__, __set_name__, details of import logic, issues with SSL 
certificates, new collections ABCs, etc.?)  We've been putting major changes in 
faster than anyone can keep up with them.  We really need to take a breath.


Raymond




___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Thu, Jul 26, 2018 at 12:00 AM Nicholas Chammas <
nicholas.cham...@gmail.com> wrote:

> Forgive me for being slow. I'm missing what's different in semantics
> between the translation above and Chris's translation below:
>

You are VERY close now.  You have more SPAM, so yours is better:

In [1]: class Spam:
   ...: @property
   ...: def eggs(self):
   ...: print("SPAM SPAM SPAM")
   ...: return "eggs"
   ...:
In [2]: spam = Spam()
In [3]: _tmp = spam
In [4]: if _tmp is not None:
   ...:  _tmp = _tmp.eggs
   ...:  if _tmp is not None:
   ...:  _tmp = _tmp.bacon
   ...: food = _tmp
   ...: del _tmp
   ...: food
   ...:
SPAM SPAM SPAM
-
AttributeError  Traceback (most recent call last)
 in ()
  2  _tmp = _tmp.eggs
  3  if _tmp is not None:
> 4  _tmp = _tmp.bacon
  5 food = _tmp
  6 del _tmp

AttributeError: 'str' object has no attribute 'bacon'
In [5]: if spam is not None and spam.eggs is not None:
   ...: food = spam.eggs.bacon
   ...:
SPAM SPAM SPAM
SPAM SPAM SPAM
-
AttributeError  Traceback (most recent call last)
 in ()
  1 if spam is not None and spam.eggs is not None:
> 2 food = spam.eggs.bacon
  3

AttributeError: 'str' object has no attribute 'bacon'



-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
BTW, even for the "compare to None" issue, the situation in 0.1.1 isn't as
bad as you might think.  Definitely a ""
cannot be compared as "is None".  But even there, this works:

>>> NullCoalesce(spam).bacon

>>> NullCoalesce(spam).bacon == None
True
>>> NullCoalesce(spam).bacon == 0
False
>>> NullCoalesce(spam).bacon is None
False


So yeah, the docs should say "If you are using the `coalescing` library,
use `==` rather than `is` to compare values with None".

Yes, that's contrary to best style in general Python... but it's a pretty
small change to make in that specialized code that needs to deal with
"hierarchical semi-structured data that uses None (rather than missing
attributes or other sentinels) to mark unreachable branches."


On Wed, Jul 25, 2018 at 11:53 PM David Mertz  wrote:

> On Wed, Jul 25, 2018, 11:27 PM Chris Angelico  wrote:
>
>> > That's a bug in my proxy too.  I'll figure out how to fix it in 0.1.2
>> soon.
>> > This is early alpha, and the things you're noting are valuable bug
>> reports.
>> > But none of this is fundamentally unfixable in a library, nor even
>> > especially difficult.
>>
>> If you're going to make that work, then by definition you would be
>> wrapping up the None, right? Which would mean that every one of the
>> prints would say "". Which, in turn,
>> means that you cannot do this:
>>
>> >>> NullCoalesce(spam).nil is None
>>
>> or rather, it will always be False. With PEP 505, you most certainly
>> *can* do this check, because it would really truly be None.
>>
>> This IS fundamentally unfixable in a library.
>>
>
> If your meaning of "fix" is simply "add new syntax", of course that's
> true. If it's "solve the actual problem that motivates the PEP" I can
> definitely fix it.
>
> Right now, you can still always call .unbox() at the end to get the
> underlying value. I agree that's a little ugly, hence why I added the wrapt
> proxy stuff. Most operations trigger unboxing, but indeed not simply
> echoing to the shell.
>
> I think I'll add a property spelled '_' to make it less busy (but more
> cryptic, I know). E.g.
>
> NullCoalesce(spam).nil.nil.nil._ is None'
>
> I also added an unbox() function that will pass through non-proxy objects
> untouched. So it's safe to unbox anything if you are unsure what it is.
>
> Of course I'm not claiming any library is without a need to work with it's
> quirks and limits. But they are very few even in this 4-hours-of-work alpha.
>
>>

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 11:09 PM David Mertz  wrote:

> On Wed, Jul 25, 2018 at 10:50 PM Nicholas Chammas <
> nicholas.cham...@gmail.com> wrote:
>
>> Indeed. Thanks for the counter-example. I think the correct translation
>> is as follows:
>> food = spam?.eggs?.bacon
>> Becomes:
>> food = None
>> if spam is not None and spam.eggs is not None:
>> food = spam.eggs.bacon
>>
> Did I get it right now? :)
>>
>
> Nope, still not right, I'm afraid!
>
> Chris Angelica provided a more accurate translation.
>

Forgive me for being slow. I'm missing what's different in semantics
between the translation above and Chris's translation below:

_tmp = spam
> if _tmp is not None:
> _tmp = _tmp.eggs
> if _tmp is not None:
> _tmp = _tmp.bacon
> food = _tmp
>

What's a case where they would do something different?

* If spam is None, they work the same -> None
* If spam is not None, but spam.eggs exists and is None, they work the same
-> None
* If spam is not None, but spam.eggs doesn't exist, they work the same ->
AttributeError
* If spam is not None, and spam.eggs is not None, but spam.eggs.bacon is
None, they work the same -> None
* If spam is not None, and spam.eggs is not None, but spam.eggs.bacon
doesn't exist, they work the same -> AttributeError
* If spam is not None, and spam.eggs is not None, and spam.eggs.bacon is
not None, they work the same -> bacon
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018, 11:27 PM Chris Angelico  wrote:

> > That's a bug in my proxy too.  I'll figure out how to fix it in 0.1.2
> soon.
> > This is early alpha, and the things you're noting are valuable bug
> reports.
> > But none of this is fundamentally unfixable in a library, nor even
> > especially difficult.
>
> If you're going to make that work, then by definition you would be
> wrapping up the None, right? Which would mean that every one of the
> prints would say "". Which, in turn,
> means that you cannot do this:
>
> >>> NullCoalesce(spam).nil is None
>
> or rather, it will always be False. With PEP 505, you most certainly
> *can* do this check, because it would really truly be None.
>
> This IS fundamentally unfixable in a library.
>

If your meaning of "fix" is simply "add new syntax", of course that's true.
If it's "solve the actual problem that motivates the PEP" I can definitely
fix it.

Right now, you can still always call .unbox() at the end to get the
underlying value. I agree that's a little ugly, hence why I added the wrapt
proxy stuff. Most operations trigger unboxing, but indeed not simply
echoing to the shell.

I think I'll add a property spelled '_' to make it less busy (but more
cryptic, I know). E.g.

NullCoalesce(spam).nil.nil.nil._ is None'

I also added an unbox() function that will pass through non-proxy objects
untouched. So it's safe to unbox anything if you are unsure what it is.

Of course I'm not claiming any library is without a need to work with it's
quirks and limits. But they are very few even in this 4-hours-of-work alpha.

>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Chris Angelico
On Thu, Jul 26, 2018 at 1:19 PM, David Mertz  wrote:
> On Wed, Jul 25, 2018 at 11:08 PM Chris Angelico  wrote:
>>
>> > Yeah, yeah.  I know it's alpha software I wrote two nights ago, and
>> > slightly
>> > patched 5 minutes before that post.  You fixed those concerns; I'll
>> > happily
>> > take PRs on fixing them better.
>>
>> PRs? Nope. I don't think it's possible to do this with correct
>> semantics without language support.
>>
>> With PEP 505, I could write this:
>>
>> >>> print(spam?.nil?.nil?.nil?.nil)
>> None
>>
>> Can you do that with your proxy?
>
>
> Oh yeah.  You are right! Thank you.
>
> That's a bug in my proxy too.  I'll figure out how to fix it in 0.1.2 soon.
> This is early alpha, and the things you're noting are valuable bug reports.
> But none of this is fundamentally unfixable in a library, nor even
> especially difficult.

If you're going to make that work, then by definition you would be
wrapping up the None, right? Which would mean that every one of the
prints would say "". Which, in turn,
means that you cannot do this:

>>> NullCoalesce(spam).nil is None

or rather, it will always be False. With PEP 505, you most certainly
*can* do this check, because it would really truly be None.

This IS fundamentally unfixable in a library.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018 at 11:08 PM Chris Angelico  wrote:

> > Yeah, yeah.  I know it's alpha software I wrote two nights ago, and
> slightly
> > patched 5 minutes before that post.  You fixed those concerns; I'll
> happily
> > take PRs on fixing them better.
>
> PRs? Nope. I don't think it's possible to do this with correct
> semantics without language support.
>
> With PEP 505, I could write this:
>
> >>> print(spam?.nil?.nil?.nil?.nil)
> None
>
> Can you do that with your proxy?
>

Oh yeah.  You are right! Thank you.

That's a bug in my proxy too.  I'll figure out how to fix it in 0.1.2
soon.  This is early alpha, and the things you're noting are valuable bug
reports.  But none of this is fundamentally unfixable in a library, nor
even especially difficult.

I doubt I'll ever even use my own software.  It's just a proof-of-concept
that we can achieve the ACTUAL purpose of PEP 505 with no language
changes.  I don't very often have a need to solve the problem PEP 505
does... even though I very often work in the very domain it is intended to
address (semi-structured nested data).  Even if the PEP could be a little
bit more elegant for a very few circumstances, it's just not anywhere close
to deserving syntax... especially not syntax that even proponents tend to
misunderstand the semantics of.

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018 at 10:50 PM Nicholas Chammas <
nicholas.cham...@gmail.com> wrote:

> Indeed. Thanks for the counter-example. I think the correct translation is
> as follows:
> food = spam?.eggs?.bacon
> Becomes:
> food = None
> if spam is not None and spam.eggs is not None:
> food = spam.eggs.bacon
>
Did I get it right now? :)
>

Nope, still not right, I'm afraid!

Chris Angelica provided a more accurate translation.  Do you not see that
the fact that your *second* try at understanding the actual behavior is
still wrong suggest that this operator is a HUGE bug magnet?!


> So, shame on me. I think this particular mistake reflects more on me than
> on PEP 505, but I see how this kind of mistake reflects badly on the folks
> advocating for the PEP (or at least, playing devil's advocate).
>

I really, really don't.  I think you see an intuitive behavior that would
be nice and useful in a certain area.  That behavior just isn't what the
PEP proposes though... it's kinda-sorta close enough to be lured into
thinking it's a good idea.

Honestly, I think the behavior of GreedyAccess in my little library I wrote
over the last couple nights is FAR more often what programmers ACTUALLY
want than NullCoalesce is.  Even Steve Dower—in the PEP and in this
discussion—acknowledges the appeal and utility of the GreedyAccess
behavior.  It's in the "Rejected Ideas" section, which is fair enough.

But in a library like mine... or indeed, in a much better library that you
or someone else writes... it's perfectly easy to have both classes, and
choose which behavior is more useful for your case.  A new syntax feature
can't let user decide which behavior (or maybe some other behavior
altogether) is most useful for their specific case.  A library does that
easily[*].

[*] In version 0.1.1 of coalescing—changed from 0.1—I added the option to
use a sentinel other than None if you want.  I'm not sure how useful that
is, but that idea was in some old PEPs, and I think in the Rejected Ideas
of 505.  With a library, I have a parameter that need not be used to switch
that[**].  E.g.:

NullCoalesce(foo, sentinel=float('nan')).bar.baz.blam

[**] Yes, I even handle NaN's in a special way because they are non-equal
even to themselves.  You could use empty string, or 0, or my_null =
object(), or whatever.
-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Chris Angelico
On Thu, Jul 26, 2018 at 12:56 PM, David Mertz  wrote:
> On Wed, Jul 25, 2018 at 10:41 PM Chris Angelico  wrote:
>>
>> A bit problematic. But after (a) figuring out that your module is
>> named "coalesce" even though I installed "coalescing" AND (b) going
>> and separately installing wrapt, and finally (c) doing the import that
>> you didn't mention, we still have this fundamental problem:
>
>
> Yeah, yeah.  I know it's alpha software I wrote two nights ago, and slightly
> patched 5 minutes before that post.  You fixed those concerns; I'll happily
> take PRs on fixing them better.

PRs? Nope. I don't think it's possible to do this with correct
semantics without language support.

>> >>> spam.nil = None
>> >>> print(NullCoalesce(spam).nil.nil)
>> None
>> >>> print(NullCoalesce(spam).nil.nil.nil)
>> Traceback (most recent call last):
>>   File "", line 1, in 
>> AttributeError: 'NoneType' object has no attribute 'nil'
>
>
> Why is this wrong? This is EXACTLY the same behavior as the `?.` operator
> would have in the last case.  Do you not recognize the behavior you are
> advocating in PEP 505?

With PEP 505, I could write this:

>>> spam = SimpleNamespace()
>>> spam.nil = None
>>> print(spam?.nil)
None
>>> print(spam?.nil?.nil)
None
>>> print(spam?.nil?.nil?.nil)
None
>>> print(spam?.nil?.nil?.nil?.nil)
None

Can you do that with your proxy?

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Chris Angelico
On Thu, Jul 26, 2018 at 12:45 PM, David Mertz  wrote:
> On Wed, Jul 25, 2018 at 10:29 PM Chris Angelico  wrote:
>> It is *actually impossible* to
>> perfectly represent short-circuiting semantics in Python!
>
>
> It's INCREDIBLY EASY to represent short-circuiting semantics in Python! What
> on earth are you talking about?  That's what the if/elif/else blocks do.

Except for the aforementioned "single lookup, single assignment"
semantics. You can't achieve that with an if/else block.

>> And before you go "well that proves my point, this suggestion is bad",
>> let's
>> apply the same test to a few other pieces of syntax. Rewrite the
>> following statements without using the syntactic feature named in the
>> comment:
>
>
> This is childishly simple:
>
>>
>> # 1) Decorators
>> @deco
>> def func():
>> ...
>
>
> def func():
>...
> func = deco(func)

Okay. Try this then:

def deco(f):
print(globals()[f.__name__])
return f
func = "funky"
@deco
def func(): pass

Childishly simple? Or does it have its own subtleties? You might think
this is trivial and pointless, but consider the case of a writable
property:

class X:
@property
def spam(self): return 42
@spam.setter
def spam(self, val): print("Setting spam to", val)

This version won't work:

class X:
def spam(self): return 42
spam = property(spam)
def spam(self, val): print("Setting spam to", val)
spam = spam.setter(spam)

See how easy it is to create an imperfect representation?

>> # 3) and the big one: generator expressions
>> # yes, I'm deliberately using x multiple ways here
>> def f(x): return x*x
>> x = range(10)
>> x = (f(x) for x in x if x % 2)
>
>
> I'm not going to bother with that.  I'd fire anyone who wrote it, after code
> review.  Minus the abuse of names, it's just:
>
> def gen(xs):
>
> for x in xs:
>
> if x % 2:
>
> yield f(x)
>
> x = gen(xs)

Modulo a TON of subtleties about exactly what gets evaluated when.
Again, you've made an imperfect equivalence. So if you're going to
complain about people making ?. equivalences that aren't perfect, make
sure you're just as pedantic about existing syntax. You scored one out
of three, and only by punting to the existing PEP.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018 at 10:41 PM Chris Angelico  wrote:

> A bit problematic. But after (a) figuring out that your module is
> named "coalesce" even though I installed "coalescing" AND (b) going
> and separately installing wrapt, and finally (c) doing the import that
> you didn't mention, we still have this fundamental problem:
>

Yeah, yeah.  I know it's alpha software I wrote two nights ago, and
slightly patched 5 minutes before that post.  You fixed those concerns;
I'll happily take PRs on fixing them better.


> >>> from coalesce import NullCoalesce
> >>> from types import SimpleNamespace
> >>> spam, spam.eggs, spam.eggs.bacon = SimpleNamespace(),
> SimpleNamespace(), 42
> >>> NullCoalesce(spam).eggs.bacon
> 
>
> That isn't 42. That's a thing that, forever afterwards, will be a
> proxy.


Yeah.  That's a thing it does.  It's less of an issue than you think since,
e.g.:

>>> from coalesce import NullCoalesce
>>> from types import SimpleNamespace
>>> spam, spam.eggs, spam.eggs.bacon = SimpleNamespace(),
SimpleNamespace(), 42
>>> NullCoalesce(spam).eggs.bacon + 1
43
>>> NullCoalesce(spam).eggs.bacon * 1
42


Most things you actually do with the proxy wind up getting the value back
once it is used.  However, this seems to be a bug that I inherit from
wrapt.ObjectProxy:

>>> NullCoalesce(spam).eggs.bacon + 0
ValueError: wrapper has not been initialized


If you do an operation that combines the proxy value with "Falsey" values,
it doesn't do the implicit unboxing.  Same with e.g. `proxyval + ""` for
strings, unfortunately.  I'm not sure how to fix that.

>>> spam.nil = None
> >>> print(NullCoalesce(spam).nil.nil)
> None
> >>> print(NullCoalesce(spam).nil.nil.nil)
> Traceback (most recent call last):
>   File "", line 1, in 
> AttributeError: 'NoneType' object has no attribute 'nil'
>

Why is this wrong? This is EXACTLY the same behavior as the `?.` operator
would have in the last case.  Do you not recognize the behavior you are
advocating in PEP 505?

I recognize that the proxy value not always "auto-unboxing" is a limitation
that I don't like.

-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 10:12 PM David Mertz  wrote:

> On Wed, Jul 25, 2018 at 9:47 PM Nicholas Chammas <
> nicholas.cham...@gmail.com> wrote:
>
>> > That is disingenuous, I think.  Can this raise an AttributeError?
>>> > spam?.eggs?.bacon
>>> > Of course it can! And this is exactly the pattern used in many
>>> examples in
>>> > the PEP and the discussion. So the PEP would create a situation where
>>> code
>>> > will raise AttributeError in a slightly—and subtly—different set of
>>> > circumstances than plain attribute access will.
>>>
>>
>
>> food = spam?.eggs?.bacon
>> Can be rewritten as:
>> food = spam
>> if spam is not None and spam.eggs is not None:
>> food = spam.eggs.bacon
>> They both behave identically, no? Maybe I missed the point David was
>> trying to make.
>>
>
> No, you illustrate it perfectly! I had to stare at your translation for a
> while to decide if it was really identical to the proposed
> `spam?.eggs?.bacon`.  The fact I have to think so hard makes the syntax
> feel non-obvious.
>
> Plus, there's the fact that your best effort at translating the proposed
> syntax is WRONG.  Even a strong proponent cannot explain the behavior on a
> first try.  And indeed, it behaves subtly different from plain attribute
> access in where it raises AttributeError.
>
> >>> spam = SimpleNamespace()
> >>> spam.eggs = None
> >>> spam.eggs.bacon
> AttributeError: 'NoneType' object has no attribute 'bacon'
>
> >>> # spam?.eggs?.bacon
> >>> # Should be: None
>
> >>> "Translation" does something different
> >>> food = spam
> >>> if spam is not None and spam.eggs is not None:
> ... food = spam.eggs.bacon
> >>> food
> namespace(eggs=None)
>

Indeed. Thanks for the counter-example. I think the correct translation is
as follows:

food = spam?.eggs?.bacon

Becomes:

food = None
if spam is not None and spam.eggs is not None:
food = spam.eggs.bacon

Did I get it right now? :)

What misled me was this example from the PEP

showing
how atoms are evaluated. The breakdown begins with `_v = a`, so I copied
that pattern incorrectly when trying to explain how an example assignment
would work, instead of translating directly from what I understood the PEP
505 variant should do.

So, shame on me. I think this particular mistake reflects more on me than
on PEP 505, but I see how this kind of mistake reflects badly on the folks
advocating for the PEP (or at least, playing devil's advocate).
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018 at 10:29 PM Chris Angelico  wrote:

> food = spam?.eggs?.bacon
>
> can be rewritten as
>
> _tmp = spam
> if _tmp is not None:
> _tmp = _tmp.eggs
> if _tmp is not None:
> _tmp = _tmp.bacon
> food = _tmp
>

Yes, that looks right.  Well, you need a `del _tmp` at the end; but it's
almost right.  My point was that both you and Nicholas Chammas failed to
recognize that the other translation was wrong... I recognize it does
something "kinda similar."  But the semantics of the operators are just
plain hard to grok, even by their strongest advocates.

I can write lots of things that are "mostly correct" already in Python.
Most easily, I can write:

try:
   food = spam.eggs.bacon
except:
  food = None


That does what is actually needed about 95% of the time.  It's also clear
and easy to understand.

It is *actually impossible* to
> perfectly represent short-circuiting semantics in Python!


It's INCREDIBLY EASY to represent short-circuiting semantics in Python!
What on earth are you talking about?  That's what the if/elif/else blocks
do.

And before you go "well that proves my point, this suggestion is bad", let's
> apply the same test to a few other pieces of syntax. Rewrite the
> following statements without using the syntactic feature named in the
> comment:
>

This is childishly simple:


> # 1) Decorators
> @deco
> def func():
> ...
>

def func():
   ...
func = deco(func)


OK, this one is harder.  The "mostly correct" version is easy.  But the
actual full version is nuanced (see
https://www.python.org/dev/peps/pep-0380/ for details).

# 2) "yield from"
> def chain(*iters):
> for iter in iters:
> yield from iter
>

# The simple approximation:
for iter in iters:

for _ in iter:

yield iter



> # 3) and the big one: generator expressions
> # yes, I'm deliberately using x multiple ways here
> def f(x): return x*x
> x = range(10)
> x = (f(x) for x in x if x % 2)
>

I'm not going to bother with that.  I'd fire anyone who wrote it, after
code review.  Minus the abuse of names, it's just:

def gen(xs):

for x in xs:

if x % 2:

yield f(x)

x = gen(xs)



-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Chris Angelico
On Thu, Jul 26, 2018 at 12:30 PM, David Mertz  wrote:
> Btw. Here's a way of spelling the proposed syntax that gets the semantics
> right:
>
 # pip install coalescing
 NullCoalesce(spam).eggs.bacon

Let's try it.

rosuav@sikorsky:~$ sudo python3 -m pip install coalescing
Collecting coalescing
  Downloading 
https://files.pythonhosted.org/packages/f3/f4/120f04cc59f9fa8c55c711b67f1c9c34d8a59c34cd69249e6ff61b098987/coalescing-0.1.1.tar.gz
Installing collected packages: coalescing
  Running setup.py install for coalescing ... done
Successfully installed coalescing-0.1.1

rosuav@sikorsky:~$ python3
Python 3.8.0a0 (heads/literal_eval-exception:ddcb2eb331, Feb 21 2018, 04:32:23)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from coalescing import NullCoalesce
Traceback (most recent call last):
  File "", line 1, in 
ModuleNotFoundError: No module named 'coalescing'
>>> from coalesce import NullCoalesce
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python3.8/site-packages/coalesce.py", line 56,
in 
import wrapt
ModuleNotFoundError: No module named 'wrapt'

A bit problematic. But after (a) figuring out that your module is
named "coalesce" even though I installed "coalescing" AND (b) going
and separately installing wrapt, and finally (c) doing the import that
you didn't mention, we still have this fundamental problem:

rosuav@sikorsky:~$ python3
Python 3.8.0a0 (heads/literal_eval-exception:ddcb2eb331, Feb 21 2018, 04:32:23)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from coalesce import NullCoalesce
>>> from types import SimpleNamespace
>>> spam, spam.eggs, spam.eggs.bacon = SimpleNamespace(), SimpleNamespace(), 42
>>> NullCoalesce(spam).eggs.bacon


That isn't 42. That's a thing that, forever afterwards, will be a
proxy. And look at this:

>>> spam.nil = None
>>> print(NullCoalesce(spam).nil)

>>> print(NullCoalesce(spam).nil.nil)
None
>>> print(NullCoalesce(spam).nil.nil.nil)
Traceback (most recent call last):
  File "", line 1, in 
AttributeError: 'NoneType' object has no attribute 'nil'
>>>

Whoops.

So, no, this is most definitely NOT equivalent to the proposed semantics.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
So now at least TWO proponents of 505 cannot successfully translate a very
simple example taken almost directly from the PEP!

Is that REALLY a good argument for it being helpful, and not being a bug
magnet?!

On Wed, Jul 25, 2018 at 9:57 PM Chris Angelico  wrote:

> On Thu, Jul 26, 2018 at 11:45 AM, Nicholas Chammas
>  wrote:
> > On Wed, Jul 25, 2018 at 9:20 PM Chris Angelico  wrote:
> >>
> >> On Thu, Jul 26, 2018 at 11:02 AM, David Mertz  wrote:
> >> > That is disingenuous, I think.  Can this raise an AttributeError?
> >> >
> >> > spam?.eggs?.bacon
> >> >
> >> > Of course it can! And this is exactly the pattern used in many
> examples
> >> > in
> >> > the PEP and the discussion. So the PEP would create a situation where
> >> > code
> >> > will raise AttributeError in a slightly—and subtly—different set of
> >> > circumstances than plain attribute access will.
> >>
> >> I don't understand. If it were to raise AttributeError, it would be
> >> because spam (or spam.eggs) isn't None, but doesn't have an attribute
> >> eggs (or bacon). Exactly the same as regular attribute access. How is
> >> it slightly different? Have I missed something?
> >
> >
> > That was my reaction, too.
> >
> > food = spam?.eggs?.bacon
> >
> > Can be rewritten as:
> >
> > food = spam
> > if spam is not None and spam.eggs is not None:
> > food = spam.eggs.bacon
> >
> > They both behave identically, no? Maybe I missed the point David was
> trying
> > to make.
>
> Aside from questions of repeated evaluation/assignment, yes. The broad
> semantics should be the same.
>
> (If you want to get technical, "spam" gets evaluated exactly once,
> "spam.eggs" a maximum of once, and "food" gets assigned exactly once.
> Your equivalent may evaluate and assign multiple times.)
>
> ChrisA
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
On Wed, Jul 25, 2018 at 9:47 PM Nicholas Chammas 
wrote:

> > That is disingenuous, I think.  Can this raise an AttributeError?
>> > spam?.eggs?.bacon
>> > Of course it can! And this is exactly the pattern used in many examples
>> in
>> > the PEP and the discussion. So the PEP would create a situation where
>> code
>> > will raise AttributeError in a slightly—and subtly—different set of
>> > circumstances than plain attribute access will.
>>
>

> food = spam?.eggs?.bacon
> Can be rewritten as:
> food = spam
> if spam is not None and spam.eggs is not None:
> food = spam.eggs.bacon
> They both behave identically, no? Maybe I missed the point David was
> trying to make.
>

No, you illustrate it perfectly! I had to stare at your translation for a
while to decide if it was really identical to the proposed
`spam?.eggs?.bacon`.  The fact I have to think so hard makes the syntax
feel non-obvious.

Plus, there's the fact that your best effort at translating the proposed
syntax is WRONG.  Even a strong proponent cannot explain the behavior on a
first try.  And indeed, it behaves subtly different from plain attribute
access in where it raises AttributeError.

>>> spam = SimpleNamespace()
>>> spam.eggs = None
>>> spam.eggs.bacon
AttributeError: 'NoneType' object has no attribute 'bacon'

>>> # spam?.eggs?.bacon
>>> # Should be: None

>>> "Translation" does something different
>>> food = spam
>>> if spam is not None and spam.eggs is not None:
... food = spam.eggs.bacon
>>> food
namespace(eggs=None)


-- 
Keeping medicines from the bloodstreams of the sick; food
from the bellies of the hungry; books from the hands of the
uneducated; technology from the underdeveloped; and putting
advocates of freedom in prisons.  Intellectual property is
to the 21st century what the slave trade was to the 16th.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 9:20 PM Chris Angelico  wrote:

> On Thu, Jul 26, 2018 at 11:02 AM, David Mertz  wrote:
> > That is disingenuous, I think.  Can this raise an AttributeError?
> >
> > spam?.eggs?.bacon
> >
> > Of course it can! And this is exactly the pattern used in many examples
> in
> > the PEP and the discussion. So the PEP would create a situation where
> code
> > will raise AttributeError in a slightly—and subtly—different set of
> > circumstances than plain attribute access will.
>
> I don't understand. If it were to raise AttributeError, it would be
> because spam (or spam.eggs) isn't None, but doesn't have an attribute
> eggs (or bacon). Exactly the same as regular attribute access. How is
> it slightly different? Have I missed something?
>

That was my reaction, too.

food = spam?.eggs?.bacon

Can be rewritten as:

food = spam
if spam is not None and spam.eggs is not None:
food = spam.eggs.bacon

They both behave identically, no? Maybe I missed the point David was trying
to make.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread James Lu
What if we used ? after the statement beginning?

name ?= person.name
custom_query ?= entity.get_query(context)
# Becomes None if entity is None. Raise an exception if entity is not None and 
get_query is None or undefined.
custom_query ??= entity.get_query(context)
# If entity, entity.get_query, entity.get_query(context) evaluate to null, the 
operation short-circuits and custom_query becomes None
await? foo
with? bar as baz:
# this only runs if bar is not None
pass


?= only short circuits into None when the first evaluation is None (the weak 
operator)
??= short circuits into None whenever any evaluation is None or raises an 
AttributeError. (the strong operator)

I’m imagining the strong operator would be useful especially for duck typing. 
No more hasattr checks, no more isinstance checks. 

I would like to see some real world use cases for none aware operators that 
couldn’t be covered by these none aware assignment operators.

Previous code:
# original code
a ?= b.c
# another, second, programmer comes along and changes it to
a ?= b.c.d

The interpreter would raise an exception, if “d” was None or not defined on 
“c”. If this is intended behavior, this forces the second programmer to 
explicitly mark that all attribute access is coalescing with the strong 
operator, instead of the interpreter swallowing the exception now and emitting 
an exception later. The previous code assumes “b” is None, which in reality may 
represent the state of a network socket or a file transfer. The program may 
display that the operation was complete, leading to a bug in the output. 

I believe this is more readable as well.
> On Jul 25, 2018, at 7:32 PM, python-ideas-requ...@python.org wrote:
> 
> PEP 505: None-aware operators
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Steven D'Aprano
On Tue, Jul 24, 2018 at 08:07:36AM -0400, Richard Damon wrote:

> The fact that you changed NullCoalesce into Foo to show lack of 
> explicitness seems a straw-man.

I understood Rhodri as making the point that if you don't know what 
NullCoalesce means or does, it might as well be called Foo. There's no 
hint in the syntax that something magical is happening:


MyClass(obj).spam.eggs  # ordinary attribute lookup

YourClass(obj).spam.eggs  # still ordinary attribute lookup

Mxyzptlk(obj).spam.eggs  # looks like ordinary attribute lookup

NullCoalesce(obj).spam.eggs  # IT'S A TRAP!



> Words are FULL of meaning, while symbols are less so.

It isn't a competition to squeeze as much meaning as possible into a 
single word or symbol. Precision is more important than fullness.

A case in point: the word "add" has six meanings listed by WordNet, and 
the Mobi Thesaurus gives 102 synonyms for it. A function or method called "add" 
could do anything:

- add users to a database;
- add pages to a chapter;
- add elements to a set;
- add items to a queue;

etc. In contrast, the + symbol in Python has two standard meanings:

- numeric addition;
- sequence concatenation;

and while it is true that with operator overloading a class could make 
the + operator do anything, that is usually taken as an argument to 
avoid operator overloading, or at least use it cautiously.

Surely you don't think that the + operator is a mistake because the word 
"add" is more full of meaning than the symbol? If not, what point were 
you trying to make?


> The biggest issue I see with the use of ? here is 
> that ? does have some meaning, it says we are going to be (or have) 
> asked a question, it doesn’t tell us what the question is.

Sometimes you just have to learn the meanings of words or symbols.

What does NullCoalesce mean? Until this PEP was proposed, I had no idea 
this was even a thing, and in truth I actually had to look up "coalesce" 
in a dictionary to be sure I understood it correctly, because the 
context doesn't seem quite right.

(It still doesn't -- it might be the standard comp sci term for this 
feature, but I don't think it quite matches the ordinary usage of the 
word.)

Ask a dozen programming beginners what "NullCoalesce" does, and I expect 
every one of them will say "No idea".

Strangely enough, nobody complains about having to learn what "import" 
does, or slicing syntax x[:], or string backslash escapes "\n", or 
"property". Because we're used to them, we just accept that you have to 
learn the meaning of things the first time you see them. We aren't born 
knowing what "class" does, or the difference between x[a] and x(a).

Every single one of us, without exception, had to learn what . means at 
some point or another.

And yet, its wailing and gnashing of teeth and panic in the streets over 
the idea that people might have to learn what ?. means in the same way 
they learned what **kwargs or mylist[1:] or obj.attr means.

"It's a question, but what is the question? How will I ever
find out? If only there was a website where I might look up
Python operators and learn what they do!!!"


> ?. has some indication that we are doing an attribute access that is 
> in some way conditional, but a?.b could mean that we are conditional 
> on a not being null, or it could be asking to suppress any and all 
> error in getting b, even if a is an int and thus doesn’t have a b. The 
> words carry a lot more meaning.

Yeah, because words are always obvious.

import ast  # Who can remember all these damned TLAs?
import bdm  # Births Deaths Marriages?
import csv  # Court Services Victoria?
import mailcap  # what the postman wears on his head?
import pickle  # something to do with condiments?
import turtle  # somebody is taking the micky
import curses  # good thing I'm not superstitious


"But Steve, you don't understand. Having to learn the meaning
 of words you haven't learned before is right and proper and
 unavoidable. But all new punctuation symbols must be intuitively
 obvious to newborn babies, or else they are the Devil's Mark,
 or Perl, not sure which is worse."

(Its called sarcasm, not "strawman". Just sayin'.)


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Steven D'Aprano
On Wed, Jul 25, 2018 at 12:12:40PM -0400, Nicholas Chammas wrote:

> When something is "explicit", as I understand it, that means it does what
> it says on the cover. There is no unstated behavior. The plain meaning of
> `v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`), and
> it is just as explicit.

Right. We don't insist on writing


mydict.look_up_key_in_self_and_raise_keyerror_if_the_key_is_not_found(key="spam")

instead of 

mydict["spam"]

out of a mistaken idea that explicitness requires verbosity and that 
punctuation is always implicit.

Symbols (whether made of text or punctuation) have meaning, and that 
meaning has to be taken into account. You *can't* spell everything out 
in full. We always have to take the meaning of something as given, and 
that can be punctuation just as easily as words.


> This reminds me of something I read about once called Stroustrup's Rule
>  [1]:
> 
> > For new features, people insist on LOUD explicit syntax.
> > For established features, people want terse notation.
> 
> I think the "explicit vs. implicit" part of this discussion is probably
> better expressed as a discussion about "loud vs. terse" syntax. None of the
> operators in PEP 505 have implicit behavior, to the best of my
> understanding. It's just that the operators are new and have terse
> spellings.

That is a great observation! Thanks.


-- 
Steve
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Greg Ewing

David Mertz wrote:
Sorry. From my tablet. "Bug magnets" (it really, really wants to 
autocorrect that)


At least it didn't correct it to "butt magnets". :-)

--
Greg
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Abe Dillon
*sorry, cat hit "send"...

Just reading those examples made me want to cry and go hide in a dark dark
cave and never come out. I'm sure using actual variable names would help a
bit, but not much.

As for the non-english nature of:
value = person.name

I highly disagree with the argument that since that is a step removed from
natural language readability that:
value = person?.name

Should be considered fair game. Nor do I buy the "other languages do it"
argument. Some of the syntax of Python is based on familiar patterns in
other languages (like '.' access) some of it is based on common math (e.g.
"=", "+", etc.) which is also taught in grade school. Some of the patterns
borrowed from other languages were a mistake and considered cruft. Some of
that cruft was scraped off in the 2to3 migration. Maybe "." should have
been apostrophe "s" all along. Maybe lambda should have been
'make_function'. That's not what we're here to discuss. A lot of languages
have a ternary operator (x ? y : z). Python wisely used words instead of
symbols and now many students don't even have to crack a book to decipher
Python's ternary operator. Adding crap to a language is easy. Removing it
is damn near impossible. You have to have extremely good reasons to add new
syntax and I don't have to defend any of Python's warts to justify
rejecting yours.

On Wed, Jul 25, 2018 at 6:15 PM, Abe Dillon  wrote:

> The two statements you wrote are not the same. The first statement will
>> error out if person is None.
>
> That's my bad. I was copying off of an erroneous example. Thanks for
> correcting me.
>
> The proposed None-aware operators are specifically designed to handle
>> variables that may be None.
>>
> Yes, I think the syntax that you've landed on is confusing enough that it
> opens the door to more errors than it closes. Just reading "(a?.b ?? c).d?.e"
> and "await a?.b(c).d?[e]"
>
>
> On Wed, Jul 25, 2018 at 6:06 PM, Nicholas Chammas <
> nicholas.cham...@gmail.com> wrote:
>
>> On Wed, Jul 25, 2018 at 6:11 PM Abe Dillon  wrote:
>>
>>> The problem here is not whether it's explicit. It's about Readability
>>> and conciseness. Using symbols in place of words almost always harms
>>> readability in favor of conciseness.
>>>
>>> value = person.name if person.name else person
>>>
>>> almost reads like english (aside from being a weird and totally uncommon
>>> use case)
>>>
>>> value = person?.name
>>>
>>> Is a huge step towards the concise illegible soup of symbols that Perl
>>> is famous for. It's a huge No from me.
>>>
>>
>> The two statements you wrote are not the same. The first statement will
>> error out if person is None. The proposed None-aware operators are
>> specifically designed to handle variables that may be None.
>>
>> The first statement should instead read:
>>
>> value = person.name if person is not None else person
>>
>> That's what `value = person?.name` means.
>>
>> As others have pointed out, I suppose the fact that multiple people have
>> messed up the meaning of the proposed operators is concerning. Perhaps the
>> PEP could be improved by adding some dead simple examples of each operator
>> and an equivalent statement that doesn't use the operator, to better
>> illustrate their meaning. But I gather that will do little in the way of
>> addressing some of the stronger objections raised here.
>>
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Abe Dillon
>
> The two statements you wrote are not the same. The first statement will
> error out if person is None.

That's my bad. I was copying off of an erroneous example. Thanks for
correcting me.

The proposed None-aware operators are specifically designed to handle
> variables that may be None.
>
Yes, I think the syntax that you've landed on is confusing enough that it
opens the door to more errors than it closes. Just reading "(a?.b ?? c).d?.e"
and "await a?.b(c).d?[e]"


On Wed, Jul 25, 2018 at 6:06 PM, Nicholas Chammas <
nicholas.cham...@gmail.com> wrote:

> On Wed, Jul 25, 2018 at 6:11 PM Abe Dillon  wrote:
>
>> The problem here is not whether it's explicit. It's about Readability and
>> conciseness. Using symbols in place of words almost always harms
>> readability in favor of conciseness.
>>
>> value = person.name if person.name else person
>>
>> almost reads like english (aside from being a weird and totally uncommon
>> use case)
>>
>> value = person?.name
>>
>> Is a huge step towards the concise illegible soup of symbols that Perl is
>> famous for. It's a huge No from me.
>>
>
> The two statements you wrote are not the same. The first statement will
> error out if person is None. The proposed None-aware operators are
> specifically designed to handle variables that may be None.
>
> The first statement should instead read:
>
> value = person.name if person is not None else person
>
> That's what `value = person?.name` means.
>
> As others have pointed out, I suppose the fact that multiple people have
> messed up the meaning of the proposed operators is concerning. Perhaps the
> PEP could be improved by adding some dead simple examples of each operator
> and an equivalent statement that doesn't use the operator, to better
> illustrate their meaning. But I gather that will do little in the way of
> addressing some of the stronger objections raised here.
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 6:11 PM Abe Dillon  wrote:

> The problem here is not whether it's explicit. It's about Readability and
> conciseness. Using symbols in place of words almost always harms
> readability in favor of conciseness.
>
> value = person.name if person.name else person
>
> almost reads like english (aside from being a weird and totally uncommon
> use case)
>
> value = person?.name
>
> Is a huge step towards the concise illegible soup of symbols that Perl is
> famous for. It's a huge No from me.
>

The two statements you wrote are not the same. The first statement will
error out if person is None. The proposed None-aware operators are
specifically designed to handle variables that may be None.

The first statement should instead read:

value = person.name if person is not None else person

That's what `value = person?.name` means.

As others have pointed out, I suppose the fact that multiple people have
messed up the meaning of the proposed operators is concerning. Perhaps the
PEP could be improved by adding some dead simple examples of each operator
and an equivalent statement that doesn't use the operator, to better
illustrate their meaning. But I gather that will do little in the way of
addressing some of the stronger objections raised here.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
Sorry. From my tablet. "Bug magnets" (it really, really wants to
autocorrect that)

And yes, the problem is that the equivalent is actually:

v = a
if v is not None: v=a.b

The semantics are simply not the ones that are intuitive to most people
reading 'v = a?.b'

On Wed, Jul 25, 2018, 7:01 PM Abe Dillon  wrote:

> The fact that a while bunch have people have commented on this subthread
>> while not recognizing that the semantics of the '?.' and the if blocks are
>> entirely different suggests the operators are but magnets.
>>
>
> Can you explain? What do you mean by "the operators are but magnets"?
>
> The "None coalescing" operator seems so similar to the short circuit
> behavior of "or" that it has pretty much no merit. It's compared to ternary
> statements in the last section of the PEP (which is suspiciously lacking
> the "or" pattern).
>
> I would agree that Python could use some more support for EAFP
>  style coding. An express-ionized
> version of try/catch might help there, but I'm pretty sure the search for
> an elegant solution to that has been relatively fruitless. The attribute
> access and indexing are just unreadable in my view. Maybe if the question
> mark came at the end of the expression it would be more readable and just
> mean, "if the preceding expression raises an attribute exception on a
> none-type object, ignore it and evaluate to None otherwise return the
> result of the evaluation" Then just use parentheses to capture the scope:
>
> initial = (person.name[0])? # handles if person is None or person.name is
> None
>
> but that still seems like a good way to end up with very ugly code.
> Haskel's Maybe seems like a much better and more readable approach.
>
>
>
> On Wed, Jul 25, 2018 at 5:36 PM, David Mertz  wrote:
>
>> The fact that a while bunch have people have commented on this subthread
>> while not recognizing that the semantics of the '?.' and the if blocks are
>> entirely different suggests the operators are but magnets.
>>
>> On Wed, Jul 25, 2018, 5:17 PM Nicholas Chammas <
>> nicholas.cham...@gmail.com> wrote:
>>
>>> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
>>> wrote:
>>>
 This:

 v = a?.b

 ...*implicitly* checks if value is not None [and continues execution].
 This:

 v = a
 if a.b is not None:
 v = a.b

 ...*explicitly* checks if value is not None and continues execution.

>>>
>>> I think both of those are equally explicit. It's just that one notation
>>> is more concise than the other. Explicitness and conciseness are related
>>> but different things.
>>>
>>> When something is "explicit", as I understand it, that means it does
>>> what it says on the cover. There is no unstated behavior. The plain meaning
>>> of `v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`),
>>> and it is just as explicit.
>>>
>>> This reminds me of something I read about once called Stroustrup's Rule
>>> 
>>>  [1]:
>>>
>>> > For new features, people insist on LOUD explicit syntax.
>>> > For established features, people want terse notation.
>>>
>>> I think the "explicit vs. implicit" part of this discussion is probably
>>> better expressed as a discussion about "loud vs. terse" syntax. None of the
>>> operators in PEP 505 have implicit behavior, to the best of my
>>> understanding. It's just that the operators are new and have terse
>>> spellings.
>>>
>>> As a point of comparison, I think a good example of implicit behavior is
>>> type coercion. When you ask Python to add an int to a float
>>>
>>> a = 3 + 4.5
>>>
>>> all that you've explicitly asked for is the addition. However, Python
>>> implicitly converts the 3 from an int to a float as part of the operation.
>>> The type conversion isn't anywhere "on the cover" of the + operator. It's
>>> implicit behavior.
>>>
>>> [1] Bjarne Stroustrup makes the observation in this talk
>>>  at
>>> 23:00.
>>> ___
>>> Python-ideas mailing list
>>> Python-ideas@python.org
>>> https://mail.python.org/mailman/listinfo/python-ideas
>>> Code of Conduct: http://python.org/psf/codeofconduct/
>>>
>>
>> ___
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Elazar
On Wed, Jul 25, 2018 at 3:11 PM Abe Dillon  wrote:

> The problem here is not whether it's explicit. It's about Readability and
> conciseness. Using symbols in place of words almost always harms
> readability in favor of conciseness.
>
> value = person.name if person.name else person
>
> almost reads like english (aside from being a weird and totally uncommon
> use case)
>
> value = person?.name
>
> Is a huge step towards the concise illegible soup of symbols that Perl is
> famous for. It's a huge No from me.
>
>
> Similarly,

Value is name of person

almost reads like english.

value = person.name

Starts to look like pearl (but does not avoid repetition; only hurts
english-like-readability) - or perhaps some other programming languages
that use similar operators, such as C#, Swift, Dart, F#, Kotlin and others.
As far as I know it is not generally considered a bad addition in any of
these languages, all of which put emphasis on readability.

Elazar
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Abe Dillon
>
> The fact that a while bunch have people have commented on this subthread
> while not recognizing that the semantics of the '?.' and the if blocks are
> entirely different suggests the operators are but magnets.
>

Can you explain? What do you mean by "the operators are but magnets"?

The "None coalescing" operator seems so similar to the short circuit
behavior of "or" that it has pretty much no merit. It's compared to ternary
statements in the last section of the PEP (which is suspiciously lacking
the "or" pattern).

I would agree that Python could use some more support for EAFP
 style coding. An express-ionized
version of try/catch might help there, but I'm pretty sure the search for
an elegant solution to that has been relatively fruitless. The attribute
access and indexing are just unreadable in my view. Maybe if the question
mark came at the end of the expression it would be more readable and just
mean, "if the preceding expression raises an attribute exception on a
none-type object, ignore it and evaluate to None otherwise return the
result of the evaluation" Then just use parentheses to capture the scope:

initial = (person.name[0])? # handles if person is None or person.name is
None

but that still seems like a good way to end up with very ugly code.
Haskel's Maybe seems like a much better and more readable approach.



On Wed, Jul 25, 2018 at 5:36 PM, David Mertz  wrote:

> The fact that a while bunch have people have commented on this subthread
> while not recognizing that the semantics of the '?.' and the if blocks are
> entirely different suggests the operators are but magnets.
>
> On Wed, Jul 25, 2018, 5:17 PM Nicholas Chammas 
> wrote:
>
>> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
>> wrote:
>>
>>> This:
>>>
>>> v = a?.b
>>>
>>> ...*implicitly* checks if value is not None [and continues execution].
>>> This:
>>>
>>> v = a
>>> if a.b is not None:
>>> v = a.b
>>>
>>> ...*explicitly* checks if value is not None and continues execution.
>>>
>>
>> I think both of those are equally explicit. It's just that one notation
>> is more concise than the other. Explicitness and conciseness are related
>> but different things.
>>
>> When something is "explicit", as I understand it, that means it does what
>> it says on the cover. There is no unstated behavior. The plain meaning of
>> `v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`), and
>> it is just as explicit.
>>
>> This reminds me of something I read about once called Stroustrup's Rule
>> 
>>  [1]:
>>
>> > For new features, people insist on LOUD explicit syntax.
>> > For established features, people want terse notation.
>>
>> I think the "explicit vs. implicit" part of this discussion is probably
>> better expressed as a discussion about "loud vs. terse" syntax. None of the
>> operators in PEP 505 have implicit behavior, to the best of my
>> understanding. It's just that the operators are new and have terse
>> spellings.
>>
>> As a point of comparison, I think a good example of implicit behavior is
>> type coercion. When you ask Python to add an int to a float
>>
>> a = 3 + 4.5
>>
>> all that you've explicitly asked for is the addition. However, Python
>> implicitly converts the 3 from an int to a float as part of the operation.
>> The type conversion isn't anywhere "on the cover" of the + operator. It's
>> implicit behavior.
>>
>> [1] Bjarne Stroustrup makes the observation in this talk
>>  at
>> 23:00.
>> ___
>> Python-ideas mailing list
>> Python-ideas@python.org
>> https://mail.python.org/mailman/listinfo/python-ideas
>> Code of Conduct: http://python.org/psf/codeofconduct/
>>
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 6:36 PM David Mertz  wrote:

> The fact that a while bunch have people have commented on this subthread
> while not recognizing that the semantics of the '?.' and the if blocks are
> entirely different suggests the operators are but magnets.
>
> On Wed, Jul 25, 2018, 5:17 PM Nicholas Chammas 
> wrote:
>
>> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
>> wrote:
>>
>>> This:
>>>
>>> v = a?.b
>>>
>>> ...*implicitly* checks if value is not None [and continues execution].
>>> This:
>>>
>>> v = a
>>> if a.b is not None:
>>> v = a.b
>>>
>>> ...*explicitly* checks if value is not None and continues execution.
>>>
>>
Sorry, lazy reading on my part. I skimmed the expanded form assuming it was
correct. I think it should instead read `if a is not None: ...`.

Is that what you're getting at?
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread David Mertz
The fact that a while bunch have people have commented on this subthread
while not recognizing that the semantics of the '?.' and the if blocks are
entirely different suggests the operators are but magnets.

On Wed, Jul 25, 2018, 5:17 PM Nicholas Chammas 
wrote:

> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
> wrote:
>
>> This:
>>
>> v = a?.b
>>
>> ...*implicitly* checks if value is not None [and continues execution].
>> This:
>>
>> v = a
>> if a.b is not None:
>> v = a.b
>>
>> ...*explicitly* checks if value is not None and continues execution.
>>
>
> I think both of those are equally explicit. It's just that one notation is
> more concise than the other. Explicitness and conciseness are related but
> different things.
>
> When something is "explicit", as I understand it, that means it does what
> it says on the cover. There is no unstated behavior. The plain meaning of
> `v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`), and
> it is just as explicit.
>
> This reminds me of something I read about once called Stroustrup's Rule
> 
>  [1]:
>
> > For new features, people insist on LOUD explicit syntax.
> > For established features, people want terse notation.
>
> I think the "explicit vs. implicit" part of this discussion is probably
> better expressed as a discussion about "loud vs. terse" syntax. None of the
> operators in PEP 505 have implicit behavior, to the best of my
> understanding. It's just that the operators are new and have terse
> spellings.
>
> As a point of comparison, I think a good example of implicit behavior is
> type coercion. When you ask Python to add an int to a float
>
> a = 3 + 4.5
>
> all that you've explicitly asked for is the addition. However, Python
> implicitly converts the 3 from an int to a float as part of the operation.
> The type conversion isn't anywhere "on the cover" of the + operator. It's
> implicit behavior.
>
> [1] Bjarne Stroustrup makes the observation in this talk
>  at
> 23:00.
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-ideas] As-do statements/anonymous blocks in python

2018-07-25 Thread James Lu
I'm open to any changes or criticism.

```
import atexit
as atexit.register:
# ...do various cleanup tasks...
print('Goodbye')

# is approximately equivalent to =>
import atexit
def _():
# ...do various cleanup tasks...
print('Goodbye')
atexit.register(_)

# flask example
@app.route("/")
def hello():
return "Hello World!"
# is approximately equivalent to =>
as app.route('/'):
return "Hello World!"

@app.route('/user/')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username

as app.route('/user/') do username:
return "Hello World!"

def print_sorted(iterable, block):
sorted(iterable, )

l = [1, 2, 3, 4, 'spam']

as l.sort(key=%) do obj:
return str(obj)

# multiple arguments
as spam do a, b:
...
```
## `%`  function call syntax
Calling a function with a single percent in place of an argument creates a
new function.

```
lumberjack(15, %)
# is equivalent to the expression
lambda x: lumberjack(15, %)
```
Using `*` instead of `%` could also be possible.

```
import threading, time
def interval(seconds, block):
def target():
while True:
time.sleep(seconds)
if block():  # stop looping if block returns True
break
threading.Thread(target=target).start()

as interval(5, %):
   print("chirp")
# => chirp every 5 seconds on a seperate thread
as threading.Timer(5, %):
   print("hi")
# => say "hi" in 5 seconds
```

## `^` currying function definition syntax?
I'm not sure this is necessary or a good idea.
```
def interval(seconds, ^block):
def target():
while True:
time.sleep(seconds)
if block():  # stop looping if block returns True
break
threading.Thread(target=target).start()
# is aprroximately equivalent to
def interval(seconds, block=None):
def inner(block):
def target():
while True:
time.sleep(seconds)
if block():
break
threading.Thread(target=target).start()
if block == None:
def outer(block):
return inner(block)
else:
return inner(block)

as interval(5):
print('chirp')
# equivalent to
interval(5)(lambda: print('chirp'))
```
### Lazy evaluation of chained `%` calls?
This would allow things like:
```
start_on_new_thread = threading.Thread(target=%).start()
def bong():
while True:
time.sleep(6*60)
print('BONG')
start_on_new_thread(bong)
# alternatively
as start_on_new_thread:
while True:
time.sleep(6*60)
print('BONG')
```

## As-do statements in classes
```
class M():
 def __init__(self):
 self.time = 5
 as interval(self.time, %):
 print('chirp')
```

I'm not sure if this should be valid, and I'd like the community's input on
when as-do statements should be bound when as-do.

## Proposed Type Hinting Syntax
```
as app.route('/user/') do (username: str):
return "Hello World!"
```

Alternatives:
```
as app.route('/user/') do username: str%
return "Hello World!"
# like objective-c
as app.route('/user/') do username: str^
return "Hello World!"
# like coffeescript
as app.route('/user/') do username: str ->
return "Hello World!"
```

I’m not totally sure of practical uses, but I’m imagining it would make
passing a function to another function much more convenient. In React, you
pass an argument called `render` to a `FlatList`, and `render` renders an
item of the list. `FlatList` is a scrollable list that handles unloading
off-screen items and loading items that will appear in the scroll box soon.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Abe Dillon
The problem here is not whether it's explicit. It's about Readability and
conciseness. Using symbols in place of words almost always harms
readability in favor of conciseness.

value = person.name if person.name else person

almost reads like english (aside from being a weird and totally uncommon
use case)

value = person?.name

Is a huge step towards the concise illegible soup of symbols that Perl is
famous for. It's a huge No from me.



On Wed, Jul 25, 2018 at 11:12 AM, Nicholas Chammas <
nicholas.cham...@gmail.com> wrote:

> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
> wrote:
>
>> This:
>>
>> v = a?.b
>>
>> ...*implicitly* checks if value is not None [and continues execution].
>> This:
>>
>> v = a
>> if a.b is not None:
>> v = a.b
>>
>> ...*explicitly* checks if value is not None and continues execution.
>>
>
> I think both of those are equally explicit. It's just that one notation is
> more concise than the other. Explicitness and conciseness are related but
> different things.
>
> When something is "explicit", as I understand it, that means it does what
> it says on the cover. There is no unstated behavior. The plain meaning of
> `v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`), and
> it is just as explicit.
>
> This reminds me of something I read about once called Stroustrup's Rule
> 
>  [1]:
>
> > For new features, people insist on LOUD explicit syntax.
> > For established features, people want terse notation.
>
> I think the "explicit vs. implicit" part of this discussion is probably
> better expressed as a discussion about "loud vs. terse" syntax. None of the
> operators in PEP 505 have implicit behavior, to the best of my
> understanding. It's just that the operators are new and have terse
> spellings.
>
> As a point of comparison, I think a good example of implicit behavior is
> type coercion. When you ask Python to add an int to a float
>
> a = 3 + 4.5
>
> all that you've explicitly asked for is the addition. However, Python
> implicitly converts the 3 from an int to a float as part of the operation.
> The type conversion isn't anywhere "on the cover" of the + operator. It's
> implicit behavior.
>
> [1] Bjarne Stroustrup makes the observation in this talk
>  at
> 23:00.
>
> ___
> Python-ideas mailing list
> Python-ideas@python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
>
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Wed, Jul 25, 2018 at 12:12 PM Nicholas Chammas <
nicholas.cham...@gmail.com> wrote:

> On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
> wrote:
>
>> This:
>>
>> v = a?.b
>>
>> ...*implicitly* checks if value is not None [and continues execution].
>> This:
>>
>> v = a
>> if a.b is not None:
>> v = a.b
>>
>> ...*explicitly* checks if value is not None and continues execution.
>>
>
> I think both of those are equally explicit. It's just that one notation is
> more concise than the other. Explicitness and conciseness are related but
> different things.
>
> 
>

It looks like others already discussed this point later in the thread.
Apologies for rehashing the argument.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 505: None-aware operators

2018-07-25 Thread Nicholas Chammas
On Mon, Jul 23, 2018 at 6:05 PM Giampaolo Rodola' 
wrote:

> This:
>
> v = a?.b
>
> ...*implicitly* checks if value is not None [and continues execution].
> This:
>
> v = a
> if a.b is not None:
> v = a.b
>
> ...*explicitly* checks if value is not None and continues execution.
>

I think both of those are equally explicit. It's just that one notation is
more concise than the other. Explicitness and conciseness are related but
different things.

When something is "explicit", as I understand it, that means it does what
it says on the cover. There is no unstated behavior. The plain meaning of
`v = a?.b` is that it expands to the longer form (`v = a; if a.b ...`), and
it is just as explicit.

This reminds me of something I read about once called Stroustrup's Rule
 [1]:

> For new features, people insist on LOUD explicit syntax.
> For established features, people want terse notation.

I think the "explicit vs. implicit" part of this discussion is probably
better expressed as a discussion about "loud vs. terse" syntax. None of the
operators in PEP 505 have implicit behavior, to the best of my
understanding. It's just that the operators are new and have terse
spellings.

As a point of comparison, I think a good example of implicit behavior is
type coercion. When you ask Python to add an int to a float

a = 3 + 4.5

all that you've explicitly asked for is the addition. However, Python
implicitly converts the 3 from an int to a float as part of the operation.
The type conversion isn't anywhere "on the cover" of the + operator. It's
implicit behavior.

[1] Bjarne Stroustrup makes the observation in this talk
 at
23:00.
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Multi-core reference count garbage collection

2018-07-25 Thread Jonathan Fine
Hi All

INTRODUCTION

This is the third and concluding post, where I describe a scheme for
multi-core reference counting garbage collection. The first two posts
are
https://mail.python.org/pipermail/python-ideas/2018-July/052054.html
https://mail.python.org/pipermail/python-ideas/2018-July/052151.html

This subject is quite technical, with pitfalls and a race hazard. If
you don't understand what I've written, or think it wrong, it might be
that I screwed up and got it wrong. I personally find it a hard
subject. Or it might be that you've missed something in one of the two
previous posts. Or we might both be wrong. Or both right!

For the race hazard, see
https://mail.python.org/pipermail/python-ideas/2018-July/052190.html

There have been many valuable contributions to this discussion thread,
which I will acknowledge later, in another post. However, I do repeat
that this scheme is based on other people's work (particularly talks
by Larry Hastings), as well as my own thinking.

And it is actually a known and published idea (which is reassuring).
https://mail.python.org/pipermail/python-ideas/2018-July/052061.html

THE STORY SO FAR

We have 5 worker processes and one garbage collection (GC) process.
Each worker process has an INCR buffer in which it logs an ID, every
time the process increases the refcount of the object with that ID.
And similarly for DECR.

When the worker INCR and DECR buffers are full, they are passed over
to the GC process. The GC process keeps, for each object ID, a running
total of how many references. In this way it consumes the information
in the INCR and DECR buffers.

The problem, as always in garbage collection, is to reclaim objects
that will no longer be used. With reference counting, objects whose
reference count is zero can be reclaimed. This is often done, in
single process systems, immediately after the reference count becomes
zero. (An important aside: For multi-core machines this is an
unhelpful constraint. Relaxing it will allow the worker processes to
run more freely.)

At each point in time, there are for each object ID two reference
counts. The first is the running total, updated as full INCR and DECR
buffers are applied to it. I will call this the RAW TOTAL. The second
is the raw total, adjusted by all the INCR and DECR buffers in the
worker processes. I will call this the REAL TOTAL.

Once the real total is zero, it stays zero. This is an immediate
consequence of the worker threads having no references to the object.
Having no references, they cannot do an INCR or DECR. When the real
total is zero, the object can be reclaimed.

The problem is to refine what we have, so that all objects whose real
count is zero are in good time reclaimed. We want to avoid locking all
the worker threads, for example to compute real counts for all IDs.

BEING TRICKY

Think of the worker threads as an adversary, who are trying to delay
or fool the garbage collector.

Here's one thing that can be done. Have a worker thread
1. Acquire (references to) some objects (say from other worker processes).
2. Delete those object references, without filling either the INCR or
DECR buffer.
3. Spin its wheels endlessly.

This will defeat the GC process, unless the system from time to time
sends the INCR and DECR buffers to the GC process, whether or not they
are full. So we'll add this to the system requirements.

Here's something else, which is part of normal use. We have one worker
thread do a calculation for another. The return value is passed from
one thread to another. It could happen that, for some ID, an INCR in
one thread is followed by a DECR in another. Now suppose that the GC
process gets
* First, the process buffer containing the DECR.
* And then the process buffer that contains the INCR.
(This is a race hazard. The order of operations has been reversed.)

Thus it can happen that the raw total for an ID can go down to zero
and then increase up to one. This can't happen for the true total, of
course. (With more work, the raw counts can go negative!)

DEFEATING TRICKINESS

The problem is for the GC process to discover IDs for which the real
total is zero. And in good time. Here's how we'll do it. Suppose an ID
has raw total zero. That makes it a candidate ID.

Now do a global INCR update. By this we mean that we have the GC
thread get INCR buffers from all the worker threads, and applies them
to the raw totals.

If the raw total for the candidate ID (drum roll) is still zero, then
the real total is also zero.

That's it. The rest is implementation.

Let's see why this is. First, note that we don't need to know exactly
when the real count became zero. We just need to know that it is now
zero. (And once zero, it stays zero.)

Now note that the real count can never be negative. Now suppose at
time T the raw count (for an ID) is zero, but that the real count is
one or more. That means that some worker process has a reference, and
so the ID appears in some INCR buffer.

Well, we just did a 

Re: [Python-ideas] A better (simpler) approach to PEP 505

2018-07-25 Thread Grégory Lielens


On Wednesday, July 25, 2018 at 10:33:37 AM UTC+2, Brice Parent wrote:
>
> I think the use case here is not really the simple 'is  None' + 'is not 
> None'.
>

Sure, that's why I also proposed to manually check a non-too-small samples 
of the None-testing occurences found by Guido .
You did it on your sample, and your findings findings are what I roughly 
expected.
I didn't do it. Well, not true, I sort of did it ;-), but I was lazy so I 
did not look enough to be representative, it was only a quick look at a 
very few instances:

I did not encounter deep hierarchy descent (I think the few we have use 
hasattr), but I found a couple where the proposed syntax would help but 
just a little: it's short and would use single ?? or ??=
By far, the most common case was using None as a marker for "we need a 
default sensible in the context", most of the time for a default argument. 
?? and ??= indeed makes things slightly shorter and usually slightly 
clearer, but the improvement is very small as  things are short and clear 
already. That's also why I was interested in the default argument 
delegating: In quite a few cases, the None default was because the real 
default was in a subfunction, and a way to delegate would be much more 
useful there.

if the case is just to replace one None value by something else, it's 
> not really an improvement as we just save one short line, and once the 
> new syntax is accepted and we're used to it, both solution are quite 
> explicit with what they do, so I'd prefer the status quo over a second 
> way of doing the same thing.
>

Yep, ditto. That's why I am -1 on ?? and ??= : They are useful, but not 
enough imho

It gets interesting in json-like cases, when we traverse a deep tree in 
> which we might encounter None at multiple levels. 
>

I hoped the PEP writers would submit such reallife examples, I think that's 
the motivation behind the PEP. But either I missed it, or they didn't show 
it yet. 
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] A better (simpler) approach to PEP 505

2018-07-25 Thread Brice Parent

Le 25/07/2018 à 08:49, Grégory Lielens a écrit :
BTW, I did (very quickly, so it's rough, my regexps are not really 
catching everything) the same or our code base:


"is None"+ "is not None": 5600
AttributeError: 160
3 args getattr: 60
hasattr: 1800

So very similar to your patternexcept for hasattr, which is much 
more common in my case...
(I'm not going to speak about how nice or ugly the syntax is, just about 
the use cases and statistics)


I think the use case here is not really the simple 'is  None' + 'is not 
None'.


if the case is just to replace one None value by something else, it's 
not really an improvement as we just save one short line, and once the 
new syntax is accepted and we're used to it, both solution are quite 
explicit with what they do, so I'd prefer the status quo over a second 
way of doing the same thing.


It gets interesting in json-like cases, when we traverse a deep tree in 
which we might encounter None at multiple levels. To me, the new 
functionality is better by than the status quo as it shortens the code 
drastically and makes it more readable (you may see the entire traversal 
at once).


So for the statistics, what's getting interesting is knowing when we are 
in that second case (but of course, it's harder to get them using simple 
regexes). Maybe we could find when there are more than one "is None" or 
"is not None" within the small block of code, and then manually check a 
few random dozens of those cases to see how many of them would be improved?
Another thing that would be interesting in those statistics, but 
probably even harder to get automatically, is the proportion of cases 
where there is a side effect involved (so the cases when we also need a 
temporary variable not to have the side effect executed twice). Those 
cases benefit more of the new syntax than from the old one, until 
there's a good solution with ':=' or a lazy evaluation syntax, or some 
function return caching from the caller side.
Also, it would be nice to know if those use cases come from specific 
libraries/functionalities (like json tree traversal or use of ORM) or 
from many different situations. In the first case, the improvement would 
probably belong inside the libraries themselves, or helpers could be 
created for this very purpose, and in the second case, if the problem is 
quite common, it gets interesting finding a solution inside Python 
itself, like what's described in this PEP.


I didn't automate those search in my codebase, I just searched for 'is 
None' and looked if it was complicated enough to justify a new syntax, 
and over 937 'is None', 43 were close to another 'is None', so I looked 
them up manually, and 13 could have benefited from the proposal, in the 
sense I described sooner, so more than 1 'is None' removed in a single 
line of code, and/or there was a side effect (I needed a temp variable 
not to have the side effect repeated). But I didn't check for side 
effects in the other 894 'is None', so this number should probably be a 
bit bigger.
Side note: we're not big JSON users, and when we do use some, we catch 
exceptions as it's never (here) normal not have well formed json 
strings, so the code never continues and we never have to use default 
values given by the backend.


___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] A better (simpler) approach to PEP 505

2018-07-25 Thread Grégory Lielens
BTW, I did (very quickly, so it's rough, my regexps are not really catching 
everything) the same or our code base:

"is None"+ "is not None": 5600
AttributeError: 160
3 args getattr: 60
hasattr: 1800

So very similar to your patternexcept for hasattr, which is much more 
common in my case...
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/