Re: seeking deeper (language theory) reason behind Python design choice

2018-05-19 Thread Peter J. Holzer
On 2018-05-19 11:38:09 +0300, Marko Rauhamaa wrote:
> "Peter J. Holzer" :
> > (I wonder whether the notion that “=” and “==” are easy to mix up
> > stems from the early days of C when C was an outlier (most other
> > languages at the time used “=” for equality). Now C is mainstream and
> > it's those other languages that seem odd.)
> 
> I occasionally mix them up one way or another, whether by typing them
> wrong accidentally or through some copy-and-paste mishap. Typos of all
> kind happen all the time, but the "="/"==" mixup isn't easy for the eye
> to spot and it doesn't create a syntax error.
> 
> A famous example:
> 
>+   if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
>+   retval = -EINVAL;

It's famous, but it is also a bad example:

1) It wasn't an accident, it was deliberate.
2) It was spotted.

hp

-- 
   _  | Peter J. Holzer| we build much bigger, better disasters now
|_|_) || because we have much more sophisticated
| |   | h...@hjp.at | management tools.
__/   | http://www.hjp.at/ | -- Ross Anderson 


signature.asc
Description: PGP signature
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-19 Thread Marko Rauhamaa
"Peter J. Holzer" :
> (I wonder whether the notion that “=” and “==” are easy to mix up
> stems from the early days of C when C was an outlier (most other
> languages at the time used “=” for equality). Now C is mainstream and
> it's those other languages that seem odd.)

I occasionally mix them up one way or another, whether by typing them
wrong accidentally or through some copy-and-paste mishap. Typos of all
kind happen all the time, but the "="/"==" mixup isn't easy for the eye
to spot and it doesn't create a syntax error.

A famous example:

   +   if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
   +   retval = -EINVAL;

   https://lwn.net/Articles/57135/>


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-19 Thread Peter J. Holzer
On 2018-05-16 01:26:38 +0100, bartc wrote:
> On 15/05/2018 21:21, Peter J. Holzer wrote:
> > I have been programming in C since the mid-80's and in Perl since the
> > mid-90's (both languages allow assignment expressions). I accumulated my
> > fair share of bugs in that time, but AFAIR I made this particular error
> > very rarely (I cannot confidently claim that I never made it). Clearly
> > it is not “a total bug magnet” in my experience. There are much bigger
> > problems in C and Perl (and Python, too). But of course my experience is
> 
> All those languages use = for assignment and == for equality.
> 
> If like me you normally use a language where = means equality (and := is
> used for assignment), then you're going to get it wrong more frequently when
> using C or Python (I don't use Perl).

Absolutely. These days I program mostly in Python and Perl and find that
I often omit semicolons in Perl. If I was programming in Pascal and C I
probably would mix up “:=”, “=” and “==”. But I don't. All the programming
languages I have used regularly (C, Perl, Java, JavaScript, Python) use
the same operators for assignment and comparison. So my fingers know what
to type.

(I wonder whether the notion that “=” and “==” are easy to mix up stems
from the early days of C when C was an outlier (most other languages at
the time used “=” for equality). Now C is mainstream and it's those other
languages that seem odd.)

> You might get it wrong anyway because = is used for equality in the real
> world too.

Not after a few years of programming. Probably not even after a few
weeks of programming. You develop muscle memory quite quickly. 

hp

-- 
   _  | Peter J. Holzer| we build much bigger, better disasters now
|_|_) || because we have much more sophisticated
| |   | h...@hjp.at | management tools.
__/   | http://www.hjp.at/ | -- Ross Anderson 


signature.asc
Description: PGP signature
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-19 Thread Peter J. Holzer
On 2018-05-16 00:04:06 +, Steven D'Aprano wrote:
> On Tue, 15 May 2018 22:21:15 +0200, Peter J. Holzer wrote:
> > On 2018-05-15 00:52:42 +, Steven D'Aprano wrote:
> [...]
> >> By 1991 there had already been *decades* of experience with C
> > 
> > About one and a half decades.
> 
> That would still be plural decades.
> 
> C's first release was 1972, so more like 19 years than 15.

I thought it was 1974, but Ritchie writes "By early 1973, the essentials
of modern C were complete." So you are closer than me. But we don't
know whether those early users of C tended to confuse “=” and “==”
(Ritchie did change the compound assignments from ”=+”, “=-” etc. so
“+=”, “-=”, etc., so at the early stages he did change syntax if it
proved to be error-prone. He didn't change the precedence of “&” and “|”
after introducing “&&” and “||”, though.). C spread beyond the Unix team
in the mid to late 70s.

> >> proving that the "=" assignment syntax is dangerously confusable with
> >> == and a total bug magnet when allowed as expressions as well, so it
> >> was perfectly reasonable to ban it from the language.
> > 
> > Experience? Yes. Data? I doubt it.
> 
> I'm using "proving" informally above, not in the sense of actual legal or 
> scientific standards of proof.

“Proof by assertion”? I am not a native English speaker, but I don't
think just claiming that something is the case constitutes a “proof”
even in the most informal use of the language.

Humans are notoriously bad at estimating risk. We often talk a lot about
and take rather extreme measures to avoid relatively small risks (e.g.
being killed in a terrorist attack) while mostly ignoring much larger
risks (e.g. being killed in a car accident). Yes, bugs of this class
were found in the wild. Yes, compiler writers added warnings about
suspicious use of assignments in a boolean context. Yes, Guido avoided
assignment expressions because he thought they were too dangerous. But
does any of this prove that assignment expressions are “a total bug
magnet”? I don't think so.


> If you are going to object to that, remember that neither is there 
> scientific data proving that assignment as an expression is useful, so we 
> can always just reject the construct as "useless until proven otherwise" 
> :-)

It is used, therefore it is useful ;-).

I think it is very useful in C which reports exceptional conditions
(errors, end of file, ...) by returning reserved values. So you often
want to combine an assignment and a test. The vast majority of
assignment sub-expressions you'll see in a C program are of this type.

I think it would be much less useful in Python, because Python has
exceptions and generators (and these are used by both the standard
library and idiomatic Python code). So most situations where you would
use an assignment sub-expression in C simply don't arise. As I said, I
don't miss the feature in Python.


> > I have been programming in C since the mid-80's [...]
> > I guess I could write a script which
> > searches through all my repositories for changesets where “=” was
> > replaced by “==”. Not sure what that would prove.)
> 
> You were using version control repositories in the 1980s, and still have 
> access to them? I'm impressed.

I started using Unix in early 1987 and SCCS shortly afterwards. So this
year may mark my 30th anniversary as a version control system user. But
I don't know if I still have any of my SCCS repos, and if I have, the
disks and tapes probably aren't readable any more.

But I wasn't actually thinking of going that far back. I am not much
interested whether I made that kind of error as a C newbie in 1987. I am
interested whether I made it as an experienced C and Perl programmer.
So I was thinking of analyzing repos which are moderately current. If I
could find cases where I wrote “=” instead of “==”, I'd have to admit
that a) I do make that error at least occationally and b) I don't always
find it before committing. But that still wouldn't prove anything: I
would have to compare it to other bug classes, and most importantly,
whether a single programmer (me) tends make (or not make) a specific
error doesn't say anything about the entirety of programmers. And it's
the latter that counts.


> > OTOH, despite having used C and Perl long before Python, I don't miss
> > assignment expressions. Every language has its idioms, and just because
> > you write stuff like “if ((fd = open(...)) == -1)” a lot in C doesn't
> > mean you have to be able to write that in Python.
> 
> I'm not a C coder, but I think that specific example would be immune to 
> the bug we are discussing, since (I think) you can't chain assignments in 
> C. Am I right?
> 
> fd = open(...)) = -1
> 
> would be a syntax error.

Yes, because you omitted a parenthesis ;-), But yes, that would be error
(although not a syntax error - the syntax is fine), because the result
of an assignment isn't an l-value in standard C and cannot be assigned
to. Some compilers (among them 

Re: seeking deeper (language theory) reason behind Python design choice

2018-05-16 Thread Ian Kelly
On Wed, May 16, 2018 at 10:06 AM, bartc  wrote:
> On 16/05/2018 16:09, Ian Kelly wrote:
>>
>> On Tue, May 15, 2018, 6:36 PM bartc  wrote:
>>
>>> On 16/05/2018 01:04, Steven D'Aprano wrote:
>>>
 I'm not a C coder, but I think that specific example would be immune to
 the bug we are discussing, since (I think) you can't chain assignments
 in
 C. Am I right?
>>>
>>>
>>> Assignments can be chained in C (with right-to-left precedence) as can
>>> augmented assignments (+= and so on).
>>>
>>
>> Yes, but not in the particular example that Steven was referring to, which
>> you elided from your quoting.
>
>
> I was responding to the chained assignment bit:
>
>  a = b = c = d = x;
>
> is allowed, but (depending on implementation details), the first = might be
> a different kind of assignment from the other three.
>
>> open(...) is not a valid LHS for assignment.
>
>
> The LHS needs to be an lvalue. A function result by itself won't be. open()
> would need to be a macro that expands to an lvalue, or used like this when
> open() returns a pointer:
>
>a = *open() = x;
>
> So it only needs an extra * (subject to the correct types of everything
> involved) for both these "=" to be plausible.

Sure, but that wasn't the example. The macro possibility is a good
point, but that's technically the C preprocessor, not the C language
itself.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-16 Thread bartc

On 16/05/2018 16:09, Ian Kelly wrote:

On Tue, May 15, 2018, 6:36 PM bartc  wrote:


On 16/05/2018 01:04, Steven D'Aprano wrote:


I'm not a C coder, but I think that specific example would be immune to
the bug we are discussing, since (I think) you can't chain assignments in
C. Am I right?


Assignments can be chained in C (with right-to-left precedence) as can
augmented assignments (+= and so on).



Yes, but not in the particular example that Steven was referring to, which
you elided from your quoting.


I was responding to the chained assignment bit:

 a = b = c = d = x;

is allowed, but (depending on implementation details), the first = might 
be a different kind of assignment from the other three.



open(...) is not a valid LHS for assignment.


The LHS needs to be an lvalue. A function result by itself won't be. 
open() would need to be a macro that expands to an lvalue, or used like 
this when open() returns a pointer:


   a = *open() = x;

So it only needs an extra * (subject to the correct types of everything 
involved) for both these "=" to be plausible.


--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-16 Thread Ian Kelly
On Tue, May 15, 2018, 6:36 PM bartc  wrote:

> On 16/05/2018 01:04, Steven D'Aprano wrote:
>
> > I'm not a C coder, but I think that specific example would be immune to
> > the bug we are discussing, since (I think) you can't chain assignments in
> > C. Am I right?
>
> Assignments can be chained in C (with right-to-left precedence) as can
> augmented assignments (+= and so on).
>

Yes, but not in the particular example that Steven was referring to, which
you elided from your quoting. open(...) is not a valid LHS for assignment.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-16 Thread Chris Angelico
On Thu, May 17, 2018 at 12:25 AM, Grant Edwards
 wrote:
> On 2018-05-16, Steven D'Aprano  wrote:
>> On Tue, 15 May 2018 22:21:15 +0200, Peter J. Holzer wrote:
>>
>>> On 2018-05-15 00:52:42 +, Steven D'Aprano wrote:
>> [...]
 By 1991 there had already been *decades* of experience with C
>>>
>>> About one and a half decades.
>>
>> That would still be plural decades.
>
> So would zero. ;)
>
> The only plural in English implies is that the quantity is not 1.  It
> does _not_ imply the quantity is greater than 1.

By 1991 there had already been AT LEAST negative seven decades of
experience with C. It's mathematically provable! And completely
useless.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-16 Thread Grant Edwards
On 2018-05-16, Steven D'Aprano  wrote:
> On Tue, 15 May 2018 22:21:15 +0200, Peter J. Holzer wrote:
>
>> On 2018-05-15 00:52:42 +, Steven D'Aprano wrote:
> [...]
>>> By 1991 there had already been *decades* of experience with C
>> 
>> About one and a half decades.
>
> That would still be plural decades.

So would zero. ;)

The only plural in English implies is that the quantity is not 1.  It
does _not_ imply the quantity is greater than 1.

-- 
Grant Edwards   grant.b.edwardsYow! !  Now I understand
  at   advanced MICROBIOLOGY and
  gmail.comth' new TAX REFORM laws!!

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread bartc

On 16/05/2018 01:04, Steven D'Aprano wrote:


I'm not a C coder, but I think that specific example would be immune to
the bug we are discussing, since (I think) you can't chain assignments in
C. Am I right?


Assignments can be chained in C (with right-to-left precedence) as can 
augmented assignments (+= and so on).


--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread bartc

On 15/05/2018 21:21, Peter J. Holzer wrote:


I have been programming in C since the mid-80's and in Perl since the
mid-90's (both languages allow assignment expressions). I accumulated my
fair share of bugs in that time, but AFAIR I made this particular error
very rarely (I cannot confidently claim that I never made it). Clearly
it is not “a total bug magnet” in my experience. There are much bigger
problems in C and Perl (and Python, too). But of course my experience is


All those languages use = for assignment and == for equality.

If like me you normally use a language where = means equality (and := is 
used for assignment), then you're going to get it wrong more frequently 
when using C or Python (I don't use Perl).


You might get it wrong anyway because = is used for equality in the real 
world too.


And it's an error that is awkward to detect (in C anyway, as it would be 
an error in Python) because usually both = and == are plausible in an 
expression.


--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread Steven D'Aprano
On Tue, 15 May 2018 22:21:15 +0200, Peter J. Holzer wrote:

> On 2018-05-15 00:52:42 +, Steven D'Aprano wrote:
[...]
>> By 1991 there had already been *decades* of experience with C
> 
> About one and a half decades.

That would still be plural decades.

C's first release was 1972, so more like 19 years than 15. That's just 
under two decades.


>> proving that the "=" assignment syntax is dangerously confusable with
>> == and a total bug magnet when allowed as expressions as well, so it
>> was perfectly reasonable to ban it from the language.
> 
> Experience? Yes. Data? I doubt it.

I'm using "proving" informally above, not in the sense of actual legal or 
scientific standards of proof.

If you are going to object to that, remember that neither is there 
scientific data proving that assignment as an expression is useful, so we 
can always just reject the construct as "useless until proven otherwise" 
:-)


> I will readily admit that my knowledge of research into the usability of
> programming languages is more than spotty, but I have read a few papers
> about the topic over the last decade. I don't recall any which
> quantified "bug magnets" under realistic conditions (two hour toy
> problems for first-year students don't count). I thought there was one
> by Google, but that was about compile-time errors.
> 
> Language design ist still mostly an art driven by gut feeling, not
> engineering driven by data. I doubt that this was better in 1991.
> 
> I have been programming in C since the mid-80's [...]
> I guess I could write a script which
> searches through all my repositories for changesets where “=” was
> replaced by “==”. Not sure what that would prove.)

You were using version control repositories in the 1980s, and still have 
access to them? I'm impressed.


> OTOH, despite having used C and Perl long before Python, I don't miss
> assignment expressions. Every language has its idioms, and just because
> you write stuff like “if ((fd = open(...)) == -1)” a lot in C doesn't
> mean you have to be able to write that in Python.

I'm not a C coder, but I think that specific example would be immune to 
the bug we are discussing, since (I think) you can't chain assignments in 
C. Am I right?

fd = open(...)) = -1

would be a syntax error. But:

fd = -1

would not be.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread Peter J. Holzer
On 2018-05-15 00:52:42 +, Steven D'Aprano wrote:
> Now remember that in 1991 when Guido made the decision to ban = as an 
> expression, those concepts didn't even exist. There were no Python 
> linters, and no reason to imagine that there ever would be. Guido didn't 
> know that Python would become one of the top 10 most used languages. For 
> all he knew, version 1.0 could be the final release.
> 
> By 1991 there had already been *decades* of experience with C

About one and a half decades.

> proving that the "=" assignment syntax is dangerously confusable with
> == and a total bug magnet when allowed as expressions as well, so it
> was perfectly reasonable to ban it from the language.

Experience? Yes. Data? I doubt it.

I will readily admit that my knowledge of research into the usability
of programming languages is more than spotty, but I have read a few
papers about the topic over the last decade. I don't recall any which
quantified "bug magnets" under realistic conditions (two hour toy
problems for first-year students don't count). I thought there was one
by Google, but that was about compile-time errors.

Language design ist still mostly an art driven by gut feeling, not
engineering driven by data. I doubt that this was better in 1991.

I have been programming in C since the mid-80's and in Perl since the
mid-90's (both languages allow assignment expressions). I accumulated my
fair share of bugs in that time, but AFAIR I made this particular error
very rarely (I cannot confidently claim that I never made it). Clearly
it is not “a total bug magnet” in my experience. There are much bigger
problems in C and Perl (and Python, too). But of course my experience is
just that of a single programmer (or a handful if I include people
whose code I've reviewed or debugged) and in any case just anecdotal.
(Could I quantify even my own experience? I guess I could write a script
which searches through all my repositories for changesets where “=” was
replaced by “==”. Not sure what that would prove.)

OTOH, despite having used C and Perl long before Python, I don't miss
assignment expressions. Every language has its idioms, and just because
you write stuff like “if ((fd = open(...)) == -1)” a lot in C doesn't
mean you have to be able to write that in Python.

hp

-- 
   _  | Peter J. Holzer| we build much bigger, better disasters now
|_|_) || because we have much more sophisticated
| |   | h...@hjp.at | management tools.
__/   | http://www.hjp.at/ | -- Ross Anderson 


signature.asc
Description: PGP signature
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread Python
On Tue, May 15, 2018 at 12:52:42AM +, Steven D'Aprano wrote:
> But you miss the point that even if = versus == errors are picked up by 
> code reviews or tests, they are still software bugs. Your *process* 
> (testing and reviews) picked up the bug before they went into production, 
> but *the bug still was made*.

I do not miss this point.  My premise from the beginning was that
humans make mistakes, this bug will occur, and most importantly it's
no worse than any other bug.  Wrong code is wrong code.  YOU'RE GOING
TO SCREW UP, and you need *SOMETHING* in place to catch that.  It may
as well also catch this, and it's NOT that hard to do... If you had no
other tools, you could write a regex to scan your code for it and
review the matches.  If you never discovered that this was a
well-known pitfall that's one thing, but I've known about it since
approximately 1986--it's been around a long time as you yourself say,
so there's no excuse for someone now, 30+ years later, not knowing
about it and watching out for it... unless they simply don't care
about writing working code and so put no effort into learning about
such things.

The noob argument only reinforces my point--they're going to screw up
all manner of things, until they learn not to...  The noob argument is
only a worse example of the same reason why we have software
development process (and mentors).  If you're in the unfortunate
position you described, where you don't have peer review, then you
need to employ good proccess EVEN MORE, because you have only yourself
to rely on.  If you don't employ it, it's pretty much a guanrantee
that your software quality will be sub par, unless you are a true
superstar.  [They exist, I've come to know a small handful.
Unfortunately I am not one of them.]

Seperately, I asserted that you can, if you really want to, learn to
not make this mistake, BUT IT'S NOT RELEVANT TO MY POINT.  In life we
learn to stop making all manner of mistakes, and reduce the frequency
of others.  In nearly half a century of life, I've NEVER made the
mistake of putting my hand on a hot stove burner, because I've learned
that it's dangerous, and take extra care around hot stove burners.  To
me this bug is exactly the same.  Likewise I'm POSITIVE there are
types of mistakes that YOU never make, though this bug may not be one
of them.  I'm certain it can be one that you learn to not make, if you
exert the required effort, whatever it may be *for you*.  But I must
admit that neither of us can conclusively prove the other wrong, and
you will likely believe whatever you've convinced yourself of already,
just as I do, and that's fine.  

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-15 Thread Steven D'Aprano
On Mon, 14 May 2018 21:24:01 -0400, Dennis Lee Bieber wrote:


>   The problem with adding the feature is that it will start to be
> used by
> newbies who lack the discipline to use it reliably: ensuring that
> comparisons are coded with constants (which for Python really means
> literals) on the left-hand side, so that a type of "=" for "==" will be
> flagged and not transparently pass.


Using = alone is absolutely not on the table.

The current two leading contenders, both controversial, are:

name := expression

name given name = expression


The second is being sponsored, backed, supported and subsidised by the 
Department of Repeated Redundancy and Repetitiveness.

(And before you ask, unfortunately "expression as name" has been ruled 
out because it is ambiguous with other uses of "as".


-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Steven D'Aprano
On Mon, 14 May 2018 18:20:13 -0500, Python wrote:

> I am hardly perfect.

Have you tried just wanting to be perfect more?


Look, we get it: it is possible to improve the quality of your code by 
paying attention to what you do, by proof-reading, testing, code reviews, 
warnings, linters, etc. We're not all doomed to be careless coders. I 
agree completely.

Also agree completely that assignment in expressions is sometimes useful.

Also agree that *with care and good management* it is possible to reduce 
the error rate from assignment-expressions to a manageable level -- even 
if assignment is spelled "=". Not to *zero*, but some non-zero manageable 
level.

But you miss the point that even if = versus == errors are picked up by 
code reviews or tests, they are still software bugs. Your *process* 
(testing and reviews) picked up the bug before they went into production, 
but *the bug still was made*.

A mere typo is not a bug if the compiler flags it before the code runs. 
It's just a typo.

So instead of congratulating yourself over how you never make the = 
versus == bug, you ought to be sheepishly realising how often you make 
it, but fortunately you have the processes in place to catch it before it 
reaches production.

Now remember that not every programmer works in large teams with pair 
programming, code reviews, test driven development, automatic buildbots 
to catch errors, etc.

Now remember that in 1991 when Guido made the decision to ban = as an 
expression, those concepts didn't even exist. There were no Python 
linters, and no reason to imagine that there ever would be. Guido didn't 
know that Python would become one of the top 10 most used languages. For 
all he knew, version 1.0 could be the final release.

By 1991 there had already been *decades* of experience with C proving 
that the "=" assignment syntax is dangerously confusable with == and a 
total bug magnet when allowed as expressions as well, so it was perfectly 
reasonable to ban it from the language.

There's nothing you can do with assignment expressions that can't be done 
*almost* as easily with assignment statements. Its often a matter of mere 
personal preference, do I want to write this as a single line or two?

And as the discussions over PEP 572 prove, the choice about allowing 
assignment expressions is *not easy*. Not only is there the matter of 
whether or not to allow it, but what spelling to use, and what scope the 
assignment should operate in.

And if you think that last one is the most trivial, in fact with list 
comprehensions and generator expressions, it will probably end up being 
the most controversial of all the questions.

And the most likely to sink the proposal.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Chris Angelico
On Tue, May 15, 2018 at 9:20 AM, Python  wrote:
> I'm well acquainted with that pheonomenon, though I daresay that if
> you proofread your own product you will often find your mistakes.  You
> just won't always.  But, I never said review it right after you wrote
> it, and in fact I don't do that (well, I do reread it if it seems
> something potentially concerning).  Rather I review it when I'm about
> to check it in, which for anything non-trivial is generally days
> later, after it's been tested (which implies the tests were written).
> I find my own bugs very often (but not nearly as often as I'd like).

Where does your code sit during those days? What happens if multiple
people make changes to the same files in parallel - do you deal with
merge conflicts all the time simply because you don't want to push
code in a timely manner?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Python
On Mon, May 14, 2018 at 12:02:47PM -0600, Ian Kelly wrote:
> On Mon, May 14, 2018 at 9:38 AM, Python  wrote:
> > Absolutely correct.  If you're not doing THOROUGH code reviews, and
> > not thoroughly testing your code, your job is only half done.  You
> > should be your own first reviewer, and then have a second someone
> > competent review it after you do.
> 
> One should never be their own "first reviewer" because it may lead to
> the mindset that a "second reviewer" is unnecessary.

I went on to say that the second reviewer was required (i.e. this
should be considered a required part of good process).  If you decide
this is your process and it's required then it's required, regardless
of what you personally think.

> You're about as likely to notice the glaring bugs in the code that
> you just wrote as you are to notice the missing or misspelled words
> in the sentence you just penned.

I'm well acquainted with that pheonomenon, though I daresay that if
you proofread your own product you will often find your mistakes.  You
just won't always.  But, I never said review it right after you wrote
it, and in fact I don't do that (well, I do reread it if it seems
something potentially concerning).  Rather I review it when I'm about
to check it in, which for anything non-trivial is generally days
later, after it's been tested (which implies the tests were written).
I find my own bugs very often (but not nearly as often as I'd like).

I am hardly perfect.  What I am is thorough.  I would argue that is
required to write quality software.  If your goal is not to write
quality software, then none of this matters.  And if it is your goal,
you shouldn't need to care about this, because you'll either get it
right through whatever process you have, or you'll avoid it entirely
if you don't think your process is adequate.  Your choice.  Or not, if
the language decides you can't be responsible enough to make that
choice for yourself.

> That said, when I'm doing a code review, my focus is on all of the
> following things:
> 
> * Design: does this code make sense for what it's trying to accomplish?
> * Functionality: does the code work as intended?
> * Readability: can I understand it, and will others understand it later?
> * Complexity: could this code be simpler?
> * Tests: does the code include good tests?

These all seem fine, but if you're missing extremely well-known
pitfalls, then... I'll prefer a different code reviewer. :)  Maybe you
should consider adding that to your list.

> The existence of subtle bugs are just one of the things that I'm
> thinking about, so from my perspective, the more the compiler can help
> with this, the better.

I don't disagree with that, except that I don't consider this a subtle
bug, largely on account of its aforementioned status as well-known
pitfall.  But niether do I consider it damning, obviously.

> In C, if I miss a misplaced '=' then the code will do the wrong
> thing. 

Better yet, the compiler should warn you about it (which I believe it
does).  And you should be compiling with warnings. 

> In Python, I don't even have to worry about it, and I like it that
> way. 

If you're so concerned about making that mistake, YOU CAN CHOOSE TO
NOT USE THAT CONSTRUCT.  It doesn't need to be a decision forced on
you by the compiler.

As we've learned in this thread, there is a PEP for implementing this
feature which Guido apparently approves, so it can't be all that evil
after all, can it?

> So when you say that '=' as an expression should be supported
> because you think it's useful, and anyway those sorts of bugs will
> be caught by code reviews, the way that reads to me is:

Actually if you read all of what I wrote, you'll know that what I said
was assignment as an expression should be allowed, and if there were
to be a different operator to express that to avoid confusion, that
would be just fine with me.  But I don't think that need be a
condition.

> "'=' as an expression should be supported because it's convenient to
> me, and I don't believe I write bugs

Convenience is sort of Python's gig, isn't it?  "Make simple things
easy, make hard things possible."

> and if I do it doesn't matter because my time is important than that
> of the person who reviews my code."

Circumstantially, that may actually be true... or it may not.  Depends
on who you're working with, their roles and seniority, relative skill
and compensation, and probably  other factors.  Most groups have such
a heirarchy, even if it is largely implied rather than stated.
HOWEVER it hardly matters if the construct in question is accepted
practice.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Ian Kelly
On Mon, May 14, 2018 at 9:38 AM, Python  wrote:
> Absolutely correct.  If you're not doing THOROUGH code reviews, and
> not thoroughly testing your code, your job is only half done.  You
> should be your own first reviewer, and then have a second someone
> competent review it after you do.

One should never be their own "first reviewer" because it may lead to
the mindset that a "second reviewer" is unnecessary. You're about as
likely to notice the glaring bugs in the code that you just wrote as
you are to notice the missing or misspelled words in the sentence you
just penned. Why? Because you just wrote it, and as a result you
believe that you know what it says, and you'll simply fail to process
the fact that it actually says something different.

That said, when I'm doing a code review, my focus is on all of the
following things:

* Design: does this code make sense for what it's trying to accomplish?
* Functionality: does the code work as intended?
* Readability: can I understand it, and will others understand it later?
* Complexity: could this code be simpler?
* Tests: does the code include good tests?

The existence of subtle bugs are just one of the things that I'm
thinking about, so from my perspective, the more the compiler can help
with this, the better. In C, if I miss a misplaced '=' then the code
will do the wrong thing. In Python, I don't even have to worry about
it, and I like it that way. So when you say that '=' as an expression
should be supported because you think it's useful, and anyway those
sorts of bugs will be caught by code reviews, the way that reads to me
is:

"'=' as an expression should be supported because it's convenient to
me, and I don't believe I write bugs, and if I do it doesn't matter
because my time is important than that of the person who reviews my
code."
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Ian Kelly
On Mon, May 14, 2018 at 9:20 AM, Python  wrote:
> On Sun, May 13, 2018 at 02:42:48PM +1000, Chris Angelico wrote:
>> On Sun, May 13, 2018 at 2:31 PM, Python  wrote:
>> >> Yes, and I'd go further: I *am* too stupid to get this right.
>> >
>> > No, you are not.  Do you ever say "dog" when you mean "dot" instead?
>> > Do you ever say "dad" when you mean "mom" instead?  Internalize that
>> > "=" is "equals" (or "assigns" if you prefer) and "==" is "is equal to"
>> > then use those phrases in your head when you're thinking about which
>> > one you need in your code, and I'm pretty sure you'll stop making this
>> > mistake.  It may help that the phrase with twice as many syllables
>> > represents the operator that has twice as many characters.  Eventually
>> > it becomes second nature, like not calling Dad "Mom."
>>
>> Rght, of course. Because prevention of bugs is just a matter of
>> wanting to.
>
> Preventing *certain classes* of bugs, mainly botching syntax, is mostly
> just a matter of wanting to, like a piano virtuoso who can play
> complicated pieces night after night flawlessly.  It just takes focus
> and practice.  Preventing the = vs. == bug is nowhere near as
> complex or difficut as La Campanella, so you don't even need to be a
> virtuoso.  You just have to be mindful and careful.

I'm reminded of the first bullet point of step 6 in this article,
which just crossed my inbox this morning:

https://www.e4developer.com/2018/05/13/how-to-write-horrible-java/
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Steven D'Aprano
On Mon, 14 May 2018 10:20:06 -0500, Python wrote:

> Preventing *certain classes* of bugs, mainly botching syntax, is mostly
> just a matter of wanting to, 

That comment is very ignorant of the mental processes involved in both 
language processing and typing, two skills used in programming. You can't 
prevent errors merely, or even "mostly", by wanting not to make errors.


> like a piano virtuoso who can play
> complicated pieces night after night flawlessly.

Right up until the moment that they make a mistake, which they do.

Virtuosos suffer from fatigue or injuries, they have slumps, they have 
bad days, they often cannot reproduce the same performance (every 
performance is unique since they are not robots that can repeat every 
minute motion over and over again) and they make mistakes. "Flawlessly" 
does not mean without flaw, it is mere hyperbole.

https://www.telegraph.co.uk/culture/music/
classicalconcertreviews/10878171/Khatia-Buniatishvili-Queen-Elizabeth-
Hall-review-sorely-disappointing.html


> It just takes focus
> and practice.  Preventing the = vs. == bug is nowhere near as complex or
> difficut as La Campanella, so you don't even need to be a virtuoso.  You
> just have to be mindful and careful.

Botched syntax is a form of botched spelling.

https://mail.python.org/pipermail/python-list/2018-May/733040.html

Maybe you just didn't want to spell "pposted" or "lenghty" correctly?


À propos of nothing, I used to know somebody who seriously used to argue 
that his spelling mistakes were deliberate. Not as as a self-deprecating 
joke. He literally tried to convince people that whenever he spelled 
something incorrectly, it was a deliberate choice for "irony" or 
"rhetorical effect" or "my own personal reasons". He fooled nobody.

Very sad, the extents people will go to to fool themselves into believing 
that they have 100% control over each and every one of their actions. 
Just sayin'.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Python
On Sun, May 13, 2018 at 09:46:48PM +1000, Chris Angelico wrote:
> > I expect that these days it will be rare, since most C compilers would
> > default to warning about it if you run with warnings enabled.
> 
> That assumes that you regularly run with warnings enabled. While that
> might seem like a no-brainer, unfortunately it isn't. With the number
> of C compilers out there, it's hard to make sure your code compiles
> cleanly with -Wall on every one of them; and if there's a spew of
> warnings, one more isn't going to be noticed. So for a large codebase,
> it's entirely possible that it WON'T regularly be compiled with
> warnings enabled.

As it happens, my team does compile with -Wall -Werror at all times in
every project (though we do rely on some third-party libraries as
dependencies which we can not). But I do agree with your point...

> Warnings certainly help, but they're not a complete solution.

Absolutely correct.  If you're not doing THOROUGH code reviews, and
not thoroughly testing your code, your job is only half done.  You
should be your own first reviewer, and then have a second someone
competent review it after you do.  You should also be your own first
tester, and then have someone competent test it after you.  In both
cases, ideally the "someone competent" would be a team of someones,
though that's not always practical.  But I believe this process is
absolutely essential to producing non-trivial quality software.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Python
On Sun, May 13, 2018 at 11:05:48AM +, Steven D'Aprano wrote:
> On Sat, 12 May 2018 21:42:13 -0500, Python wrote:
> 
> > Responding to this further would essentially just require me to
> > reiterate what I already wrote--I won't do that.  I'll simply maintain
> > that in my rather lenghty experience, this mistake has actually been
> > rather rare and has to my knowledge *never* caused a support issue
> > requiring a bug fix to production code in projects I've been associated
> > with.  It's a useful construction whose detriment has, IMO, been
> > completely overblown.
> 
> I already linked to the attempt to install a backdoor in the Linux kernel 
> with this, but even for accidental errors, thirty seconds on the CVE 
> database finds at least one real-world example:
> 
> https://www.cvedetails.com/cve/CVE-2009-4633/
> 
> I expect that these days it will be rare, since most C compilers would 
> default to warning about it if you run with warnings enabled.

A couple of anecdotes is a very far way off from making the case.
Either the code was not reviewed or the reviewer was careless.  And
I'm not saying it never happens, I'm saying it's not any worse than
any other possible bug, and far less common in practice than plenty of
other classes of bugs.  I'm also not saying that you couldn't use a
different operator that's less likely to cause confusion.  I *am*
saying this is a useful feature that I find myself wanting very often.
Obviously since there's a PEP about a way to provide exactly this
feature, plenty of people consider it a worthwhile feature to have.

Yes, bugs happen.  Eliminating useful constructs from the language is
not a good way of dealing with that problem.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Python
On Sun, May 13, 2018 at 02:42:48PM +1000, Chris Angelico wrote:
> On Sun, May 13, 2018 at 2:31 PM, Python  wrote:
> >> Yes, and I'd go further: I *am* too stupid to get this right.
> >
> > No, you are not.  Do you ever say "dog" when you mean "dot" instead?
> > Do you ever say "dad" when you mean "mom" instead?  Internalize that
> > "=" is "equals" (or "assigns" if you prefer) and "==" is "is equal to"
> > then use those phrases in your head when you're thinking about which
> > one you need in your code, and I'm pretty sure you'll stop making this
> > mistake.  It may help that the phrase with twice as many syllables
> > represents the operator that has twice as many characters.  Eventually
> > it becomes second nature, like not calling Dad "Mom."
> 
> Rght, of course. Because prevention of bugs is just a matter of
> wanting to. 

Preventing *certain classes* of bugs, mainly botching syntax, is mostly
just a matter of wanting to, like a piano virtuoso who can play
complicated pieces night after night flawlessly.  It just takes focus
and practice.  Preventing the = vs. == bug is nowhere near as 
complex or difficut as La Campanella, so you don't even need to be a
virtuoso.  You just have to be mindful and careful.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Chris Angelico
On Mon, May 14, 2018 at 10:49 PM, Rhodri James  wrote:
> On 13/05/18 05:31, Python wrote:
>>
>> No, you are not.  Do you ever say "dog" when you mean "dot" instead?
>> Do you ever say "dad" when you mean "mom" instead?
>
>
> One of my aunts used to muddle family names all the time.  She once called
> me by my sister's name; one would have thought the beard was a clue to that
> one.
>
> Similarly  my mother once asked my sister to "Get the thingummy off the
> whatsit."  The alarming thing was that my sister understood this and handed
> her the correct object.

That's alarming to you? It's pretty normal in my family. I think we
all developed mindreading abilities as young children, or something.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-14 Thread Rhodri James

On 13/05/18 05:31, Python wrote:

No, you are not.  Do you ever say "dog" when you mean "dot" instead?
Do you ever say "dad" when you mean "mom" instead?


One of my aunts used to muddle family names all the time.  She once 
called me by my sister's name; one would have thought the beard was a 
clue to that one.


Similarly  my mother once asked my sister to "Get the thingummy off the 
whatsit."  The alarming thing was that my sister understood this and 
handed her the correct object.


So yes, actually we do make that kind of error all the time.  Moreover, 
it's very hard to notice *in your own code* because you read what you 
meant, not what you wrote.  Ask any author about proof-reading, and 
they'll tell you to get someone else to do it.


--
Rhodri James *-* Kynesim Ltd
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-13 Thread Chris Angelico
On Sun, May 13, 2018 at 9:05 PM, Steven D'Aprano
 wrote:
> On Sat, 12 May 2018 21:42:13 -0500, Python wrote:
>
>> Responding to this further would essentially just require me to
>> reiterate what I already wrote--I won't do that.  I'll simply maintain
>> that in my rather lenghty experience, this mistake has actually been
>> rather rare and has to my knowledge *never* caused a support issue
>> requiring a bug fix to production code in projects I've been associated
>> with.  It's a useful construction whose detriment has, IMO, been
>> completely overblown.
>
> I already linked to the attempt to install a backdoor in the Linux kernel
> with this, but even for accidental errors, thirty seconds on the CVE
> database finds at least one real-world example:
>
> https://www.cvedetails.com/cve/CVE-2009-4633/
>
>
> I expect that these days it will be rare, since most C compilers would
> default to warning about it if you run with warnings enabled.
>

That assumes that you regularly run with warnings enabled. While that
might seem like a no-brainer, unfortunately it isn't. With the number
of C compilers out there, it's hard to make sure your code compiles
cleanly with -Wall on every one of them; and if there's a spew of
warnings, one more isn't going to be noticed. So for a large codebase,
it's entirely possible that it WON'T regularly be compiled with
warnings enabled.

Warnings certainly help, but they're not a complete solution.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-13 Thread Steven D'Aprano
On Sat, 12 May 2018 21:42:13 -0500, Python wrote:

> Responding to this further would essentially just require me to
> reiterate what I already wrote--I won't do that.  I'll simply maintain
> that in my rather lenghty experience, this mistake has actually been
> rather rare and has to my knowledge *never* caused a support issue
> requiring a bug fix to production code in projects I've been associated
> with.  It's a useful construction whose detriment has, IMO, been
> completely overblown.

I already linked to the attempt to install a backdoor in the Linux kernel 
with this, but even for accidental errors, thirty seconds on the CVE 
database finds at least one real-world example:

https://www.cvedetails.com/cve/CVE-2009-4633/


I expect that these days it will be rare, since most C compilers would 
default to warning about it if you run with warnings enabled.


-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Chris Angelico
On Sun, May 13, 2018 at 2:31 PM, Python  wrote:
> On Wed, May 09, 2018 at 03:57:35PM +1000, Chris Angelico wrote:
>> On Wed, May 9, 2018 at 3:44 PM, Steven D'Aprano
>> > If all programmers were as awesome as you and never made typos, the world
>> > would be a better place. But we know from experience that even
>> > experienced C programmers can make this mistake by accident.
>>
>> Yes, and I'd go further: I *am* too stupid to get this right.
>
> No, you are not.  Do you ever say "dog" when you mean "dot" instead?
> Do you ever say "dad" when you mean "mom" instead?  Internalize that
> "=" is "equals" (or "assigns" if you prefer) and "==" is "is equal to"
> then use those phrases in your head when you're thinking about which
> one you need in your code, and I'm pretty sure you'll stop making this
> mistake.  It may help that the phrase with twice as many syllables
> represents the operator that has twice as many characters.  Eventually
> it becomes second nature, like not calling Dad "Mom."

Rght, of course. Because prevention of bugs is just a matter of
wanting to. You remind me of a previous boss of mine, who didn't
understand why debugging ever had to happen - he thought that if the
programmers he employed would just take a bit more care, they could
write perfect code.

And commits like this never happen:
https://github.com/Rosuav/MustardMine/commit/ca0b1f47b2fe4438caea549410e1f1296798ba56

Let me break it to you gently: you are flat out wrong. Yep, that's as
gentle as I can make it.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
On Wed, May 09, 2018 at 03:57:35PM +1000, Chris Angelico wrote:
> On Wed, May 9, 2018 at 3:44 PM, Steven D'Aprano
> > If all programmers were as awesome as you and never made typos, the world
> > would be a better place. But we know from experience that even
> > experienced C programmers can make this mistake by accident.
> 
> Yes, and I'd go further: I *am* too stupid to get this right. 

No, you are not.  Do you ever say "dog" when you mean "dot" instead?
Do you ever say "dad" when you mean "mom" instead?  Internalize that
"=" is "equals" (or "assigns" if you prefer) and "==" is "is equal to"
then use those phrases in your head when you're thinking about which
one you need in your code, and I'm pretty sure you'll stop making this
mistake.  It may help that the phrase with twice as many syllables
represents the operator that has twice as many characters.  Eventually
it becomes second nature, like not calling Dad "Mom."


-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
On Wed, May 09, 2018 at 05:44:57AM +, Steven D'Aprano wrote:
> > On Tue, May 08, 2018 at 12:45:29AM +, Steven D'Aprano wrote:
> >> Currently, the real reason is that lambda expressions are limited to a
> >> single expression as the body of the function, and binding operations
> >> in Python are statements.
> > 
> > ...which begs the question, why shouldn't assignments be expressions, as
> > they are in many other languages?  TBH this is one of the few things
> > about Python that I dislike.
> 
> No, it raises the question :-) Begging the question means to assume the 
> answer to the same question you are asking.

In formal logic perhaps, but not in colloquial speech.  Search google
for "beg the question"--what it will give you is exactly how I used
it. [The question is begged for on account of being the obvious
question to ask...]

> As Chris already pointed out, there is a PEP in progress at the moment 
> aimed at allowing assignment expressions (PEP 572). It is very 
> controversial, but Guido appears to be in favour of it (as I am, although 
> not necessarily in its current form). 

Well, obviously I'm a fan of the idea...

> If all programmers were as awesome as you and never made typos, the world 
> would be a better place. 

HA!  I make plenty of mistakes, but I think it's fair to say that when
most reasonably competent programmers have a bit of experience under
their belt, some bug or other has bitten them enough as fledgelings
that they become paranoid about it and just never do it again.  It
does seem that for many of my contemporaries, this is one of those...

When I took C ages ago the text I used had a "pitfalls" section at the
end of every major section, and this was one of the items it
mentioned.  I do think having been exposed to those ideas so early
greatly benefieted me in this regard, and I've found it sorely lacking
in many programming texts I've read in the many years since.  Perhaps
an insufficient focus on programming pitfalls in modern programs is
the reason we're in this mess...

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
On Sun, May 13, 2018 at 01:01:04PM +1000, Chris Angelico wrote:
> That's fine. Your experience has been that it hasn't been a problem;
> other people's experience has been the opposite. I have never
> personally had to deal with bugs in C code where braces are omitted
> and multiple lines indented. Great! But that doesn't mean it's not a
> problem, or at least a risk.

Every line of code you write is a risk, regardless of whether it's in
a class of some language designer's hated constructs, or not... until
your code is thoroughly tested.  [And even then...]

> Guido has firmly stated that this is not going to happen in Python.
> The '=' operator is NOT going to become an expression. You may as well
> stop posting about it, because it's not going to change.

I'm well aware of this too, but I don't think that precludes reasoned
discussion of whether or not the construct is deserving of its most
hated status.  A large portion of what is discussed in this forum is
philosophical, and entirely unpractical.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
Drat, missed the main point I wanted to address in my last post:

On Tue, May 08, 2018 at 11:36:06PM -0600, Ian Kelly wrote:
> > This example also is a case FOR allowing assignments to be
> > expressions.  If Python allowed them, you could rewrite this as:
> >
> >while not (flag = we_are_done()):
> > ...
> > if error_occured():
> > break
> >notify_user()
> ># flag will be checked again later, perhaps for error reporting
> >
> > This COMPLETELY PREVENTS the spelling bug in the code above, since the
> > assignment only happens in one place; and as a bonus it's less code.
> 
> Or just use an IDE with variable name autocompletion.

Every time, without fail?  Probably not going to happen, no matter who
you are.  FWIW I *do* use an editor with autocompletion--I never use
it because in the common case it's faster for me to just type whatever
I'm typing.  But this solution--dictating *how* people work, to
overcome a limitation of the language--is a horrible one.

Besides, your entire response missed the point completely..  All of
the examples you "fixed" were just trivial academic examples designed
to illustrate the problem.  In real code, particularly in a complex
project, the spelling bug is easier to cause and harder to find, and
just rewriting your while loop probably won't do.

My ultimate point was no matter what constructions you allow or don't
allow, coders are human and they're gonna screw it up, and some of
those mistakes will get past all of your well-intentioned bug traps.
Protecting coders from themselves is not a good reason to exclude
useful language constructs.  It's a reason to have good coders, good
process, and good testing.

And if your code reviews won't catch well-known programming pitfalls,
what good are they?

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Chris Angelico
On Sun, May 13, 2018 at 12:42 PM, Python  wrote:
> On Wed, May 09, 2018 at 12:46:07PM -0400, Dennis Lee Bieber wrote:
>> On Tue, 8 May 2018 22:48:52 -0500, Python 
>> >if spam == arg:
>>
>>   Mis-typing that as
>>
>>   if spam = arg:
>>
>> IS the problem -- you've just changed the value bound to spam, and will
>> then branch based upon the new value and not a comparison of values.
>
> Yes, I'm well aware.  While I may have been momentarily confused about
> the side effects question, if you read my post I was clearly not
> confused about this.  Nor do I think anyone else who pposted in the
> thread needed it explained.
>
> Responding to this further would essentially just require me to
> reiterate what I already wrote--I won't do that.  I'll simply maintain
> that in my rather lenghty experience, this mistake has actually been
> rather rare and has to my knowledge *never* caused a support issue
> requiring a bug fix to production code in projects I've been
> associated with.  It's a useful construction whose detriment has, IMO,
> been completely overblown.
>

That's fine. Your experience has been that it hasn't been a problem;
other people's experience has been the opposite. I have never
personally had to deal with bugs in C code where braces are omitted
and multiple lines indented. Great! But that doesn't mean it's not a
problem, or at least a risk.

Guido has firmly stated that this is not going to happen in Python.
The '=' operator is NOT going to become an expression. You may as well
stop posting about it, because it's not going to change.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
On Tue, May 08, 2018 at 11:36:06PM -0600, Ian Kelly wrote:
> On Tue, May 8, 2018 at 9:48 PM, Python  wrote:
> > I'll give you an example that is both a case where Python's design
> > choices make creating a bug easier, AND a case where allowing
> > assignments to be expressions would save you.
> >
> > flag = we_are_done()
> > while not flag:
> > # do some stuff
> > ...
> > if error_occured():
> > break
> > falg = we_are_done()
> > notify_user()
> ># flag will be checked again later, perhaps for error reporting
> 
> while True:
> if we_are_done():
> break
> # do some stuff
> ...
> if error_occurred():
> break
> notify_user()
> 
> Fixed, using idiomatic Python and without needing to use assignment in
> an expression.

Two points:

1. I think the ensuing discussion clearly enough demonstrates that
   this isn't necessarily considered the most idiomatic Python.  I
   would go so far as to say it demonstrates that there's no such
   thing in actuality, in that different "experts" will have different
   opinions about what is or is not Pythonic.

2. Even if there was a definitive standard as to what is or is not
   idiomatic Python, no one is required to write it or care about it,
   and I would estimate that the vast majority of people who write
   Python don't.  People tend to use constructions they're familiar
   with and/or comfortable with, until they discover for themselves a
   reason not to.

On Thu, May 10, 2018 at 08:38:39PM -0600, Ian Kelly wrote:
> In what way does "while True" in the general case pretend to be an
> infinite loop? The break / return is right there for anyone to see.

It doesn't pretend at all, it simply is.  Its loop condition is a
constant which will require the loop to continue indefinitely--in the
general case--without intervention from some other control feature, in
the specific.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-12 Thread Python
On Wed, May 09, 2018 at 03:09:18PM +1000, Chris Angelico wrote:
> On Wed, May 9, 2018 at 1:48 PM, Python  wrote:
[much snippage...]
> > flag = (spam == arg)
>
> That's not "side effects only". 

Yeah, I'll chalk that up to posting too late in the evening after
working too long a day...  

On Wed, May 09, 2018 at 12:46:07PM -0400, Dennis Lee Bieber wrote:
> On Tue, 8 May 2018 22:48:52 -0500, Python 
> >if spam == arg:
> 
>   Mis-typing that as
> 
>   if spam = arg:
> 
> IS the problem -- you've just changed the value bound to spam, and will
> then branch based upon the new value and not a comparison of values.

Yes, I'm well aware.  While I may have been momentarily confused about
the side effects question, if you read my post I was clearly not
confused about this.  Nor do I think anyone else who pposted in the
thread needed it explained.

Responding to this further would essentially just require me to
reiterate what I already wrote--I won't do that.  I'll simply maintain
that in my rather lenghty experience, this mistake has actually been
rather rare and has to my knowledge *never* caused a support issue
requiring a bug fix to production code in projects I've been
associated with.  It's a useful construction whose detriment has, IMO,
been completely overblown.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Sat, May 12, 2018 at 1:03 AM, Ian Kelly  wrote:
> On Fri, May 11, 2018 at 7:40 AM, Chris Angelico  wrote:
>> So, yes, your function's name is outright lying. But there's nothing
>> about it that is *pretending* to be a normal function. It IS a normal
>> function.
>
> The detail of whether it's a generator function affects the function's
> execution and may be relevant to the caller. Here are two hypothetical
> functions. They do some processing with side-effects over a bunch of
> items and return the processed items. However, one is a generator
> function and the other just returns a list.
>
> def process_items(items):
> ...
>
> def handle_items(items):
> ...
>
> Now, we can agree that these ought to be better documented, but say I
> want to call one of these for the side effects and ignore the return
> value. Just from reading the first line of the function, do I need to
> iterate over the result, or not?

This is no different from anything else you might need to know about
the functions. It might be essential to know that "handle_items"
actually doesn't return anything at all, and signals success or
failure by what exception it raises. Or that "process_items", due to
internal structure and implementation, absolutely must be called from
the main thread, otherwise you risk OS-level signals corrupting your
data. The solution is simple: read the docstring.

> Scenario 2. I have two "while True" loops. One is potentially infinite
> and the other is not.
>
> while True:
> ...
>
> while True:
> ...
>
> Obviously, it's important to know whether a loop might be infinite
> before I run the code that includes it. Just from reading the first
> line of the loop, how do I know? You can argue that they should use
> strings instead to describe what they do, which would help, although I
> think that's potentially confusing.
>
> I don't see these two situations as being fundamentally different. Do you?

Not hugely, no. But it's worth noting that we have the option to
annotate a function's return value. So if you need structured
information about what this function or that function returns, you can
provide that. It's not easy to make program-readable information about
a 'while' loop (since it's not a first-class object), but you can
still have structured information about whether the loop is infinite
or not, by putting it into the loop header.

But I still think you're overblowing the case when you claim that a
generator function isn't a function. That'd be on par with claiming
that a while loop isn't a loop.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Fri, May 11, 2018 at 7:40 AM, Chris Angelico  wrote:
> So, yes, your function's name is outright lying. But there's nothing
> about it that is *pretending* to be a normal function. It IS a normal
> function.

The detail of whether it's a generator function affects the function's
execution and may be relevant to the caller. Here are two hypothetical
functions. They do some processing with side-effects over a bunch of
items and return the processed items. However, one is a generator
function and the other just returns a list.

def process_items(items):
...

def handle_items(items):
...

Now, we can agree that these ought to be better documented, but say I
want to call one of these for the side effects and ignore the return
value. Just from reading the first line of the function, do I need to
iterate over the result, or not?

Scenario 2. I have two "while True" loops. One is potentially infinite
and the other is not.

while True:
...

while True:
...

Obviously, it's important to know whether a loop might be infinite
before I run the code that includes it. Just from reading the first
line of the loop, how do I know? You can argue that they should use
strings instead to describe what they do, which would help, although I
think that's potentially confusing.

I don't see these two situations as being fundamentally different. Do you?
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Fri, May 11, 2018 at 11:31 PM, Ian Kelly  wrote:
> On Fri, May 11, 2018 at 1:01 AM, Chris Angelico  wrote:
>> On Fri, May 11, 2018 at 12:38 PM, Ian Kelly  wrote:
>>> Would you also contend that generator functions are wrong because they
>>> pretend to be normal functions?
>>>
>>> def totally_not_a_generator(n):
>>> while True:
>>> if n % 2 == 0:
>>> n //= 2
>>> else:
>>> n = n * 3 + 1
>>> stealthily = n
>>> yield stealthily
>>> if n == 1:
>>> return n
>>>
>>> py> print(totally_not_a_generator(42))  # Lies!
>>> 
>>
>> Let's see. It's created with 'def'. It can be called by putting
>> parentheses after its name. Inside the parentheses, you can give it
>> parameters. When called, it returns a value. Hmm. Sure looks like a
>> function to me.
>>
>> Tell me, which of these are functions and which are not?
>>
>> def tnag5():
>> return totally_not_a_generator(5)
>>
>> def tnag(n):
>> return iter(totally_not_a_generator(n))
>>
>> def ILY():
>> return iter([1, 2, 3]) # your heart starts beating
>>
>> async def what_about_me():
>> await spam()
>> return 42
>>
>> def digits_to_number(text):
>> return int(text, 10)
>>
>> class run_command:
>> """Compatibility shim for older API"""
>> def __init__(self, *args):
>> proc = subprocess.run(*args, stdout=subprocess.PIPE)
>> self.rc = proc.returncode
>> self.output = proc.output
>>
>> def run_command(*args):
>> proc = subprocess.run(*args, stdout=subprocess.PIPE)
>> return {"rc": proc.returncode, "output": proc.output}
>>
>>
>> The only one that inspect.isfunction() returns False for is the class,
>> and even that is a very function-like class. Every one of these is
>> callable and will return a useful value. Their headers announce one of
>> three things:
>>
>> 1) "I am a function" ==> def name(...):
>> 2) "I am a factory for objects of my own type" ==> class name:
>> 3) "I am a coroutine function" ==> async def name(...):
>>
>> Not one of them is lying. And nor is your totally_not_a_generator. As
>> Steven said, it's a function, and it returns a value.
>
> It's a generator that says it's not a generator. How is that not lying?
>
> Anyway, as far as I can see you just repeated the same argument that
> Steven wrote. I know all this, of course, and I think you missed the
> point. Please read my response to Steven.

You said:

>> Would you also contend that generator functions are wrong because they
>> pretend to be normal functions?

So, yes, your function's name is outright lying. But there's nothing
about it that is *pretending* to be a normal function. It IS a normal
function.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Fri, May 11, 2018 at 11:28 PM, Ian Kelly  wrote:
> You can get rid of the while loop:
>
> for x in iter(get_item, None):
> process(x)
>
> The reason I suggested the function I did is because the x in that
> case can't reasonably be turned into an iterator because the logic
> depends on the loop body. You can't encapsulate the iteration logic
> without having side-effects in the iteration or duplicating code.

That's actually equivalent to:

while (x := get_item()) != None:
process(x)

That's not often going to be what you want. If the function is
guaranteed to return None, you should be using "is not None", and if
it's simply returning something falsey, you should be checking
truthiness. Once again, this is shoe-horning the available mechanics
into tasks that aren't quite what they're designed for; they're "close
enough" for a lot of cases, but not really correct.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Fri, May 11, 2018 at 1:01 AM, Chris Angelico  wrote:
> On Fri, May 11, 2018 at 12:38 PM, Ian Kelly  wrote:
>> Would you also contend that generator functions are wrong because they
>> pretend to be normal functions?
>>
>> def totally_not_a_generator(n):
>> while True:
>> if n % 2 == 0:
>> n //= 2
>> else:
>> n = n * 3 + 1
>> stealthily = n
>> yield stealthily
>> if n == 1:
>> return n
>>
>> py> print(totally_not_a_generator(42))  # Lies!
>> 
>
> Let's see. It's created with 'def'. It can be called by putting
> parentheses after its name. Inside the parentheses, you can give it
> parameters. When called, it returns a value. Hmm. Sure looks like a
> function to me.
>
> Tell me, which of these are functions and which are not?
>
> def tnag5():
> return totally_not_a_generator(5)
>
> def tnag(n):
> return iter(totally_not_a_generator(n))
>
> def ILY():
> return iter([1, 2, 3]) # your heart starts beating
>
> async def what_about_me():
> await spam()
> return 42
>
> def digits_to_number(text):
> return int(text, 10)
>
> class run_command:
> """Compatibility shim for older API"""
> def __init__(self, *args):
> proc = subprocess.run(*args, stdout=subprocess.PIPE)
> self.rc = proc.returncode
> self.output = proc.output
>
> def run_command(*args):
> proc = subprocess.run(*args, stdout=subprocess.PIPE)
> return {"rc": proc.returncode, "output": proc.output}
>
>
> The only one that inspect.isfunction() returns False for is the class,
> and even that is a very function-like class. Every one of these is
> callable and will return a useful value. Their headers announce one of
> three things:
>
> 1) "I am a function" ==> def name(...):
> 2) "I am a factory for objects of my own type" ==> class name:
> 3) "I am a coroutine function" ==> async def name(...):
>
> Not one of them is lying. And nor is your totally_not_a_generator. As
> Steven said, it's a function, and it returns a value.

It's a generator that says it's not a generator. How is that not lying?

Anyway, as far as I can see you just repeated the same argument that
Steven wrote. I know all this, of course, and I think you missed the
point. Please read my response to Steven.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Fri, May 11, 2018 at 1:06 AM, Chris Angelico  wrote:
> On Fri, May 11, 2018 at 4:54 PM, Ian Kelly  wrote:
>> On Thu, May 10, 2018 at 11:45 PM, Steven D'Aprano
>>  wrote:
>>> To be honest, I'm having trouble thinking of a good use-case for "while
>>> True", now that we have infinite iterators. Most cases of
>>>
>>> while True:
>>> x = get_item()
>>> if not x: break
>>> process(x)
>>>
>>> are better written as:
>>>
>>> for x in iterator:
>>> process(x)
>>
>> x = get_item()
>> while True:
>> x = process(x)
>
> More likely:
>
> x = get_item()
> while x:
> process(x)
> x = get_item()
>
> which (a) repeats the call to get_item, (b) doesn't support the
> 'continue' statement, and (c) hides crucial loop iteration information
> at the BOTTOM of the loop.
>
> But to make this iterator, you need to separate the while loop's
> header from its body. Compare:
>
> while x := get_item():
> process(x)
>
>
> def get_items():
> while True:
> x = get_item()
> if not x: return
> yield x
>
> for x in get_items():
> process(x)
>
> It hasn't actually gotten rid of the fib of the infinite loop; all
> it's done is wrap it up in a function. Yes, that can be of value; but
> adding another level of indirection doesn't solve a problem, it just
> moves it around.

You can get rid of the while loop:

for x in iter(get_item, None):
process(x)

The reason I suggested the function I did is because the x in that
case can't reasonably be turned into an iterator because the logic
depends on the loop body. You can't encapsulate the iteration logic
without having side-effects in the iteration or duplicating code.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Marko Rauhamaa
Chris Angelico :

> On Fri, May 11, 2018 at 7:10 PM, Gregory Ewing
>  wrote:
>> I suggest adding a new builtin constant:
>>
>>YouFeelLikeIt = True
>>
>> Then all pseudo-infinite loops can be written
>>
>>while YouFeelLikeIt:
>>   ...
>>
>
> Personally, I prefer to use string literals.
>
> while "you feel like it":
> ...

I still think my use of the Ellipsis speaks more to the maintainer of
the code:

   while ...:
   pass


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Fri, May 11, 2018 at 7:10 PM, Gregory Ewing
 wrote:
> I suggest adding a new builtin constant:
>
>YouFeelLikeIt = True
>
> Then all pseudo-infinite loops can be written
>
>while YouFeelLikeIt:
>   ...
>

Personally, I prefer to use string literals.

while "you feel like it":
...

Which, in a non-joking context, tends to look like this:

while "moar data":
data = get_data()
process_data(data)

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Gregory Ewing

I suggest adding a new builtin constant:

   YouFeelLikeIt = True

Then all pseudo-infinite loops can be written

   while YouFeelLikeIt:
  ...

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Gregory Ewing

Marko Rauhamaa wrote:

I was mildly amused when Python happily executed such code. "..." is a
valid expression and thus, a valid statement.


Fortunately, "?" still works for this!

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Fri, May 11, 2018 at 12:03 AM, Steven D'Aprano
 wrote:
> On Thu, 10 May 2018 20:38:39 -0600, Ian Kelly wrote:
>
>> Would you also contend that generator functions are wrong because they
>> pretend to be normal functions?
>
> You're going to need to be more specific. In what way are they not normal
> functions? You call them like normal functions, providing arguments like
> normal functions, and receiving a result just like normal functions.

The way that they execute is not like a normal function. If you call
one, having read the code but having failed to notice the 'yield', you
will be confused by the result.

Likewise, if you run a while True loop (or *any* loop, really), having
read the code but failed to notice the 'break', you will be confused
by the result.

The point being that you cannot necessarily infer what a while loop
will do just by reading the loop condition, any more than you can know
what a function call will return if all you've read are the name and
the signature.

> If you call a function like iter(), you also get back an iterator, just
> as you do when you call a generator. Is iter() not a normal function?

Presumably somebody experienced with Python will already know what
iter does without needing to read the code.

>> def totally_not_a_generator(n):
>> while True:
>> if n % 2 == 0:
>> n //= 2
>> else:
>> n = n * 3 + 1
>> stealthily = n
>> yield stealthily
>> if n == 1:
>> return n
>
> I must admit, I'm a little perplexed. In what way is this totally not a
> generator? (To be precise, a generator function.) The inspect module
> thinks it is (and so do I):

The example was tongue-in-cheek. As suggested by the comment in the
part that you cut out where I called it, the code is lying.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Fri, May 11, 2018 at 4:54 PM, Ian Kelly  wrote:
> On Thu, May 10, 2018 at 11:45 PM, Steven D'Aprano
>  wrote:
>> To be honest, I'm having trouble thinking of a good use-case for "while
>> True", now that we have infinite iterators. Most cases of
>>
>> while True:
>> x = get_item()
>> if not x: break
>> process(x)
>>
>> are better written as:
>>
>> for x in iterator:
>> process(x)
>
> x = get_item()
> while True:
> x = process(x)

More likely:

x = get_item()
while x:
process(x)
x = get_item()

which (a) repeats the call to get_item, (b) doesn't support the
'continue' statement, and (c) hides crucial loop iteration information
at the BOTTOM of the loop.

But to make this iterator, you need to separate the while loop's
header from its body. Compare:

while x := get_item():
process(x)


def get_items():
while True:
x = get_item()
if not x: return
yield x

for x in get_items():
process(x)

It hasn't actually gotten rid of the fib of the infinite loop; all
it's done is wrap it up in a function. Yes, that can be of value; but
adding another level of indirection doesn't solve a problem, it just
moves it around.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Chris Angelico
On Fri, May 11, 2018 at 12:38 PM, Ian Kelly  wrote:
> Would you also contend that generator functions are wrong because they
> pretend to be normal functions?
>
> def totally_not_a_generator(n):
> while True:
> if n % 2 == 0:
> n //= 2
> else:
> n = n * 3 + 1
> stealthily = n
> yield stealthily
> if n == 1:
> return n
>
> py> print(totally_not_a_generator(42))  # Lies!
> 

Let's see. It's created with 'def'. It can be called by putting
parentheses after its name. Inside the parentheses, you can give it
parameters. When called, it returns a value. Hmm. Sure looks like a
function to me.

Tell me, which of these are functions and which are not?

def tnag5():
return totally_not_a_generator(5)

def tnag(n):
return iter(totally_not_a_generator(n))

def ILY():
return iter([1, 2, 3]) # your heart starts beating

async def what_about_me():
await spam()
return 42

def digits_to_number(text):
return int(text, 10)

class run_command:
"""Compatibility shim for older API"""
def __init__(self, *args):
proc = subprocess.run(*args, stdout=subprocess.PIPE)
self.rc = proc.returncode
self.output = proc.output

def run_command(*args):
proc = subprocess.run(*args, stdout=subprocess.PIPE)
return {"rc": proc.returncode, "output": proc.output}


The only one that inspect.isfunction() returns False for is the class,
and even that is a very function-like class. Every one of these is
callable and will return a useful value. Their headers announce one of
three things:

1) "I am a function" ==> def name(...):
2) "I am a factory for objects of my own type" ==> class name:
3) "I am a coroutine function" ==> async def name(...):

Not one of them is lying. And nor is your totally_not_a_generator. As
Steven said, it's a function, and it returns a value. That's not
materially different from ILY() in my example - it returns something
which you can iterate over.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Thu, May 10, 2018 at 11:45 PM, Steven D'Aprano
 wrote:
> To be honest, I'm having trouble thinking of a good use-case for "while
> True", now that we have infinite iterators. Most cases of
>
> while True:
> x = get_item()
> if not x: break
> process(x)
>
> are better written as:
>
> for x in iterator:
> process(x)

x = get_item()
while True:
x = process(x)
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Ian Kelly
On Thu, May 10, 2018 at 11:17 PM, Steven D'Aprano
 wrote:
> To answer your question from a later post:
>
> In what way does "while True" in the general case pretend
> to be an infinite loop?
>
> It doesn't *pretend* to be an infinite loop. It *is* an infinite loop
> which breaks out early.
>
> I realise that all infinite loops end up breaking out early, even if it's
> only when you power-cycle the device. But code ought to match intent, and
> "while condition which can never be false" shouts from the mountain tops
> that it is an infinite loop. The simpler the condition, the more loudly
> it shouts, and you can't get simpler than True.
>
> (The one thing that beats "while True" as an indicator of an infinite
> loop is the old Hypertalk syntax "repeat forever".)

How about the asyncio event loop's run_forever and run_until_complete
methods? run_forever also implies an infinite loop, except that you
can stop the event loop at any time. The other choice,
run_until_complete, requires that you already know when you want to
stop when you call it. Another way of looking at it, run_forever is
like a while loop and run_until_complete is like a for loop.

So if you know you want to stop the loop at some point, but you don't
know when, what do you do to express your intent?

> and if we came across it in real life, we'd surely question the sanity of
> the developer who wrote it. Why should while loops be any different?
>
> while True:
> if not condition: break  # equivalent to GOTO 99
> block
> LABEL 99
>
> I understand that *today*, using existing Python syntax, there is
> sometimes no avoiding that (except, possibly, with something worse). I
> get that. But if we had the choice to move the condition into the while
> condition, we ought to take it.

This is a straw man. As I already replied to Chris, this is not the
type of while True I've been arguing for. Obviously in this case the
condition should be moved into the while statement.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-11 Thread Steven D'Aprano
On Thu, 10 May 2018 20:38:39 -0600, Ian Kelly wrote:

> Would you also contend that generator functions are wrong because they
> pretend to be normal functions?

You're going to need to be more specific. In what way are they not normal 
functions? You call them like normal functions, providing arguments like 
normal functions, and receiving a result just like normal functions.

If you call a function like iter(), you also get back an iterator, just 
as you do when you call a generator. Is iter() not a normal function?

We also call classes, and callable instances, as if they were normal 
functions. Is that also a problem?

I guess the answer depends on what we mean by "function":

- an instance of FunctionType

- a thing we call to get back a result

or possibly both, as context requires.


> def totally_not_a_generator(n):
> while True:
> if n % 2 == 0:
> n //= 2
> else:
> n = n * 3 + 1
> stealthily = n
> yield stealthily
> if n == 1:
> return n

I must admit, I'm a little perplexed. In what way is this totally not a 
generator? (To be precise, a generator function.) The inspect module 
thinks it is (and so do I): 

py> inspect.isgeneratorfunction(totally_not_a_generator)
True

as well as a function:

py> inspect.isfunction(totally_not_a_generator)
True


It's not a *generator object*, but it returns one:


py> inspect.isgenerator(totally_not_a_generator)
False
py> inspect.isgenerator(totally_not_a_generator(99))
True


-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Steven D'Aprano
On Fri, 11 May 2018 05:17:59 +, Steven D'Aprano wrote:

> On Fri, 11 May 2018 03:29:57 +0300, Marko Rauhamaa wrote:
[...]
> To answer your question from a later post:
> 
> In what way does "while True" in the general case pretend to be an
> infinite loop?

Oops, sorry, that was Ian Kelly who asked that, not Marko.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Steven D'Aprano
On Fri, 11 May 2018 01:51:47 +0300, Marko Rauhamaa wrote:

> Paul Rubin :
> 
>> Marko Rauhamaa  writes:
>>> It turns out "while True" is the most natural choice in about half of
>>> the while loops.
>>
>> Maybe the rest would be "repeat until" if Python had that?
> 
> No. "Repeat until" is a relatively infrequent need.

And again, YMMV. In my experience, most "while True" loops would be 
better off written as a "repeat... until True" loop. But since Python 
doesn't have syntax for such repeat until loops, our work-around is to 
use a while True and break out of it at the end of the loop.

To be honest, I'm having trouble thinking of a good use-case for "while 
True", now that we have infinite iterators. Most cases of

while True:
x = get_item()
if not x: break
process(x)

are better written as:

for x in iterator:
process(x)



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Steven D'Aprano
On Fri, 11 May 2018 03:29:57 +0300, Marko Rauhamaa wrote:

>> Now do you understand what I mean about putting the condition into the
>> loop header?
> 
> Thanks, but no thanks. The "while True" idiom beats that one hands down.

Why do you think it is better to lie to the reader and tell them they are 
entering an infinite loop, only to later on say "Ha ha, fooled you!"?

It doesn't matter whether it is one line later, or sixteen pages later. 
The initial "while True" suggests an infinite loop, because the loop 
condition is *always* True, so the loop never ends.

To answer your question from a later post:

In what way does "while True" in the general case pretend
to be an infinite loop?

It doesn't *pretend* to be an infinite loop. It *is* an infinite loop 
which breaks out early.

I realise that all infinite loops end up breaking out early, even if it's 
only when you power-cycle the device. But code ought to match intent, and 
"while condition which can never be false" shouts from the mountain tops 
that it is an infinite loop. The simpler the condition, the more loudly 
it shouts, and you can't get simpler than True.

(The one thing that beats "while True" as an indicator of an infinite 
loop is the old Hypertalk syntax "repeat forever".)

If we want to communicate the intent of our code, the while-condition 
ought to be in the loop header *if possible*. (I appreciate it isn't 
always possible.)

We wouldn't write this:

# let's pretend we have GOTO
if True:
if not condition: GOTO 99
block
LABEL 99


and if we came across it in real life, we'd surely question the sanity of 
the developer who wrote it. Why should while loops be any different?

while True:
if not condition: break  # equivalent to GOTO 99
block
LABEL 99

I understand that *today*, using existing Python syntax, there is 
sometimes no avoiding that (except, possibly, with something worse). I 
get that. But if we had the choice to move the condition into the while 
condition, we ought to take it.


> As for the "is not None" test, I generally want to make it explicit
> because
> 
>  1. that's what I mean and
> 
>  2. there's a chance in some context of confusing None with other falsey
> values.

Indeed #2 is correct, and of course *in general* we ought to be explicit 
when testing for None. But in the case of regexes, I doubt that testing 
for None is *actually* what you mean. It's merely what you *think* you 
mean *wink*

To be precise, the rule is that re.match() returns a true object (a 
MatchObject) if the search succeeded, and a false object (documented as 
None) if it fails. But we surely don't care that the failure case is 
*specifically* None. It should make no difference at all if re.match() 
returned False instead, or a falsey MatchObject with all fields left 
empty, since we never use it.

So we ought not care that it is specifically None.

Testing for None particularly makes sense if you need a sentinel and:

- you don't distinguish between truthy and falsey values at all;

- or you want to distinguish between truthy values, falsey values,
  and leave None to stand in for things which are neither ("maybe"?).

The re.match case doesn't meet either of those conditions.

Of course, none of this is to say that testing for None is "wrong". 
re.match is documented as returning None, and a backwards-incompatible 
change is exceedingly unlikely. So you're safe there. It's just 
unnecessary.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Steven D'Aprano
On Thu, 10 May 2018 22:59:03 +0300, Marko Rauhamaa wrote:

> It turns out "while True" is the most natural choice in
> about half of the while loops.


YMMV.

In my case, it is more like about one in ten.




-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Ian Kelly
On Thu, May 10, 2018 at 7:10 PM, Chris Angelico  wrote:
> On Fri, May 11, 2018 at 10:29 AM, Marko Rauhamaa  wrote:
>> Chris Angelico :
>>
>>> But for the loop itself, you absolutely CAN write this more logically.
>>> I'll take your second version as a template:
>>>
>>> def split_cmd(self, cmd):
>>> args = []
>>> while (match := self.TERM_PTN.match(cmd)) is not None:
>>> args.append(match.group('term'))
>>> if not match.group('sep'):
>>> verb = args.pop(0).upper()
>>> return verb, args
>>> cmd = cmd[match.end(0):]
>>> return None, None
>>>
>>> And, if this is actually a regex, "is not None" is unnecessary:
>>>
>>> while match := self.TERM_PTN.match(cmd):
>>>
>>> Now do you understand what I mean about putting the condition into the
>>> loop header?
>>
>> Thanks, but no thanks. The "while True" idiom beats that one hands down.
>
> Because you're used to it? Or because it's somehow more logical to
> pretend that this is an infinite loop? Explain in more detail.

In what way does "while True" in the general case pretend to be an
infinite loop? The break / return is right there for anyone to see.

Would you also contend that generator functions are wrong because they
pretend to be normal functions?

def totally_not_a_generator(n):
while True:
if n % 2 == 0:
n //= 2
else:
n = n * 3 + 1
stealthily = n
yield stealthily
if n == 1:
return n

py> print(totally_not_a_generator(42))  # Lies!

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Ian Kelly
On Tue, May 8, 2018 at 11:50 PM, Chris Angelico  wrote:
> On Wed, May 9, 2018 at 3:36 PM, Ian Kelly  wrote:
>>
>> while True:
>> if we_are_done():
>> break
>> # do some stuff
>> ...
>> if error_occurred():
>> break
>> notify_user()
>>
>>
>> Fixed, using idiomatic Python and without needing to use assignment in
>> an expression.
>
> Why is it that "while True" is idiomatic Python for a non-infinite
> loop? Is it merely because Python currently has no other way to spell
> certain loops? Surely it would be more idiomatic to encode the loop's
> termination condition in the header, if it were possible.

In the case of the code above you're correct; the condition could be
moved directly into the while. The loop that I adapted first assigned
we_are_done() to flag and then asserted that flag would be checked
again later. I neglected to maintain this part when I rewrote it.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Chris Angelico
On Fri, May 11, 2018 at 10:29 AM, Marko Rauhamaa  wrote:
> Chris Angelico :
>
>> But for the loop itself, you absolutely CAN write this more logically.
>> I'll take your second version as a template:
>>
>> def split_cmd(self, cmd):
>> args = []
>> while (match := self.TERM_PTN.match(cmd)) is not None:
>> args.append(match.group('term'))
>> if not match.group('sep'):
>> verb = args.pop(0).upper()
>> return verb, args
>> cmd = cmd[match.end(0):]
>> return None, None
>>
>> And, if this is actually a regex, "is not None" is unnecessary:
>>
>> while match := self.TERM_PTN.match(cmd):
>>
>> Now do you understand what I mean about putting the condition into the
>> loop header?
>
> Thanks, but no thanks. The "while True" idiom beats that one hands down.

Because you're used to it? Or because it's somehow more logical to
pretend that this is an infinite loop? Explain in more detail.

> As for the "is not None" test, I generally want to make it explicit
> because
>
>  1. that's what I mean and
>
>  2. there's a chance in some context of confusing None with other falsey
> values.
>

With the standard library re module, there is no such chance. So it's
pointlessly explicit about something that won't ever happen.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
Chris Angelico :

> But for the loop itself, you absolutely CAN write this more logically.
> I'll take your second version as a template:
>
> def split_cmd(self, cmd):
> args = []
> while (match := self.TERM_PTN.match(cmd)) is not None:
> args.append(match.group('term'))
> if not match.group('sep'):
> verb = args.pop(0).upper()
> return verb, args
> cmd = cmd[match.end(0):]
> return None, None
>
> And, if this is actually a regex, "is not None" is unnecessary:
>
> while match := self.TERM_PTN.match(cmd):
>
> Now do you understand what I mean about putting the condition into the
> loop header?

Thanks, but no thanks. The "while True" idiom beats that one hands down.

As for the "is not None" test, I generally want to make it explicit
because

 1. that's what I mean and

 2. there's a chance in some context of confusing None with other falsey
values.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Chris Angelico
On Fri, May 11, 2018 at 8:49 AM, Marko Rauhamaa  wrote:
> def split_cmd(self, cmd):
> args = []
> while True:
> match = self.TERM_PTN.match(cmd)
> if match is None:
> return None, None
> args.append(match.group('term'))
> if not match.group('sep'):
> break
> cmd = cmd[match.end(0):]
> verb = args.pop(0).upper()
> return verb, args
>
> You *could* get rid of True. For example:

Yes, you could. For a start, you'd want to add a docstring so someone
else can figure out what on earth is going on here. For instance, I
don't understand why, even after iterating several times, a regex
match failure instantly results in you returning (None, None); is that
an error condition? If so, why is it not raising an exception? What
kind of regex is this (at least, it looks like you're doing regex
work), and can you use re.split() instead of all this? Why are you
uppercasing the verb? Why an ALL_CAPS name (usually a constant) being
referenced from an object (self)? So much of this doesn't look even
slightly Pythonic.

But for the loop itself, you absolutely CAN write this more logically.
I'll take your second version as a template:

def split_cmd(self, cmd):
args = []
while (match := self.TERM_PTN.match(cmd)) is not None:
args.append(match.group('term'))
if not match.group('sep'):
verb = args.pop(0).upper()
return verb, args
cmd = cmd[match.end(0):]
return None, None

And, if this is actually a regex, "is not None" is unnecessary:

while match := self.TERM_PTN.match(cmd):

Now do you understand what I mean about putting the condition into the
loop header?

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
Paul Rubin :

> Marko Rauhamaa  writes:
>> It turns out "while True" is the most natural choice in about half of
>> the while loops.
>
> Maybe the rest would be "repeat until" if Python had that?

No. "Repeat until" is a relatively infrequent need.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
Chris Angelico :
> On Fri, May 11, 2018 at 5:59 AM, Marko Rauhamaa  wrote:
>> Joking aside, to answer Chris's question, of course you can use a
>> real condition with "while". However, you shouldn't force it or try
>> to avoid "while True". It turns out "while True" is the most natural
>> choice in about half of the while loops.
>
> So if I understand you correctly, you're saying that a real condition
> is better, but "while True" is the best option half the time. In other
> words, "while True" is the ONLY option half the time, since any other
> option would be better.

A real example:

def split_cmd(self, cmd):
args = []
while True:
match = self.TERM_PTN.match(cmd)
if match is None:
return None, None
args.append(match.group('term'))
if not match.group('sep'):
break
cmd = cmd[match.end(0):]
verb = args.pop(0).upper()
return verb, args

You *could* get rid of True. For example:

def split_cmd(self, cmd):
args = []
match = self.TERM_PTN.match(cmd)
while match is not None:
args.append(match.group('term'))
if not match.group('sep'):
verb = args.pop(0).upper()
return verb, args
cmd = cmd[match.end(0):]
match = self.TERM_PTN.match(cmd)
return None, None

However, that would be a slight stylistic degradation because

 1. the redundant matching statement is redundant and

 2. an abnormal return is at the bottom of the function.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Peter Pearson
On Wed, 09 May 2018 12:51:15 -0700, Paul Rubin wrote:
> Dennis Lee Bieber  writes:
>>  Yes, code reviews may catch such errors... and later, when the
>> summary of errors is analyzed for suggestions on how to reduce them --
>> the odds are good that "assignment expressions" will be banned in the
>> style documents for that language at the company.
>
> I don't think I've worked on any C programs with that style restriction
> and I can't think of any times when I found that type of bug in deployed
> code.  I've made the error once or twice while coding, but caught it
> right away during inspection or testing.  Banning it seems
> counterproductive.  I could imagine having it flagged by a compiler
> warning that can be locally disabled by a pragma.  

Interestingly, the problem is broader than inadvertently making the
mistake yourself; it includes catching deliberate misdirection by
others.  In the famous "Linux Backdoor Attempt of 2003"
(https://freedom-to-tinker.com/2013/10/09/the-linux-backdoor-attempt-of-2003/),
somebody who I think never got caught introduced these lines
into the code for the wait4 function:

if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
retval = -EINVAL;

Setting the user ID to zero confers root privileges.

- Peter
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Chris Angelico
On Fri, May 11, 2018 at 5:59 AM, Marko Rauhamaa  wrote:
> Mikhail V :
>
>> On Wed, May 9, 2018 at 8:50 AM, Chris Angelico  wrote:
>>> On Wed, May 9, 2018 at 3:36 PM, Ian Kelly  wrote:
 while True:
>>>
>>> Why is it that "while True" is idiomatic Python for a non-infinite
>>> loop? Is it merely because Python currently has no other way to spell
>>> certain loops? Surely it would be more idiomatic to encode the loop's
>>> termination condition in the header, if it were possible.
>>
>> Don't know about 'idiomatic', but the above spelling is exactly what i
>> tend to use lately for almost all loops. It noticeably reduces
>> cognitive load. Though lately more often i prefer "while 1:" so it
>> makes the nodes more lightweight and distinct from the rest lines. And
>> not even official declaration of "idiomatic" as something else will
>> make me switch back.
>
> How about:
>
>while ...:
>do_stuff()
>if done:
>break
>do_more_stuff()
>
> where ... is the Ellipsis.
>
> Joking aside, to answer Chris's question, of course you can use a real
> condition with "while". However, you shouldn't force it or try to avoid
> "while True". It turns out "while True" is the most natural choice in
> about half of the while loops.

So if I understand you correctly, you're saying that a real condition
is better, but "while True" is the best option half the time. In other
words, "while True" is the ONLY option half the time, since any other
option would be better.

My point is that creating a way to write more conditions as actual
loop headers is an improvement in Pythonicity, not a worsening of it.
It is not fundamentally Pythonic to write a non-infinite loop as
"while True"; that is a limitation caused by the inability to
represent certain conditions in any better way.

It is NOT idiomatic to use "while True" and then write your condition
just inside the loop.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
Mikhail V :

> On Wed, May 9, 2018 at 8:50 AM, Chris Angelico  wrote:
>> On Wed, May 9, 2018 at 3:36 PM, Ian Kelly  wrote:
>>> while True:
>>
>> Why is it that "while True" is idiomatic Python for a non-infinite
>> loop? Is it merely because Python currently has no other way to spell
>> certain loops? Surely it would be more idiomatic to encode the loop's
>> termination condition in the header, if it were possible.
>
> Don't know about 'idiomatic', but the above spelling is exactly what i
> tend to use lately for almost all loops. It noticeably reduces
> cognitive load. Though lately more often i prefer "while 1:" so it
> makes the nodes more lightweight and distinct from the rest lines. And
> not even official declaration of "idiomatic" as something else will
> make me switch back.

How about:

   while ...:
   do_stuff()
   if done:
   break
   do_more_stuff()

where ... is the Ellipsis.

Joking aside, to answer Chris's question, of course you can use a real
condition with "while". However, you shouldn't force it or try to avoid
"while True". It turns out "while True" is the most natural choice in
about half of the while loops.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Mikhail V
On Wed, May 9, 2018 at 8:50 AM, Chris Angelico  wrote:
> On Wed, May 9, 2018 at 3:36 PM, Ian Kelly  wrote:
>>
>> while True:
>> if we_are_done():
>> break
>> # do some stuff
>> ...
>> if error_occurred():
>> break
>> notify_user()
>>
>>
>> Fixed, using idiomatic Python and without needing to use assignment in
>> an expression.
>
> Why is it that "while True" is idiomatic Python for a non-infinite
> loop? Is it merely because Python currently has no other way to spell
> certain loops? Surely it would be more idiomatic to encode the loop's
> termination condition in the header, if it were possible.

Don't know about 'idiomatic', but the above spelling is exactly what i
tend to use lately for almost all loops. It noticeably reduces cognitive load.
Though lately more often i prefer "while 1:" so it makes
the nodes more lightweight and distinct from the rest lines.
And not even official declaration of "idiomatic" as something else will
make me switch back.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Rob Gaddi

On 05/10/2018 03:02 AM, bartc wrote:

On 10/05/2018 09:09, Marko Rauhamaa wrote:

bartc :

When typing in code (in various languages), I have a habit of typing
"..." at places that need to be implemented. For example:

 if count:
 ...
 else:
 do_something_smart()
 break

the idea being that "..." will surely trigger a syntax error if I forget
to address it.

I was mildly amused when Python happily executed such code. "..." is a
valid expression and thus, a valid statement.


I wondered what it meant, so I typed in:

    print (...)

and it displayed:

    Ellipsis

which wasn't very enlightening.



No, but if you ever have difficulty remembering how to spell "ellipsis", 
it's good to know Python comes with a built-in reference.


--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order.  See above to fix.
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
bartc :
> I wondered what it meant, so I typed in:
>
>print (...)
>
> and it displayed:
>
>Ellipsis
>
> which wasn't very enlightening.

It doesn't mean anything for Python. It's just a special singleton
sentinel object that is stored in the predefined variable "Ellipsis" and
has a literal "..." in the language.

Apparently, Python provides it as a courtesy to the Numpy module:

   https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread bartc

On 10/05/2018 09:09, Marko Rauhamaa wrote:

bartc :

On 09/05/2018 06:44, Steven D'Aprano wrote:

But by the time 1.4 came around, Guido had settled on a clean separation
between statements and expressions as part of Python's design.

That separation has gradually weakened over the years,


Presumably it's non-existent now, as it seems you can type any
expression as a statement in its own right:

   "stmt"
   a + b*c
   p == 0


When typing in code (in various languages), I have a habit of typing
"..." at places that need to be implemented. For example:

 if count:
 ...
 else:
 do_something_smart()
 break

the idea being that "..." will surely trigger a syntax error if I forget
to address it.

I was mildly amused when Python happily executed such code. "..." is a
valid expression and thus, a valid statement.


I wondered what it meant, so I typed in:

   print (...)

and it displayed:

   Ellipsis

which wasn't very enlightening.

--
bartc


--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Rustom Mody
Marko wrote:
> When typing in code (in various languages), I have a habit of typing 
> "..." at places that need to be implemented

Quite a research area actually
https://wiki.haskell.org/GHC/Typed_holes
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-10 Thread Marko Rauhamaa
bartc :
> On 09/05/2018 06:44, Steven D'Aprano wrote:
>> But by the time 1.4 came around, Guido had settled on a clean separation
>> between statements and expressions as part of Python's design.
>>
>> That separation has gradually weakened over the years,
>
> Presumably it's non-existent now, as it seems you can type any
> expression as a statement in its own right:
>
>   "stmt"
>   a + b*c
>   p == 0

When typing in code (in various languages), I have a habit of typing
"..." at places that need to be implemented. For example:

if count:
...
else:
do_something_smart()
break

the idea being that "..." will surely trigger a syntax error if I forget
to address it.

I was mildly amused when Python happily executed such code. "..." is a
valid expression and thus, a valid statement.


Marko
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-09 Thread Steven D'Aprano
On Wed, 09 May 2018 22:48:42 +0100, bartc wrote:

> On 09/05/2018 06:44, Steven D'Aprano wrote:
>> On Tue, 08 May 2018 22:48:52 -0500, Python wrote:
>> 
>> 
>> But by the time 1.4 came around, Guido had settled on a clean
>> separation between statements and expressions as part of Python's
>> design.
>> 
>> That separation has gradually weakened over the years,
> 
> Presumably it's non-existent now, as it seems you can type any
> expression as a statement in its own right:

That has always been the case. What I mean is that a few of the pure-
statement features have now gained an expression form.


>> with the addition of the ternary if operator
> 
> If you mean that this is a kind of statement that can be incorporated
> into an expression, then just class it as an operator not a statement.

I called it an operator because it is an operator :-)


To hopefully be more clear, any expression can be used as a statement 
(usually pointlessly). But statements (aside from expressions) cannot be 
used as expressions. There are, however, a small number of statements 
which have gained an equivalent expression form.



-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-09 Thread bartc

On 09/05/2018 06:44, Steven D'Aprano wrote:

On Tue, 08 May 2018 22:48:52 -0500, Python wrote:




But by the time 1.4 came around, Guido had settled on a clean separation
between statements and expressions as part of Python's design.

That separation has gradually weakened over the years,


Presumably it's non-existent now, as it seems you can type any 
expression as a statement in its own right:


  "stmt"
  a + b*c
  p == 0

 with the addition

of the ternary if operator


If you mean that this is a kind of statement that can be incorporated 
into an expression, then just class it as an operator not a statement. 
(They are different in any case, for example statement-if doesn't return 
a value.)




and comprehensions,


And that one, although it's a more complex example.


It might simply be that Guido (like many people) considered assignment to
fundamentally be an imperative command, not an expression.


You design a language, you get to choose how it works.

(I allow assignments in expressions in my languages, but the two are 
different constructs: statement-assignment returns no value; 
expression-assignment does, although both use ":=" syntax for the 
assignment operator.


That's OK ":=" doesn't really get mixed up with "=" for equality as "=" 
and "==" would do. So one answer would be to use something other than 
"=" for assignments within expressions.


I don't however allow augmented assignments in expressions, as it's not 
that useful, and it would be too much (and I could never get the 
precedences right). But normal assignment is handy.)


--
bartc
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-09 Thread Rhodri James

On 09/05/18 06:57, Chris Angelico wrote:

On Wed, May 9, 2018 at 3:44 PM, Steven D'Aprano
 wrote:

On Tue, 08 May 2018 22:48:52 -0500, Python wrote:

I've always felt that this mentality was insulting to the programmer:
"You're too stupid to get this right."  Sure, I've created that bug in
other languages (or rather its inverse) but not since college.  You make
it a few times, you go nuts debugging it, you learn what it is, you
never do it again.


And fortunately we don't have to deal with a steady stream of new
programmers learning the language and making newbie errors, right?

If all programmers were as awesome as you and never made typos, the world
would be a better place. But we know from experience that even
experienced C programmers can make this mistake by accident.


Yes, and I'd go further: I *am* too stupid to get this right.


Thirded.  I am a C and assembler programmer by trade, and I often type 
"=" for "==" when I'm coding quickly, and sometimes even when I'm trying 
to be careful.  I've met a lot of programmers over the years who assert 
that they are experienced enough not to make mistakes like that.  They 
are, without fail, embarrassed when I turn on the compiler warning flags.


--
Rhodri James *-* Kynesim Ltd
--
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-09 Thread Chris Angelico
On Wed, May 9, 2018 at 3:44 PM, Steven D'Aprano
 wrote:
> On Tue, 08 May 2018 22:48:52 -0500, Python wrote:
>> I've always felt that this mentality was insulting to the programmer:
>> "You're too stupid to get this right."  Sure, I've created that bug in
>> other languages (or rather its inverse) but not since college.  You make
>> it a few times, you go nuts debugging it, you learn what it is, you
>> never do it again.
>
> And fortunately we don't have to deal with a steady stream of new
> programmers learning the language and making newbie errors, right?
>
> If all programmers were as awesome as you and never made typos, the world
> would be a better place. But we know from experience that even
> experienced C programmers can make this mistake by accident.

Yes, and I'd go further: I *am* too stupid to get this right. That's
why I have an editor that highlights certain words. (My current editor
colours every Python standard library module name, so if I happen to
create a variable called "time", it'll make it really obvious that I
am now shadowing an importable module. Or, as I recently did,
"sched".) That's why Python gives me tracebacks that show me exactly
where I messed up. That's why my code is full of debugging checks,
comments, and other tools to help me track down my mistakes after I
make them.

Because I *will* make mistakes. I will make a LOT of mistakes. And I
am not going to try to pretend that I don't.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-08 Thread Chris Angelico
On Wed, May 9, 2018 at 3:36 PM, Ian Kelly  wrote:
>
> while True:
> if we_are_done():
> break
> # do some stuff
> ...
> if error_occurred():
> break
> notify_user()
>
>
> Fixed, using idiomatic Python and without needing to use assignment in
> an expression.

Why is it that "while True" is idiomatic Python for a non-infinite
loop? Is it merely because Python currently has no other way to spell
certain loops? Surely it would be more idiomatic to encode the loop's
termination condition in the header, if it were possible.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-08 Thread Steven D'Aprano
On Tue, 08 May 2018 22:48:52 -0500, Python wrote:

> On Tue, May 08, 2018 at 12:45:29AM +, Steven D'Aprano wrote:
>> Currently, the real reason is that lambda expressions are limited to a
>> single expression as the body of the function, and binding operations
>> in Python are statements.
> 
> ...which begs the question, why shouldn't assignments be expressions, as
> they are in many other languages?  TBH this is one of the few things
> about Python that I dislike.

No, it raises the question :-) Begging the question means to assume the 
answer to the same question you are asking.

As Chris already pointed out, there is a PEP in progress at the moment 
aimed at allowing assignment expressions (PEP 572). It is very 
controversial, but Guido appears to be in favour of it (as I am, although 
not necessarily in its current form). There's about a bazillion emails on 
the Python-Ideas and Python-Dev mailing lists arguing about it.

(Oh, and it goes *all the way back to February*.)

In the very earliest versions of Python, like 0.1, there was only a 
single = operator that was used for both equals and assignment, but that 
was changed by the first official 1.0 release. I don't know if that 
change was driven by personal preference (Guido just liked it better), 
bad experiences with bugs, or what.

But by the time 1.4 came around, Guido had settled on a clean separation 
between statements and expressions as part of Python's design.

That separation has gradually weakened over the years, with the addition 
of the ternary if operator and comprehensions, but it is still an 
important part of Python's design. You might find something on Guido's 
blogs or his various essays:

http://neopythonic.blogspot.com.au/

https://www.artima.com/weblogs/index.jsp?blogger=guido

https://legacy.python.org/doc/essays/


but I don't have time to go trawling the blogs for this.

It might simply be that Guido (like many people) considered assignment to 
fundamentally be an imperative command, not an expression.

Another reason is something Nick Coghlan (re-)discovered during the 
discussions for PEP 572, namely that if you allow the full, unrestricted 
assignment targets as an expression, the code is ambiguous or at least 
hard to understand the intent. That's why PEP 572 has limited assignments 
to just plain names, and not arbitrary assignment targets. Possibly Guido 
recognised this way back in Python 0.x as well.


>> since = in a statement on its own is not dangerous. People *almost
>> never* intend to write == for the side-effects only:
> 
> Seriously?  I do this--not every day, but more than occasionally, not
> just in Python.
> 
> flag = (spam == arg)

Of course we all do that, but it is nothing like what I said. I even gave 
fully-commented sample code, which you appear to have missed:

# don't care whether they are actually equal or not
# just want to call the __eq__ method for its side-effects
spam == arg + 1

I bet you never, ever, ever call == for the side-effects, throwing away 
the result of the comparison without using it or looking at it in any 
way. In many languages, such a comparison cannot even have side-effects, 
so it would be useless dead code.


>> # don't care whether they are actually equal or not 
>> # just want to call the __eq__ method for its side-effects
>> spam == arg + 1
>> 
>> Since that never happens in real life, there's no risk of accidentally
>> writing "spam = arg + 1" when you wanted "spam == arg + 1".
> 
> I've always felt that this mentality was insulting to the programmer:
> "You're too stupid to get this right."  Sure, I've created that bug in
> other languages (or rather its inverse) but not since college.  You make
> it a few times, you go nuts debugging it, you learn what it is, you
> never do it again.

And fortunately we don't have to deal with a steady stream of new 
programmers learning the language and making newbie errors, right?

If all programmers were as awesome as you and never made typos, the world 
would be a better place. But we know from experience that even 
experienced C programmers can make this mistake by accident.

Or deliberately:

https://freedom-to-tinker.com/2013/10/09/the-linux-backdoor-attempt-
of-2003/

or if that URL wraps: https://tinyurl.com/jpvbtua


Of course we all make mistakes, but some features and syntax are bug 
magnets: they *encourage* errors rather than discourage them. Anyone can 
mistype "flga" when they meant "flag", but the use of real words 
discourages that error since the reader can see that "flga" looks weird. 
But == and = are so similar that not only is it an easy typo to make, but 
its a hard typo to spot without a close, careful reading.


-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-08 Thread Ian Kelly
On Tue, May 8, 2018 at 9:48 PM, Python  wrote:
> On Tue, May 08, 2018 at 12:45:29AM +, Steven D'Aprano wrote:
>> since = in a statement on its own is not dangerous. People *almost never*
>> intend to write == for the side-effects only:
>
> Seriously?  I do this--not every day, but more than occasionally, not
> just in Python.
>
> flag = (spam == arg)
> vs.
> if spam == arg:
> flag = True
> else:
> flag = False
> if flag:
> do_something()
> else:
> do_something_else()

As Chris pointed out, this is not an example of using == for side-effects only.

>> # don't care whether they are actually equal or not
>> # just want to call the __eq__ method for its side-effects
>> spam == arg + 1
>>
>> Since that never happens in real life, there's no risk of accidentally
>> writing "spam = arg + 1" when you wanted "spam == arg + 1".
>
> I've always felt that this mentality was insulting to the programmer:
> "You're too stupid to get this right."  Sure, I've created that bug in
> other languages (or rather its inverse) but not since college.  You
> make it a few times, you go nuts debugging it, you learn what it is,
> you never do it again.
>
> And, this kind of thing is what code reviews are for--Python isn't so
> idiot-proof that you can get away without doing them for any
> non-trivial code--so (IMO) the language should not prevent you from
> doing useful things *simply* because you *might* make a mistake.

I do code reviews every day, and I doubt that I would actually notice
if one of them slipped in '=' where '==' was intended. Hopefully it
would be caught by unit testing though.

>  I'll
> give you an example that is both a case where Python's design choices
> make creating a bug easier, AND a case where allowing assignments to
> be expressions would save you.
>
> flag = we_are_done()
> while not flag:
> # do some stuff
> ...
> if error_occured():
> break
> falg = we_are_done()
> notify_user()
># flag will be checked again later, perhaps for error reporting


while True:
if we_are_done():
break
# do some stuff
...
if error_occurred():
break
notify_user()


Fixed, using idiomatic Python and without needing to use assignment in
an expression.

> Here, a common programming pattern (prime the loop control variable)
> gets you in trouble, because the assignment happens in two places, and
> you mistyped one of them.  There's no syntax error, but your program
> will execute forever, unless you were already done on the first call
> to prime the flag, or an error occurs.  This is probably worse than
> the = vs. == error, because your brain tends to "autocorrect" certain
> kinds of spelling errors, whereas experienced programmers learn to
> look for (or avoid entirely) the assignment vs. comparison bug.  The
> error here is reasonably easy to spot, given the trivial nature of the
> example, but would likely be harder to spot in more complex code with
> longer, more meaningful variable names.
>
> This example also is a case FOR allowing assignments to be
> expressions.  If Python allowed them, you could rewrite this as:
>
>while not (flag = we_are_done()):
> ...
> if error_occured():
> break
>notify_user()
># flag will be checked again later, perhaps for error reporting
>
> This COMPLETELY PREVENTS the spelling bug in the code above, since the
> assignment only happens in one place; and as a bonus it's less code.

Or just use an IDE with variable name autocompletion.
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-08 Thread Chris Angelico
On Wed, May 9, 2018 at 1:48 PM, Python  wrote:
>> since = in a statement on its own is not dangerous. People *almost never*
>> intend to write == for the side-effects only:
>
> Seriously?  I do this--not every day, but more than occasionally, not
> just in Python.
>
> flag = (spam == arg)
> vs.
> if spam == arg:
> flag = True
> else:
> flag = False
> if flag:
> do_something()
> else:
> do_something_else()

That's not "side effects only". You're evaluating a comparison for its
result - its primary effect. You're assigning the result of the
comparison to something.

Using equality comparisons for side effects would look like this:

spam == arg

No assignment. Just that, as a statement all on its own. It's
perfectly legal, but I doubt you've ever actually done this.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-08 Thread Python
On Tue, May 08, 2018 at 12:45:29AM +, Steven D'Aprano wrote:
> Currently, the real reason is that lambda expressions are limited to a 
> single expression as the body of the function, and binding operations in 
> Python are statements. 

...which begs the question, why shouldn't assignments be expressions,
as they are in many other languages?  TBH this is one of the few
things about Python that I dislike.

> > So far, no satisfying answer has come up, except for maybe to avoid a
> > programmer accidentally typing `=` instead of `==`, which I find a bit
> > unsatisfying as the only reason.
> 
> No, that's the reason why = is a statement not an expression. That's not 
> why statements aren't allowed in lambdas. If we had blocks, this would be 
> perfectly acceptable:
> 
> lambda arg: %%%START BLOCK
> spam = arg + 1
> ...
> %%%END BLOCK
> 
> since = in a statement on its own is not dangerous. People *almost never* 
> intend to write == for the side-effects only:

Seriously?  I do this--not every day, but more than occasionally, not
just in Python.

flag = (spam == arg)
vs.
if spam == arg:
flag = True
else:
flag = False
if flag:
do_something()
else:
do_something_else()

Obviously this is a simple example which could be rewritten and/or the
comparison copy-pasted; assume a more complex system where you need to
check if the two objects were equal in multiple places, but obtaining
the objects is computationally expensive (say, processing a large file
to obtain a large list of objects), and comparing them is likewise
computationally expensive.

> # don't care whether they are actually equal or not
> # just want to call the __eq__ method for its side-effects
> spam == arg + 1
> 
> Since that never happens in real life, there's no risk of accidentally 
> writing "spam = arg + 1" when you wanted "spam == arg + 1".

I've always felt that this mentality was insulting to the programmer:
"You're too stupid to get this right."  Sure, I've created that bug in
other languages (or rather its inverse) but not since college.  You
make it a few times, you go nuts debugging it, you learn what it is,
you never do it again.

And, this kind of thing is what code reviews are for--Python isn't so
idiot-proof that you can get away without doing them for any
non-trivial code--so (IMO) the language should not prevent you from
doing useful things *simply* because you *might* make a mistake.  I'll
give you an example that is both a case where Python's design choices
make creating a bug easier, AND a case where allowing assignments to
be expressions would save you.

flag = we_are_done()
while not flag:
# do some stuff
...
if error_occured():
break
falg = we_are_done()
notify_user()
   # flag will be checked again later, perhaps for error reporting

Here, a common programming pattern (prime the loop control variable)
gets you in trouble, because the assignment happens in two places, and
you mistyped one of them.  There's no syntax error, but your program
will execute forever, unless you were already done on the first call
to prime the flag, or an error occurs.  This is probably worse than
the = vs. == error, because your brain tends to "autocorrect" certain
kinds of spelling errors, whereas experienced programmers learn to
look for (or avoid entirely) the assignment vs. comparison bug.  The
error here is reasonably easy to spot, given the trivial nature of the
example, but would likely be harder to spot in more complex code with
longer, more meaningful variable names.

This example also is a case FOR allowing assignments to be
expressions.  If Python allowed them, you could rewrite this as:

   while not (flag = we_are_done()):
...
if error_occured():
break
   notify_user()
   # flag will be checked again later, perhaps for error reporting

This COMPLETELY PREVENTS the spelling bug in the code above, since the
assignment only happens in one place; and as a bonus it's less code.

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-07 Thread Steven D'Aprano
On Mon, 07 May 2018 22:27:22 +0200, all-lists wrote:

> Hi,
> 
> I was wondering (and have asked on StackOverflow [1] in a more elaborate
> way) whether there is a deeper reason to not allow assignments in lambda
> expressions.

Currently, the real reason is that lambda expressions are limited to a 
single expression as the body of the function, and binding operations in 
Python are statements. It is as simple as that: you can't have

y = x + 1

inside a lambda for the same reason you can't have

import spam
while condition:
try:
this()
except Exception:
pass

Because lambda takes a single expression.

And the reason for *that* limitation is that after 20+ years of looking, 
nobody has come up with a satisfactory syntax for a multiple statement 
block expression which:

- is not ambiguous

- can be parsed by an LL(1) parser

- and meets Guido's approval.


Nobody has quite ruled out a block expression, in fact it is one of the 
acknowledged useful features which Ruby has that Python doesn't. So its 
not like we don't want it. Its just hard to do without ambiguity or a 
more complex parser.


> 
> I'm not criticising, I'm asking in order to know ;-)
> 
> The surface-reason is the distinction between assignments and
> statements, but why it was designed this way (with respect to lambda,
> not in general)?
> 
> So far, no satisfying answer has come up, except for maybe to avoid a
> programmer accidentally typing `=` instead of `==`, which I find a bit
> unsatisfying as the only reason.

No, that's the reason why = is a statement not an expression. That's not 
why statements aren't allowed in lambdas. If we had blocks, this would be 
perfectly acceptable:

lambda arg: %%%START BLOCK
spam = arg + 1
...
%%%END BLOCK

since = in a statement on its own is not dangerous. People *almost never* 
intend to write == for the side-effects only:

# don't care whether they are actually equal or not
# just want to call the __eq__ method for its side-effects
spam == arg + 1

Since that never happens in real life, there's no risk of accidentally 
writing "spam = arg + 1" when you wanted "spam == arg + 1".




-- 
Steve

-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-07 Thread Stefan Klinger
Chris Angelico (2018-May-08, excerpt):
> What exactly would be the scope of the assigned name?

Yes, that's more like the kind of answer I was seeking.  But I'm not
entirely satisfied.

> def sort_func(item):
> date = parse_date(item.creation_date)
> return date.day_of_week, date.year, date.month, date.day
> items.sort(key=sort_func)

This function contains two statements.  Would be nice to see a
one-statement variant that exposes the same necessity of local
assignment.

I have not thought about local assignment expressions, but they can
already now be done naturally as follows:

lambda item: (lambda date: date.day_of_week, date.year, date.month, 
date.day)(parse_date(item.creation_date)

But this is stretching the usefulness of Python's lambda (readability)
quite a bit, I have to admit.

Anyway, I was rather thinking about global assignment.  And there
would even be choice in whether it should be always global, Python has
a rule for that in the following case:

x = 23

def foo(y):
x = 2 * y   # this is local
print('x in foo', x)

print('x before foo', x)
foo(42)
print('x after foo', x)


class z:
v = 12345

def bar(y):
z.v = 2 * y # this is global
print('z.v in bar', z.v)

print('z.v before bar', z.v)
bar(0)
print('z.v after bar', z.v)

Cheers
Stefan


--
http://stefan-klinger.de  o/X
Send plain text messages only, not exceeding 32kB./\/
\
-- 
https://mail.python.org/mailman/listinfo/python-list


Re: seeking deeper (language theory) reason behind Python design choice

2018-05-07 Thread Chris Angelico
On Tue, May 8, 2018 at 6:27 AM,   wrote:
> Hi,
>
> I was wondering (and have asked on StackOverflow [1] in a more
> elaborate way) whether there is a deeper reason to not allow
> assignments in lambda expressions.
>
> I'm not criticising, I'm asking in order to know ;-)
>
> The surface-reason is the distinction between assignments and
> statements, but why it was designed this way (with respect to lambda,
> not in general)?
>
> So far, no satisfying answer has come up, except for maybe to avoid a
> programmer accidentally typing `=` instead of `==`, which I find a bit
> unsatisfying as the only reason.

What exactly would be the scope of the assigned name? Let's say we
have a fairly typical use of a lambda function:

items.sort(key=lambda item: item.creation_date)

Now let's change that a bit. How would assignment fit into that?

def sort_func(item):
date = parse_date(item.creation_date)
return date.day_of_week, date.year, date.month, date.day
items.sort(key=sort_func)

Makes sense - now we're putting everything made on a Tuesday before
everything made on a Friday (I'm sure that's important to someone,
somewhere). So obviously any assignment should be local to the lambda
function, right?

What about this lambda function?

click_count = 0
b = Button(master, text="Click me", command=lambda: click_count += 1)
b.pack()

Equally obviously, this assignment belongs in the surrounding scope.
It can't be both, though. How should that be resolved?

If you want a way to do assignment as part of an expression, join the
discussions about PEP 572. Have fun; it's probably approaching a
thousand emails so far.

ChrisA
-- 
https://mail.python.org/mailman/listinfo/python-list


seeking deeper (language theory) reason behind Python design choice

2018-05-07 Thread all-lists
Hi,

I was wondering (and have asked on StackOverflow [1] in a more
elaborate way) whether there is a deeper reason to not allow
assignments in lambda expressions.

I'm not criticising, I'm asking in order to know ;-)

The surface-reason is the distinction between assignments and
statements, but why it was designed this way (with respect to lambda,
not in general)?

So far, no satisfying answer has come up, except for maybe to avoid a
programmer accidentally typing `=` instead of `==`, which I find a bit
unsatisfying as the only reason.

There's a bounty on the StackOverflow question.

Thanks for reading!
Stefan


[1] 
https://stackoverflow.com/questions/50090868/why-are-assignments-not-allowed-in-pythons-lambda-expressions


--
http://stefan-klinger.de  o/X
Send plain text messages only, not exceeding 32kB./\/
\
-- 
https://mail.python.org/mailman/listinfo/python-list