Mailing List Archive

Friday Finking: Contorted loops
Why does Python not have a repeat-until loop construct?
(or should that be 'modern programming languages'?)

This is a perennial question (one contributor calling it "immemorial"),
but there seem to be reasons why the Python Interpreter would find such
a construct awkward, or is otherwise unable to comply. If so, what does
one need to understand, in order to comprehend the (apparent) omission?

NB I'm not asking 'how to do this with while?'.


TLDR;
- wherein the historical background is explored, a possible 'gap in
knowledge' exposed, alternative implementations discussed, PEP-proposals
critiqued, and related-questions (re-)asked at the end...


If the question itself doesn't appeal to you, perhaps some of the
discussion and web.refs (below) will. Happy Friday. Happy thinking!


The term "Structured Programming" was coined by Edsger W Dijkstra. It
proposed a number of "control structures" (which were largely
unavailable in the programming languages of that time):

- sequence: a series of statements/routines to be executed in sequence
- selection: if...then, if...then...else..., case
- iteration: while, repeat (do...until), for
- recursion: a routine 'calling itself' as a cascade

The 'content' or 'process' of each structure was a block (or in Python
terminology: a "suite") consisting of any/all of the above (thus
"nesting"). Python's indentation practice, today likely descended from
this concept.


Much of the development of the ideas behind Structured Programming that
followed the crystallisation of this list of constructs, were attempts
to mathematically (logically) 'prove' code as "correct".

One of the ideas to (help?) make things more prove-able, was that each
block and construct have only one way in (entry), and one way out
(exit), eg (from Wikipedia) "The conditional statement should have at
least one true condition and each condition should have one exit point
at max ... Often it is recommended that each loop should only have one
entry point (and in the original structural programming, also only one
exit point, and a few languages enforce this)" which as they say, was an
idea later dropped/felt to be somewhat impracticable (but to which theme
I shall return...)

Even in fairly modest Python constructs, we quickly repeal the one-in,
one-out philosophy because try...except operates by providing another
exit-path.


The 'structures' (or "constructs") of Structured Programming were
fore-runners of the Software Patterns and SOLID Principles
commonly-practised today. These ideas still hold the same goal of
trading a degree of abstraction for programming simplicity, possibly
testability, and improved quality.

Today, Python offers almost all of the SP constructs. A form of
case/select is expected in v3.10. The continuing omission is repeat-until.


If you have not met such a code-component before, the idea of a
repeat...until (or do...until) might look like this:

repeat:
code-suite
until condition

Thus, the code-suite will be executed as many times as necessary, until
the condition is met.


In Python, we are used to while-loops, which can be expressed in the
same style as:

while condition:
code-suite

What's the difference?

The answer is that the repeat's code-block MUST be executed at least
once. Whereas a while's code-suite could be totally ignored and not
executed at all!

An analogy is to RegEx and its * and + repetitions:

* means zero, one, or more matches
+ means (at least) one, or more matches


During the last weeks 'here', writing a while-loop was a topic of
conversation. A solution offered to the OP, can be described as:

loop-init-code
while True: #in other words, loop forever
code-suite
if condition:
break

Note three things:

1 the while condition has been bastardised - there is no meaningful
condition, it is designed to loop without thought or control*

2 the control condition within and ending the loop's suite exactly
replaces the until-condition of a repeat-until construct

3 the cyclomatic-complexity of the multi-faceted construct is much
higher than of a 'pure' while-loop (or for-loop)

NB "cyclomatic complexity" is an attempt to measure a program's
complexity based on the number of distinct paths or branches in the code
(please recall earlier comment about 'entry and exit').

* in one of the web.ref discussions, our own @Chris suggests taking
advantage of the 'truthiness' of data, and inserting some documentation:

while 'there is data to process':

Which is a considerable improvement over the bland 'loop forever' or
'loop until I tell you otherwise, according to criteria I won't reveal
until later' (an operating mode every?no teenager would accept,
on-principle! - including this one...)


This form is a regularly recommended as a 'solution' (see first Answer
to SO question). However, it is likely to require some set-up (which is
technically preceding, and therefore outside of the construct, yet the
construct is highly-dependent upon it. (this may be unavoidable, regardless)

Most importantly (regretfully), another construct has been added at the
(middle or) end of the loop to perform work which has been displaced
from the while-condition.

So, whereas a repeat...until is a single construct encapsulating its
code-suite, the while+True...if+condition-break, forms two constructs
'around' the code-suite - and in some circumstances the code-suite may
be effectively split into two by the positioning of the added if+condition.

None of this is calculated to lead to 'the simple life' and soothe minds
into the Zen of Python!


Whereas most of this discussion is at the theoretical level, I have
spent several 'happy hours' hacking-away in the hope of finding a
practical solution to, or work-around for, this issue. Mostly
disappearing down the ast-and-exec rabbit-hole.

In a sub-set of possible-solutions "the time has come [for] the walrus
[operator]" ('improving' a line from a Lewis Carroll poem).

However, most solutions will require some retention of 'state'.
Accordingly, generators - which will also work in simpler cases.

They in-turn led me all the way to a class. I'm still playing with that
progression...

Sadly, am of the feeling that the 'cure' may be (as much criticised and)
more painful than 'the disease'...


Returning to an earlier point: for the 'pure' while-loop there is
exactly one way 'in' (entry), and one way 'out' (exit). The above,
loop-forever idea complicates matters, because when reading the code,
one's first understanding is that the while will control the indented
code-suite beneath - be its (single) exit. However, further reading
reveals that there is a second way 'out'. I should say, "theoretically",
because while True offers no escape - that implies it is no "exit" (the
"Hotel California" clause). So, reading the "while" creates an
expectation, but that must be immediately discarded when our eyes reach
the True-condition!


In the military, we were taught to always have a (current and
applicable) Escape Plan. If you've travelled by airplane/aeroplane you
will remember the crew giving a Safety Drill, and asking you to be aware
of your nearest exit should it be necessary to rapidly depart the plane
- and that "the closest may be behind you". These plans have virtue,
because in the chaos of an emergency, the time it takes to work-it-out
on-the-fly (hah!) may cost your life (no joke!).

To be sure, the extra time and effort required to read a bastardised
Python while-loop is hardly likely to be a matter of life or death (I
sincerely hope!), but it is grounds for complaint or 'muttering'.

When introducing trainees to recursion, I repeat over-and-over (and
-over) that the very first thing to do, is to code the termination
condition (the Escape Plan)! If you've ever coded recursive constructs,
you've almost certainly seen someone who hasn't followed this (simple)
plan - in your bath-room mirror...

The same principle applies to any while+True construct. Left alone, it
will not stop. In this situation, having to prepare by thinking about an
escape-route is a fundamental flaw. When you start coding the loop, your
mind is more interested in the code-suite - the business of the loop!
Once that is coded we will (in the normal course) be ready to
think-about 'what happens next'.

Sure, if one forgets the termination-clause, Python will save your life
- and it is likely that no-one else will notice. Does that make it
'right'? Doesn't it indicate that there's a 'smell' of something wrong?

In programming, consideration of "cognitive load" very much applies. We
are unlikely to ever need to escape from a smoke-filled development
environment, but we do have (more than) enough to think-about when
coding. Indeed the essential virtue of Structured Programming, SOLID,
software patterns, etc, is to reduce cognitive load by offering
tried-and-tested solutions, templates/abstractions, re-usable code, etc.


Am I the first to query the omission of repeat-until? No - not by a
long-shot! Raymond Hettinger and Isaac Carroll proposed PEP 315 back in
2003. The BDFL said: «Please reject the PEP. More variations along these
lines won't make the language more elegant or easier to learn. They'd
just save a few hasty folks some typing while making others who have to
read/maintain their code wonder what it means.» It was rejected.

Reading it now, the proposed syntax seems more than a little clumsy; but
makes me wonder why a more 'usual' repeat-until format wasn't, or
perhaps couldn't, be used (see Parser question).


@Raymond had (at least one) another 'go' in 2009. His comments included:
«The challenge has been finding a syntax that fits well with the
patterns in the rest of the language. It seems that every approach has
it's own strengths and weaknesses...These seem syntactically weird to me
and feel more like typos than real python code. I'm sure there are many
ways to spell the last line, but in the two years since I first worked
on the PEP, I haven't found any condition-at-the-end syntax that
FeelsRight(tm).»

Curiously, the last approach illustrated therein was to open the loop
with do: and terminate it with while+condition. I'd certainly concur
that the idea of using "while" at the 'head' of a while-loop and also at
the 'foot' of a repeat-until construct, seems "weird" (also (Tm)?). Am
not sure, perhaps didn't research far-enough, to see why another
construct-name, eg "until" was not considered. Can you point-out where
that is discussed, or give a reason 'why'?


As recently as 2017, David Murray addressed this issue with PEP 548
"More Flexible Loop Control". Again, with all the benefits conferred by
hind-sight, the idea seems clumsy: replacing the if+condition-break with
break-if+condition (in similar fashion to ternary conditional operators,
list-comprehensions, etc). It comes across as syntactic-sugar. It does
not address the 'bastardisation' and extra-construct's
cyclomatic-complexity rise.

Many points raised 'here' appear in another post at about that time (see
web.refs FYI).


In many cases, another common recommendation follows the lines of:

do-something
while the-something-is-ok:
do-more
do-something

This deserves criticism due to its code-repetition and thus
contravention of the DRY principle (Do not Repeat Yourself) - the
cyclomatic-complexity of the 'bastardisation' has been removed, but I'm
still discomforted. Are you?

As mentioned earlier, a major criticism is that something that is only
being done to establish the looping mechanism (is "closely-coupled") is
separate from, not (initially at least) an integral-part of the
construct. That said, please recall earlier allowance, that some
'initialisation' may be necessary.


Perhaps I missed it as life unfolded: has there been a paper/line of
research which discounted the need for repeat-until, assuming a while
construct was available?

Is a repeat-until construct missing from other
modern-languages, or is that a particular choice made in Python's design?


A paper from Duke (University) makes reference to a "Loop and a Half"
structure, with the particular example of completing an action until
some "sentinel-value" is reached. They presage my comments (below) about
"priming" the loop, the "sentinel" text as an additional construct,
and/or duplicate code - and how all that adds-up to making "the loop
body harder to understand since it turns a read-and-process loop into a
process-and-read loop." With sundry further admissions, they rewrite
into the bastardised form which has become Python's accepted-solution.


Perhaps it was not possible before, but will it become feasible under
Python's new (v3.9+) PEG parser?



Web.Refs:
https://en.wikipedia.org/wiki/Structured_programming
Dijkstra "Notes on Structured Programming"
https://dl.acm.org/doi/pdf/10.5555/1243380
Single-Entry, Single-Exit
https://web.archive.org/web/20121114195652/http://msmvps.com/blogs/peterritchie/archive/2008/03/07/single-entry-single-exit-should-it-still-be-applicable-in-object-oriented-languages.aspx
https://en.wikipedia.org/wiki/Cyclomatic_complexity
Ned Batchelder's McCabe plug-in https://pypi.org/project/mccabe/
The Walrus and the Carpenter by Lewis Carroll
https://poets.org/poem/walrus-and-carpenter
Python's Parser https://www.python.org/dev/peps/pep-0617/
PEP 315 https://www.python.org/dev/peps/pep-0315/
BDFL Rejection
https://mail.python.org/pipermail/python-ideas/2013-June/021610.html
Later discussion
https://mail.python.org/pipermail/python-ideas/2009-April/004306.html
and
https://mail.python.org/archives/list/python-ideas@python.org/thread/2VUZ3J6C4GSHGBZJW62AY4HPEEBMXAT6/#2VUZ3J6C4GSHGBZJW62AY4HPEEBMXAT6
PEP 548 https://www.python.org/dev/peps/pep-0548/
BDFL Rejection
https://mail.python.org/pipermail/python-dev/2017-September/149232.html
Python-Ideas post
https://mail.python.org/archives/list/python-ideas@python.org/thread/EDNARFL2RGOE53SLWPTD5ZLJQOYSVDCR/#EDNARFL2RGOE53SLWPTD5ZLJQOYSVDCR
Duke Paper
https://users.cs.duke.edu/~ola/patterns/plopd/loops.html#loop-and-a-half
RegEx in Python https://docs.python.org/3/library/re.html
and https://docs.python.org/3/howto/regex.html
"bastardise" (meaning 1) https://www.dictionary.com/browse/bastardize
https://stackoverflow.com/questions/743164/how-to-emulate-a-do-while-loop
DRY
https://code.tutsplus.com/tutorials/3-key-software-principles-you-must-understand--net-25161

--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On Fri, 10 Sep 2021 09:36:36 +1200, dn via Python-list
<python-list@python.org> declaimed the following:

>Why does Python not have a repeat-until loop construct?
>(or should that be 'modern programming languages'?)
>

I would suspect Python's indentation for block structure would be the
major hindrance. After all, all existing block constructs /open/ the block.

if ...:
block

else:
block

elif ...:
block

try:
block

except ...:
block

for ...:
block

while ...:
block

def ...:
block

class ...:
block

so how would

repeat:
block
until ...
<NO BLOCK>

fit the language. The alternative would be

repeat until ...:
block

putting the condition at the top, even though it is only tested at the
bottom (after processing <block> at least once). Granted, that IS the style
used in REXX, where DO/END are generic block boundary marks, with the DO
accepting all the loop constructs (FOR, WHILE, UNTIL) as optional parts.

>This is a perennial question (one contributor calling it "immemorial"),
>but there seem to be reasons why the Python Interpreter would find such
>a construct awkward, or is otherwise unable to comply. If so, what does
>one need to understand, in order to comprehend the (apparent) omission?
>
>NB I'm not asking 'how to do this with while?'.
>
>
>TLDR;
>- wherein the historical background is explored, a possible 'gap in
>knowledge' exposed, alternative implementations discussed, PEP-proposals
>critiqued, and related-questions (re-)asked at the end...
>
>
>If the question itself doesn't appeal to you, perhaps some of the
>discussion and web.refs (below) will. Happy Friday. Happy thinking!
>
>
>The term "Structured Programming" was coined by Edsger W Dijkstra. It
>proposed a number of "control structures" (which were largely
>unavailable in the programming languages of that time):
>
>- sequence: a series of statements/routines to be executed in sequence
>- selection: if...then, if...then...else..., case
>- iteration: while, repeat (do...until), for
>- recursion: a routine 'calling itself' as a cascade
>
>The 'content' or 'process' of each structure was a block (or in Python
>terminology: a "suite") consisting of any/all of the above (thus
>"nesting"). Python's indentation practice, today likely descended from
>this concept.
>
>
>Much of the development of the ideas behind Structured Programming that
>followed the crystallisation of this list of constructs, were attempts
>to mathematically (logically) 'prove' code as "correct".
>
>One of the ideas to (help?) make things more prove-able, was that each
>block and construct have only one way in (entry), and one way out
>(exit), eg (from Wikipedia) "The conditional statement should have at
>least one true condition and each condition should have one exit point
>at max ... Often it is recommended that each loop should only have one
>entry point (and in the original structural programming, also only one
>exit point, and a few languages enforce this)" which as they say, was an
>idea later dropped/felt to be somewhat impracticable (but to which theme
>I shall return...)
>
>Even in fairly modest Python constructs, we quickly repeal the one-in,
>one-out philosophy because try...except operates by providing another
>exit-path.
>
>
>The 'structures' (or "constructs") of Structured Programming were
>fore-runners of the Software Patterns and SOLID Principles
>commonly-practised today. These ideas still hold the same goal of
>trading a degree of abstraction for programming simplicity, possibly
>testability, and improved quality.
>
>Today, Python offers almost all of the SP constructs. A form of
>case/select is expected in v3.10. The continuing omission is repeat-until.
>
>
>If you have not met such a code-component before, the idea of a
>repeat...until (or do...until) might look like this:
>
> repeat:
> code-suite
> until condition
>
>Thus, the code-suite will be executed as many times as necessary, until
>the condition is met.
>
>
>In Python, we are used to while-loops, which can be expressed in the
>same style as:
>
> while condition:
> code-suite
>
>What's the difference?
>
>The answer is that the repeat's code-block MUST be executed at least
>once. Whereas a while's code-suite could be totally ignored and not
>executed at all!
>
>An analogy is to RegEx and its * and + repetitions:
>
>* means zero, one, or more matches
>+ means (at least) one, or more matches
>
>
>During the last weeks 'here', writing a while-loop was a topic of
>conversation. A solution offered to the OP, can be described as:
>
> loop-init-code
> while True: #in other words, loop forever
> code-suite
> if condition:
> break
>
>Note three things:
>
>1 the while condition has been bastardised - there is no meaningful
>condition, it is designed to loop without thought or control*
>
>2 the control condition within and ending the loop's suite exactly
>replaces the until-condition of a repeat-until construct
>
>3 the cyclomatic-complexity of the multi-faceted construct is much
>higher than of a 'pure' while-loop (or for-loop)
>
>NB "cyclomatic complexity" is an attempt to measure a program's
>complexity based on the number of distinct paths or branches in the code
>(please recall earlier comment about 'entry and exit').
>
>* in one of the web.ref discussions, our own @Chris suggests taking
>advantage of the 'truthiness' of data, and inserting some documentation:
>
> while 'there is data to process':
>
>Which is a considerable improvement over the bland 'loop forever' or
>'loop until I tell you otherwise, according to criteria I won't reveal
>until later' (an operating mode every?no teenager would accept,
>on-principle! - including this one...)
>
>
>This form is a regularly recommended as a 'solution' (see first Answer
>to SO question). However, it is likely to require some set-up (which is
>technically preceding, and therefore outside of the construct, yet the
>construct is highly-dependent upon it. (this may be unavoidable, regardless)
>
>Most importantly (regretfully), another construct has been added at the
>(middle or) end of the loop to perform work which has been displaced
>from the while-condition.
>
>So, whereas a repeat...until is a single construct encapsulating its
>code-suite, the while+True...if+condition-break, forms two constructs
>'around' the code-suite - and in some circumstances the code-suite may
>be effectively split into two by the positioning of the added if+condition.
>
>None of this is calculated to lead to 'the simple life' and soothe minds
>into the Zen of Python!
>
>
>Whereas most of this discussion is at the theoretical level, I have
>spent several 'happy hours' hacking-away in the hope of finding a
>practical solution to, or work-around for, this issue. Mostly
>disappearing down the ast-and-exec rabbit-hole.
>
>In a sub-set of possible-solutions "the time has come [for] the walrus
>[operator]" ('improving' a line from a Lewis Carroll poem).
>
>However, most solutions will require some retention of 'state'.
>Accordingly, generators - which will also work in simpler cases.
>
>They in-turn led me all the way to a class. I'm still playing with that
>progression...
>
>Sadly, am of the feeling that the 'cure' may be (as much criticised and)
>more painful than 'the disease'...
>
>
>Returning to an earlier point: for the 'pure' while-loop there is
>exactly one way 'in' (entry), and one way 'out' (exit). The above,
>loop-forever idea complicates matters, because when reading the code,
>one's first understanding is that the while will control the indented
>code-suite beneath - be its (single) exit. However, further reading
>reveals that there is a second way 'out'. I should say, "theoretically",
>because while True offers no escape - that implies it is no "exit" (the
>"Hotel California" clause). So, reading the "while" creates an
>expectation, but that must be immediately discarded when our eyes reach
>the True-condition!
>
>
>In the military, we were taught to always have a (current and
>applicable) Escape Plan. If you've travelled by airplane/aeroplane you
>will remember the crew giving a Safety Drill, and asking you to be aware
>of your nearest exit should it be necessary to rapidly depart the plane
>- and that "the closest may be behind you". These plans have virtue,
>because in the chaos of an emergency, the time it takes to work-it-out
>on-the-fly (hah!) may cost your life (no joke!).
>
>To be sure, the extra time and effort required to read a bastardised
>Python while-loop is hardly likely to be a matter of life or death (I
>sincerely hope!), but it is grounds for complaint or 'muttering'.
>
>When introducing trainees to recursion, I repeat over-and-over (and
>-over) that the very first thing to do, is to code the termination
>condition (the Escape Plan)! If you've ever coded recursive constructs,
>you've almost certainly seen someone who hasn't followed this (simple)
>plan - in your bath-room mirror...
>
>The same principle applies to any while+True construct. Left alone, it
>will not stop. In this situation, having to prepare by thinking about an
>escape-route is a fundamental flaw. When you start coding the loop, your
>mind is more interested in the code-suite - the business of the loop!
>Once that is coded we will (in the normal course) be ready to
>think-about 'what happens next'.
>
>Sure, if one forgets the termination-clause, Python will save your life
>- and it is likely that no-one else will notice. Does that make it
>'right'? Doesn't it indicate that there's a 'smell' of something wrong?
>
>In programming, consideration of "cognitive load" very much applies. We
>are unlikely to ever need to escape from a smoke-filled development
>environment, but we do have (more than) enough to think-about when
>coding. Indeed the essential virtue of Structured Programming, SOLID,
>software patterns, etc, is to reduce cognitive load by offering
>tried-and-tested solutions, templates/abstractions, re-usable code, etc.
>
>
>Am I the first to query the omission of repeat-until? No - not by a
>long-shot! Raymond Hettinger and Isaac Carroll proposed PEP 315 back in
>2003. The BDFL said: ?Please reject the PEP. More variations along these
>lines won't make the language more elegant or easier to learn. They'd
>just save a few hasty folks some typing while making others who have to
>read/maintain their code wonder what it means.? It was rejected.
>
>Reading it now, the proposed syntax seems more than a little clumsy; but
>makes me wonder why a more 'usual' repeat-until format wasn't, or
>perhaps couldn't, be used (see Parser question).
>
>
>@Raymond had (at least one) another 'go' in 2009. His comments included:
>?The challenge has been finding a syntax that fits well with the
>patterns in the rest of the language. It seems that every approach has
>it's own strengths and weaknesses...These seem syntactically weird to me
>and feel more like typos than real python code. I'm sure there are many
>ways to spell the last line, but in the two years since I first worked
>on the PEP, I haven't found any condition-at-the-end syntax that
>FeelsRight(tm).?
>
>Curiously, the last approach illustrated therein was to open the loop
>with do: and terminate it with while+condition. I'd certainly concur
>that the idea of using "while" at the 'head' of a while-loop and also at
>the 'foot' of a repeat-until construct, seems "weird" (also (Tm)?). Am
>not sure, perhaps didn't research far-enough, to see why another
>construct-name, eg "until" was not considered. Can you point-out where
>that is discussed, or give a reason 'why'?
>
>
>As recently as 2017, David Murray addressed this issue with PEP 548
>"More Flexible Loop Control". Again, with all the benefits conferred by
>hind-sight, the idea seems clumsy: replacing the if+condition-break with
>break-if+condition (in similar fashion to ternary conditional operators,
>list-comprehensions, etc). It comes across as syntactic-sugar. It does
>not address the 'bastardisation' and extra-construct's
>cyclomatic-complexity rise.
>
>Many points raised 'here' appear in another post at about that time (see
>web.refs FYI).
>
>
>In many cases, another common recommendation follows the lines of:
>
> do-something
> while the-something-is-ok:
> do-more
> do-something
>
>This deserves criticism due to its code-repetition and thus
>contravention of the DRY principle (Do not Repeat Yourself) - the
>cyclomatic-complexity of the 'bastardisation' has been removed, but I'm
>still discomforted. Are you?
>
>As mentioned earlier, a major criticism is that something that is only
>being done to establish the looping mechanism (is "closely-coupled") is
>separate from, not (initially at least) an integral-part of the
>construct. That said, please recall earlier allowance, that some
>'initialisation' may be necessary.
>
>
>Perhaps I missed it as life unfolded: has there been a paper/line of
>research which discounted the need for repeat-until, assuming a while
>construct was available?
>
>Is a repeat-until construct missing from other
>modern-languages, or is that a particular choice made in Python's design?
>
>
>A paper from Duke (University) makes reference to a "Loop and a Half"
>structure, with the particular example of completing an action until
>some "sentinel-value" is reached. They presage my comments (below) about
>"priming" the loop, the "sentinel" text as an additional construct,
>and/or duplicate code - and how all that adds-up to making "the loop
>body harder to understand since it turns a read-and-process loop into a
>process-and-read loop." With sundry further admissions, they rewrite
>into the bastardised form which has become Python's accepted-solution.
>
>
>Perhaps it was not possible before, but will it become feasible under
>Python's new (v3.9+) PEG parser?
>
>
>
>Web.Refs:
>https://en.wikipedia.org/wiki/Structured_programming
>Dijkstra "Notes on Structured Programming"
>https://dl.acm.org/doi/pdf/10.5555/1243380
>Single-Entry, Single-Exit
>https://web.archive.org/web/20121114195652/http://msmvps.com/blogs/peterritchie/archive/2008/03/07/single-entry-single-exit-should-it-still-be-applicable-in-object-oriented-languages.aspx
>https://en.wikipedia.org/wiki/Cyclomatic_complexity
>Ned Batchelder's McCabe plug-in https://pypi.org/project/mccabe/
>The Walrus and the Carpenter by Lewis Carroll
>https://poets.org/poem/walrus-and-carpenter
>Python's Parser https://www.python.org/dev/peps/pep-0617/
>PEP 315 https://www.python.org/dev/peps/pep-0315/
>BDFL Rejection
>https://mail.python.org/pipermail/python-ideas/2013-June/021610.html
>Later discussion
>https://mail.python.org/pipermail/python-ideas/2009-April/004306.html
>and
>https://mail.python.org/archives/list/python-ideas@python.org/thread/2VUZ3J6C4GSHGBZJW62AY4HPEEBMXAT6/#2VUZ3J6C4GSHGBZJW62AY4HPEEBMXAT6
>PEP 548 https://www.python.org/dev/peps/pep-0548/
>BDFL Rejection
>https://mail.python.org/pipermail/python-dev/2017-September/149232.html
>Python-Ideas post
>https://mail.python.org/archives/list/python-ideas@python.org/thread/EDNARFL2RGOE53SLWPTD5ZLJQOYSVDCR/#EDNARFL2RGOE53SLWPTD5ZLJQOYSVDCR
>Duke Paper
>https://users.cs.duke.edu/~ola/patterns/plopd/loops.html#loop-and-a-half
>RegEx in Python https://docs.python.org/3/library/re.html
>and https://docs.python.org/3/howto/regex.html
>"bastardise" (meaning 1) https://www.dictionary.com/browse/bastardize
>https://stackoverflow.com/questions/743164/how-to-emulate-a-do-while-loop
>DRY
>https://code.tutsplus.com/tutorials/3-key-software-principles-you-must-understand--net-25161
>
>--
>Regards,
>=dn


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 9/9/2021 5:36 PM, dn via Python-list wrote:
> Why does Python not have a repeat-until loop construct?

1. It is not needed. You covered that.

2. It is rare useful. For loops are common. While loops are occasional
(nearly an order of magnitude less common than for loops. Fractional
loop constructs are rare. ("loop-and-a-half" is a mislabel since at not
even one loop is guaranteed.) "do-while" or "repeat-until is even rarer
since fractional-loop include this as a special case.

3. Adding 'until' as a keyword *now*, rather than in 1.0 or at least
several versions ago, has cost so far judged to outweigh the small
benefit. The PEP parser makes contextual keywords much more easily
possible but there is a cost to having a context dependent grammar.
Consider this 3.10.0 snippet:

>>> match, case = 1, 1
>>> match match:
... case case:
... print('matched')
...
...
matched
>>> match case:
... case match:
... print('matched')
...
...
matched

To me, having a word sometimes be a keyword and sometime not make code
harder to read. In IDLE, it is a bit easier as the keyword uses of
'match' and 'case' above are correctly highlighted as keywords, and the
non-keywords uses not highlighted. But this is harder that for
full-time keywords with sane code that works in an re-based highlighter.

Underscore, not used above, but also a new contextual keyword, is even
harder. Three of us could not get all the cases we tested correct and I
suspect doing so without running the PEG parser may be impossible.
Since highlighting is redone with each keystroke, I suspect doing the
latter would add a noticeable and unacceptable lag between keystrokes
and display.



--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-09 at 22:33:16 +0000,
Stefan Ram <ram@zedat.fu-berlin.de> wrote:

> One can think of a language where every loop is exited this
> way, the only loop construct would be
>
> loop
> ...
>
> and it would /always/ have to be exited via enclosed breaks.

I'm not quite sure what you mean by "one can," but that's how the simple
form of Common Lisp's loop macro works. Friendlier looping constructs
are built with other macros on top of that one and/or its underlying
mechanism.?

? The underlying mechanism is the moral equivalent of a Python suite
that can also contain tags and unconditional jumps to those tags, aka
"goto"s.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On Thu, 09 Sep 2021 19:07:49 -0400, Dennis Lee Bieber
<wlfraed@ix.netcom.com> declaimed the following:

>On Fri, 10 Sep 2021 09:36:36 +1200, dn via Python-list
><python-list@python.org> declaimed the following:

Someone, please shoot me now...

>>This is a perennial question (one contributor calling it "immemorial"),
>>but there seem to be reasons why the Python Interpreter would find such
>>a construct awkward, or is otherwise unable to comply. If so, what does
>>one need to understand, in order to comprehend the (apparent) omission?
>>

How did I ever let that whole quote pass through without trimming...


--
Wulfraed Dennis Lee Bieber AF6VN
wlfraed@ix.netcom.com http://wlfraed.microdiversity.freeddns.org/

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 10/09/21 11:47 am, Terry Reedy wrote:
> 2. It is rare useful.  For loops are common.  While loops are occasional
> (nearly an order of magnitude less common than for loops.  Fractional
> loop constructs are rare.

I would say that fractional loops are more common than loops
which truly need to execute completely at least once, and
aren't bugs waiting to be triggered by an edge case such as
empty input.

I seem to remember someone - maybe Wirth? - long ago expressing
the opinion that repeat-until loops often tended to be error
prone, but I can't provide a reference, sorry.

--
Greg

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 10/09/2021 00:47, Terry Reedy wrote:

> even one loop is guaranteed.) "do-while" or "repeat-until is even rarer
> since fractional-loop include this as a special case.

Is there any empirical evidence to support this?
Or is it just a case of using the tools that are available?
In my experience of using Pascal (and much later with Delphi)
that I used repeat loops at least as often as while loops,
possibly more.

But using Python and to a lesser extent C (which has a
rather horrible do/while) construct I use while loops
(often with an if-break) simply because that's what
the language offers.

So is it the case that the "need" for repeat loops is
rare, simply a result of there being no native repeat
loop available? After all we could have done without
a for loop too and just used a while loop for
everything (as was done in Oberon(?) ) Would we
then state that the use of for loops was rare?
But I would hope that any empirical research would
look at the wider function of the loop and its
purpose rather than merely analyzing the syntax
and keywords.


--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 09/09/2021 22:36, dn via Python-list wrote:

> Even in fairly modest Python constructs, we quickly repeal the one-in,
> one-out philosophy because try...except operates by providing another
> exit-path.

Exceptions are exceptional by their nature (or should be!) As such
they can arguably be excused from the SP strictures.

But python complicates this tenet still further by adding an else
clause to its loops. And complicating this still more is that these
else clauses have almost exactly opposite effects.

while...else...

executes the else if the body of the loop does NOT get executed.

for...else...

executes the else iff ALL iterations of the for loop DO complete.

This confuses beginners immensely - and quite a few non
beginners too; which is probably why they are not often
seen "in the wild".

This adds to the question of where exactly does a Python loop
end? Is it after the code-suite following the loop construct?
Or is it after the else code-suite, where such exists?

Returning to the specific case of a repeat structure.
In the case of a while loop the else offers another option:

while condition
loop-body
else
loop-body

Now loop-body always gets executed at least once. But at
the cost of duplicating the loop-body code, thus violating DRY.

Just another thought...

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-10 12:38, Alan Gauld via Python-list wrote:
> On 09/09/2021 22:36, dn via Python-list wrote:
>
>> Even in fairly modest Python constructs, we quickly repeal the one-in,
>> one-out philosophy because try...except operates by providing another
>> exit-path.
>
> Exceptions are exceptional by their nature (or should be!) As such
> they can arguably be excused from the SP strictures.
>
> But python complicates this tenet still further by adding an else
> clause to its loops. And complicating this still more is that these
> else clauses have almost exactly opposite effects.
>
> while...else...
>
> executes the else if the body of the loop does NOT get executed.
>
> for...else...
>
> executes the else iff ALL iterations of the for loop DO complete.
>
[snip]

In both cases, it executes the 'else' part if it didn't break out of the
loop. That's it.

If all of the iterations completed, then there was no break, so the
'else' part is executed.

If there were no iterations, then there was no break, so the 'else' part
is executed.

It's the same for both of them.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 10/09/2021 16:36, MRAB wrote:

>> while...else...
>>
>> executes the else if the body of the loop does NOT get executed.
>>
>> for...else...
>>
>> executes the else iff ALL iterations of the for loop DO complete.
>>
> [snip]
>
> In both cases, it executes the 'else' part if it didn't break out of the
> loop. That's it.

OK, That's a useful perspective that is at least consistent.

Unfortunately it's not how beginners perceive it and it causes
regular confusion about how/when they should use else with a loop.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>>can be misleading, because the "..." part can still contain
>>"break", "raise", "continue", and "return" statement. So one
>>better should always be on the watch when reading source code
>>of a language like Python than relying only on the condition
>>behind the "while".
>
> The existence of statements like "break" renders
> proof techniques for loops (such as Hoare's) with
> their invariants and inference rules unapplicable.

Also the reason to avoid repeat-until loops: the loop "invariant" isn't
the same on the first iteration as on subsequent iterations.
--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
So why use the word "else" when it really does not mean what users consider
else?

Again, we have words like "finally" used in some places to mean it should be
done no matter what, like closing a file that may be open.

What phrase used either in one or all contexts might have been better, if
longer?

I mean in the case where your while is NOT entered, "else" almost makes
sense. But it could also have been loop_skipped or something.

In other cases, it could be some name like "loop_completed_normally" or
whatever.

Reusing the keyword "else" over and over for "if" statements and perhaps
some kind of case/switch statement and while loops and so on, may be
parsimonious but ...


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Alan Gauld via Python-list
Sent: Friday, September 10, 2021 11:58 AM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 10/09/2021 16:36, MRAB wrote:

>> while...else...
>>
>> executes the else if the body of the loop does NOT get executed.
>>
>> for...else...
>>
>> executes the else iff ALL iterations of the for loop DO complete.
>>
> [snip]
>
> In both cases, it executes the 'else' part if it didn't break out of
> the loop. That's it.

OK, That's a useful perspective that is at least consistent.

Unfortunately it's not how beginners perceive it and it causes regular
confusion about how/when they should use else with a loop.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


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

--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
In this discussion, I shudder to mention that people often simply use all kinds of additional logic to get a result. How much code have you seen that has some variable like "completed = False" that can be set to True in multiple places and many areas inside the loop are enclosed in an IF statement that only executes when completed remains False. So there is one clean exit in the sense that even when only half a loop has been done, it continues to the end of the loop and leaves before the next iteration. True, there is no break or return from the middle of the loop but logically there is if not for the convoluted code to avoid it.

Similarly, can most "while" loops that you want to be "until" loops not be made with a bit of code? I mean set first_time to True before starting. Set your while condition to while first_time OR condition or some other such logic. That guarantees you go into the loop even when condition is False. Within the loop, negate first_time.

Does that look more like a simulated repeat until, with extra overhead?

As I see it, there are many viewpoints here. From a programming perspective, it is nice to be able to state the overall shape of what you are doing in an upfront-way and also something others can read. Some things like the C-style for loop provide a bit of this but in a way I think outsiders may stare at as in for (initialize; compare-condition; iterate-change) { ... }

That is sort of compact but I have seen it get quite complex. If designed for readers, it might be designed a bit like what we do with keywords in functions headers where you might specify the "names" of each such section to make it clearer, and not just positional.

But some forms of loops like do {...} until ...

Make you have to scan forward to see what makes them end. That is not necessarily bad as you may need to read the code to see how it sets up the variables controlling the exit condition.

But if you want a wide open setup, where the conditions for the loop being entered can be specified, then the condition for it to be repeated (if different) can be specified and the condition at the end that makes you exit without trying the condition on top, you can go nuts. As mentioned, some languages have else clauses or finally clauses and error handling with things like try() or some kind of on.exit() can cause weird things. Some languages may even want you to be able to test some condition automatically after every single statement and exit immediately.

Even if you disagree with the idea of picking a few constructs that are commonly used or encouraged, you may want to consider what happens when you make a language so bloated that compiling or interpreting it becomes a big challenge and it has too many keywords.

When it comes to other perspectives like having algorithms able to evaluate a program and prove it has no bugs, you may end up with a very restricted programming language and still fail. Throw in the reality that your loop may use variable manipulated in parallel by other threads and that your thread may be killed as it runs and I wonder.



-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On Behalf Of Greg Ewing
Sent: Friday, September 10, 2021 2:40 AM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 10/09/21 11:47 am, Terry Reedy wrote:
> 2. It is rare useful. For loops are common. While loops are
> occasional (nearly an order of magnitude less common than for loops.
> Fractional loop constructs are rare.

I would say that fractional loops are more common than loops which truly need to execute completely at least once, and aren't bugs waiting to be triggered by an edge case such as empty input.

I seem to remember someone - maybe Wirth? - long ago expressing the opinion that repeat-until loops often tended to be error prone, but I can't provide a reference, sorry.

--
Greg

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

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-10 at 15:08:19 -0600,
Joe Pfeiffer <pfeiffer@cs.nmsu.edu> wrote:

> ram@zedat.fu-berlin.de (Stefan Ram) writes:

> > The existence of statements like "break" renders
> > proof techniques for loops (such as Hoare's) with
> > their invariants and inference rules unapplicable.
>
> Also the reason to avoid repeat-until loops: the loop "invariant" isn't
> the same on the first iteration as on subsequent iterations.

I am by no means an expert, nor likely even a neophyte, but why would
the loop invariant not be the same on the first iteration?

I can certainly see that the exit condition may not make sense at the
beginning of the first iteration (e.g., there is not yet any data to
compare to the sentinel), but ISTM that claiming that the exit condition
is a loop invariant isn't kosher (because all you're claiming is that
the compiler works).

I can also see that certain state information may not be captured until
the end of the first iteration. But presumably said state information
can change from iteration to iteration, so I can't see how you'd derive
an invariant involving it.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 9/10/2021 7:38 AM, Alan Gauld via Python-list wrote:

> But python complicates this tenet still further by adding an else
> clause to its loops. And complicating this still more is that these
> else clauses have almost exactly opposite effects.

To the contrary...

if...else
executes the else part if the condition is false.

>
> while...else...
>
> executes the else if the body of the loop does NOT get executed.

IE, executes the else part if the condition is false.
A while statement is, or can be viewed as, an if statement with a goto
ending the if part.


> for...else...
>
> executes the else iff ALL iterations of the for loop DO complete.

IE, executes the else part of the condition is false.
A for loop is, or can be viewed as syntactic sugar for a while loop.
The condition is that next(iterable) yields a value.

It is possible that the doc could be improved. I have not looked for a
while. Or maybe it needs to be read more.

--
Terry Jan Reedy

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
2QdxY4RzWzUUiLuE@potatochowder.com writes:

> On 2021-09-10 at 15:08:19 -0600,
> Joe Pfeiffer <pfeiffer@cs.nmsu.edu> wrote:
>
>> ram@zedat.fu-berlin.de (Stefan Ram) writes:
>
>> > The existence of statements like "break" renders
>> > proof techniques for loops (such as Hoare's) with
>> > their invariants and inference rules unapplicable.
>>
>> Also the reason to avoid repeat-until loops: the loop "invariant" isn't
>> the same on the first iteration as on subsequent iterations.
>
> I am by no means an expert, nor likely even a neophyte, but why would
> the loop invariant not be the same on the first iteration?
>
> I can certainly see that the exit condition may not make sense at the
> beginning of the first iteration (e.g., there is not yet any data to
> compare to the sentinel), but ISTM that claiming that the exit condition
> is a loop invariant isn't kosher (because all you're claiming is that
> the compiler works).

Precisely because you've got knowledge of the exit condition on
iterations after the first, but not the first one. So, unlike a while
loop, you don't have the same knowledge on every pass.

> I can also see that certain state information may not be captured until
> the end of the first iteration. But presumably said state information
> can change from iteration to iteration, so I can't see how you'd derive
> an invariant involving it.
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 10/09/2021 19:49, Stefan Ram wrote:
> Alan Gauld <alan.gauld@yahoo.co.uk> writes:
>> OK, That's a useful perspective that is at least consistent.
>> Unfortunately it's not how beginners perceive it
> ...
>
> Beginners perceive it the way it is explained to them by
> their teacher.

I'm not sure that's true. Most beginners, in my experience,
learn the syntax from their teachers and then go off and play.
What they observe happening is what sticks. And python loop
'else' constructs appear inconsistent to them.

As teachers we like to think we are passing on our wisdom
to our students but in reality everyone learns from their
own experience. The teachers advice is just the starting
point. Hopefully, that starting point sends them in the
right direction but that's the best we can hope for.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-10 12:26:24 +0100, Alan Gauld via Python-list wrote:
> On 10/09/2021 00:47, Terry Reedy wrote:
> > even one loop is guaranteed.) "do-while" or "repeat-until is even rarer
> > since fractional-loop include this as a special case.
>
> Is there any empirical evidence to support this?
> Or is it just a case of using the tools that are available?
> In my experience of using Pascal (and much later with Delphi)
> that I used repeat loops at least as often as while loops,
> possibly more.
>
> But using Python and to a lesser extent C (which has a
> rather horrible do/while) construct

How is C's do/while loop more horrible than Pascal's repeat/until? They
seem almost exactly the same to me (the differences I see are the
inverted condition (debatable which is better) and the added block
delimiters (which I actually like)).


> So is it the case that the "need" for repeat loops is
> rare, simply a result of there being no native repeat
> loop available?

A tiny non-representative data point:

In an old collection of small C programs of mine I find:

35 regular for loops
28 while loops
2 infinite for loops
1 "infinite" for loop (i.e. it exits somewhere in the middle)
0 do/while loops.

So even though do/while loops are available in C (and I don't find them
horrible) I apparently found very little use for them (I'm sure if I
look through more of my C programs I'll find a few examples, but this
small samples shows they are rare.

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
Re: Friday Finking: Contorted loops [ In reply to ]
On 11/09/2021 15:41, Peter J. Holzer wrote:

> How is C's do/while loop more horrible than Pascal's repeat/until?

Because it is very hard to spot or distinguish from a normal
while loop.

while condition ;

Is a valid (and fairly common) loop in C

so code that has

do{
code
}
while condition;

Looks, for non-trivial cases, like a lot of code followed
by an empty while loop.

The do is easy to miss and the while loop disguised as
a repeat termination is confusing.

repeat
code
until condition

Is far clearer to comprehend since there is no ambiguity.

> In an old collection of small C programs of mine I find:
>
> 35 regular for loops
> 28 while loops
> 2 infinite for loops
> 1 "infinite" for loop (i.e. it exits somewhere in the middle)
> 0 do/while loops.

That wouldn't surprise me, I've only used do/while in C
a handful of times. But in Pascal I use it regularly.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
Alan and others,

I think human languages used to make computer languages will often cause
confusion.

Some languages have an IF .. ELSE construct but also an EITHER ... OR and a
NEITHER ... NOR and other twists and turns like words that sometimes come
apart and you end up having to dangle a part that was in the front of a word
to later in the sentence and so on.

But I suspect many languages do NOT naturally have a construct like:

WHILE ... ELSE.

The might have a sentence like "While it is sunny you should use sunscreen
but when it rains use an umbrella." It probably is even a tad deceptive to
use WHILE in one part and not in the other. Perfectly valid sentences are
"When going outside if it is sunny use sunscreen but if it is rainy use an
umbrella" or skip the while and use a more standard if/else. The world
"while" just does not feel like a partner for "else".

So say you want to have a loop starting with WHILE and FOLLOWED by a single
ELSE clause. Arguably you could make WHILE as a construct return a status of
sorts if it runs at all or perhaps if it exits after at least one iteration
because the condition evaluates to FALSE. It would either return false if
you exit with a BREAK or by an error or perhaps not exit at all if you do a
return from within.

So if you made up a syntax like:

IF (WHILE condition {...})
ELSE {...}

Then what would that mean? Again, this is a make-believe construct. In the
above, if WHILE returned a True of some sort, the else is skipped.
Otherwise, no matter what has been done within the while loop, it is done.

But as noted we have odd choices here potentially. Could we differentiate
between a BREAK statement within and something like BREAK OK variant that
means the while is to be treated as succeeded and please do not do the
trailing ELSE? I can see many possible ways to design things and cannot
expect humans to automatically assume the specific nomenclature will be
meaningful to them.

There is an alternative that people who are not damn sure what the meaning
is can do. Create a variable that is set to False or True to represent
something before the WHILE is entered. Then make sure your code flips that
value in cased you want to make sure a trailing statement is run. Then
following the while, you place an IF statement that tests that variable and
does what the ELSE cluse would have done, or not.

Looking at other constructs, look at this code with a try:

i=0
while i<5:
try:
assert(i!=3) #Raises an AssertionError if i==3
print("i={0}".format(i))
except:
continue
finally:
i+= 1; #Increment i

Now attach an ELSE clause to the WHILE, LOL!

At some point, van some humans decide just not to write the code this way?

What about code that uses CONTINUE to the point where you enter the WHILE
statement and get a secondary IF or something that keeps triggering a
CONTINUE to start the next iteration. Arguably, this can effectively mean
the WHILE loop did nothing. An example would be evaluating the contents of a
data structure like a list and adding all numeric items together and
ignoring any that are character strings. Given all characters, no summation
is done. The first statement in the loop tests a list item and does a
CONTINUE. But by the rules as I see them, the loop was entered. Yet, a
similar loop written where the WHILE condition simply tests if ANY item is
numeric, might drop right through to an ELSE clause.

Bottom line is humans do not all think alike and language constructs that
are clear and logical to one may be confusing or mean the opposite to
others.

I can even imagine designing an interface like this:

WHILE (condition):
...
IF_NOT_RUN:
...
IF_EXITED_EARLY:
...
IF_ERROR_THROWN:
...
ON_PREMATURE_RETURN_DO_THIS:
...

I am not suggesting we need critters like that, simply that ELSE is a grab
bag case that can mean many things to many people.

But if the specific meaning is clearly documented, use it. Lots of people
who program in languages like Python do not necessarily even speak much
English and just memorize the keywords.

We can come up with ever more interesting or even bizarre constructs like
multiple WHILE in a row with each one being called only if the previous one
failed to process the data. An example might be if each tests the data type
and refuses to work on it so the next one in line is called. That could
perhaps be done by having multiple ELSE statements each with another WHILE.
But is that an ideal way to do this or perhaps instead use some variant of a
switch statement or a dictionary pointing to functions to invoke or
something.

Time to go do something lese of even minor usefulness!

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Alan Gauld via Python-list
Sent: Saturday, September 11, 2021 3:59 AM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 10/09/2021 19:49, Stefan Ram wrote:
> Alan Gauld <alan.gauld@yahoo.co.uk> writes:
>> OK, That's a useful perspective that is at least consistent.
>> Unfortunately it's not how beginners perceive it
> ...
>
> Beginners perceive it the way it is explained to them by
> their teacher.

I'm not sure that's true. Most beginners, in my experience, learn the
syntax from their teachers and then go off and play.
What they observe happening is what sticks. And python loop 'else'
constructs appear inconsistent to them.

As teachers we like to think we are passing on our wisdom to our students
but in reality everyone learns from their own experience. The teachers
advice is just the starting point. Hopefully, that starting point sends them
in the right direction but that's the best we can hope for.

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


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

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
ram@zedat.fu-berlin.de (Stefan Ram) writes:

> Alan Gauld <alan.gauld@yahoo.co.uk> writes:
>>OK, That's a useful perspective that is at least consistent.
>>Unfortunately it's not how beginners perceive it
> ...
>
> Beginners perceive it the way it is explained to them by
> their teacher.

My life as a professor would have been *so* much easier if that were
true...
--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
Peter, in your own personal finite sample, I am wondering what you might do
TODAY if you looked at your loops again and considered redoing them for an
assortment of reasons ranging from using the code for teaching to efficiency
to just fitting your mood better?

I have seen seasoned authors go back to their early work and groan. Some
have even reissued earlier work with a partial rewrite often with a long
additional preface explaining why and even mentioned what was changed and
bemoaning how they thought differently back then.

My guess is that many of us (meaning myself included) often approach a
problem and go with the first thing that comes to mind. If it fits well
enough, we move on to the next thing we can do. If not, we may step back and
evaluate multiple additional options and try another tack.

I have seen not of sort-of redundant code because someone did not plan ahead
and realize something very similar might be needed later and thus did not
make a general function they could re-use. Occasionally they may later go
back and re-do but often, not so much and just keep copying lines and making
minor modifications. Same general idea.

And perhaps worse, you may write a loop and later have to keep adding code
to deal with new requirements and special cases and rather than pause and
analyze and perhaps start again with a cleaner or more easily extendable
solution, just keep grafting on things to make the darn current code work.
Code that has many ways to exit a loop is often an example of this
happening.

So if you looked at your own code now, in the context of the rest of your
code, would you change things?

in python, I suspect I would seriously change an amazing number of things
for older code including code being ported. It supports quite a few
programming constructs and styles and has access to plenty of modules that
mean you need not re-invent all the time. How many formal loops might you
replace with a list comprehension or use a generator, NOW? How many problems
you once solved by doing things like looping and searching for an element
being present in a list when now you might use a set or dictionary?

The reality is many people learn the basics of a language and write using
fairly basic constructs and only later master the more advanced topics. But
their mature work may then often heavily use those later and more effective
methods. Functional programming often uses constructs where loops become
invisible. Objects often hide loops in all kinds of methods. Sometimes
recursion effectively does a loop. It is sometimes easy to write programs
with no visible loops.

So when counting the various kinds, are you looking for direct or indirect
methods too like map/reduce or vectorized operations?


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Peter J. Holzer
Sent: Saturday, September 11, 2021 10:42 AM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 2021-09-10 12:26:24 +0100, Alan Gauld via Python-list wrote:
> On 10/09/2021 00:47, Terry Reedy wrote:
> > even one loop is guaranteed.) "do-while" or "repeat-until is even
> > rarer since fractional-loop include this as a special case.
>
> Is there any empirical evidence to support this?
> Or is it just a case of using the tools that are available?
> In my experience of using Pascal (and much later with Delphi) that I
> used repeat loops at least as often as while loops, possibly more.
>
> But using Python and to a lesser extent C (which has a rather horrible
> do/while) construct

How is C's do/while loop more horrible than Pascal's repeat/until? They seem
almost exactly the same to me (the differences I see are the inverted
condition (debatable which is better) and the added block delimiters (which
I actually like)).


> So is it the case that the "need" for repeat loops is rare, simply a
> result of there being no native repeat loop available?

A tiny non-representative data point:

In an old collection of small C programs of mine I find:

35 regular for loops
28 while loops
2 infinite for loops
1 "infinite" for loop (i.e. it exits somewhere in the middle)
0 do/while loops.

So even though do/while loops are available in C (and I don't find them
horrible) I apparently found very little use for them (I'm sure if I look
through more of my C programs I'll find a few examples, but this small
samples shows they are rare.

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
Il 11/09/2021 22:29, Avi Gross ha scritto:
>
> Alan and others,
>
> I think human languages used to make computer languages will often cause
> confusion.
>
> Some languages have an IF .. ELSE construct but also an EITHER ... OR and a
> NEITHER ... NOR and other twists and turns like words that sometimes come
> apart and you end up having to dangle a part that was in the front of a word
> to later in the sentence and so on.
>
> But I suspect many languages do NOT naturally have a construct like:
>
> WHILE ... ELSE.
>
> The might have a sentence like "While it is sunny you should use sunscreen
> but when it rains use an umbrella." It probably is even a tad deceptive to
> use WHILE in one part and not in the other. Perfectly valid sentences are
> "When going outside if it is sunny use sunscreen but if it is rainy use an
> umbrella" or skip the while and use a more standard if/else. The world
> "while" just does not feel like a partner for "else".
>
> So say you want to have a loop starting with WHILE and FOLLOWED by a single
> ELSE clause. Arguably you could make WHILE as a construct return a status of
> sorts if it runs at all or perhaps if it exits after at least one iteration
> because the condition evaluates to FALSE. It would either return false if
> you exit with a BREAK or by an error or perhaps not exit at all if you do a
> return from within.
>
> So if you made up a syntax like:
>
> IF (WHILE condition {...})
> ELSE {...}
>
> Then what would that mean? Again, this is a make-believe construct. In the
> above, if WHILE returned a True of some sort, the else is skipped.
> Otherwise, no matter what has been done within the while loop, it is done.
>
> But as noted we have odd choices here potentially. Could we differentiate
> between a BREAK statement within and something like BREAK OK variant that
> means the while is to be treated as succeeded and please do not do the
> trailing ELSE? I can see many possible ways to design things and cannot
> expect humans to automatically assume the specific nomenclature will be
> meaningful to them.
>
> There is an alternative that people who are not damn sure what the meaning
> is can do. Create a variable that is set to False or True to represent
> something before the WHILE is entered. Then make sure your code flips that
> value in cased you want to make sure a trailing statement is run. Then
> following the while, you place an IF statement that tests that variable and
> does what the ELSE cluse would have done, or not.
>
> Looking at other constructs, look at this code with a try:
>
> i=0
> while i<5:
> try:
> assert(i!=3) #Raises an AssertionError if i==3
> print("i={0}".format(i))
> except:
> continue
> finally:
> i+= 1; #Increment i
>
> Now attach an ELSE clause to the WHILE, LOL!
>
> At some point, van some humans decide just not to write the code this way?
>
> What about code that uses CONTINUE to the point where you enter the WHILE
> statement and get a secondary IF or something that keeps triggering a
> CONTINUE to start the next iteration. Arguably, this can effectively mean
> the WHILE loop did nothing. An example would be evaluating the contents of a
> data structure like a list and adding all numeric items together and
> ignoring any that are character strings. Given all characters, no summation
> is done. The first statement in the loop tests a list item and does a
> CONTINUE. But by the rules as I see them, the loop was entered. Yet, a
> similar loop written where the WHILE condition simply tests if ANY item is
> numeric, might drop right through to an ELSE clause.
>
> Bottom line is humans do not all think alike and language constructs that
> are clear and logical to one may be confusing or mean the opposite to
> others.
>
> I can even imagine designing an interface like this:
>
> WHILE (condition):
> ...
> IF_NOT_RUN:
> ...
> IF_EXITED_EARLY:
> ...
> IF_ERROR_THROWN:
> ...
> ON_PREMATURE_RETURN_DO_THIS:
> ...
>
> I am not suggesting we need critters like that, simply that ELSE is a grab
> bag case that can mean many things to many people.
>
> But if the specific meaning is clearly documented, use it. Lots of people
> who program in languages like Python do not necessarily even speak much
> English and just memorize the keywords.
>
> We can come up with ever more interesting or even bizarre constructs like
> multiple WHILE in a row with each one being called only if the previous one
> failed to process the data. An example might be if each tests the data type
> and refuses to work on it so the next one in line is called. That could
> perhaps be done by having multiple ELSE statements each with another WHILE.
> But is that an ideal way to do this or perhaps instead use some variant of a
> switch statement or a dictionary pointing to functions to invoke or
> something.
>
> Time to go do something lese of even minor usefulness!
>
> -----Original Message-----
> From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
> Behalf Of Alan Gauld via Python-list
> Sent: Saturday, September 11, 2021 3:59 AM
> To: python-list@python.org
> Subject: Re: Friday Finking: Contorted loops
>
> On 10/09/2021 19:49, Stefan Ram wrote:
>> Alan Gauld <alan.gauld@yahoo.co.uk> writes:
>>> OK, That's a useful perspective that is at least consistent.
>>> Unfortunately it's not how beginners perceive it
>> ...
>>
>> Beginners perceive it the way it is explained to them by
>> their teacher.
>
> I'm not sure that's true. Most beginners, in my experience, learn the
> syntax from their teachers and then go off and play.
> What they observe happening is what sticks. And python loop 'else'
> constructs appear inconsistent to them.
>
> As teachers we like to think we are passing on our wisdom to our students
> but in reality everyone learns from their own experience. The teachers
> advice is just the starting point. Hopefully, that starting point sends them
> in the right direction but that's the best we can hope for.
>
> --
> Alan G
> Author of the Learn to Program web site
> http://www.alan-g.me.uk/
> http://www.amazon.com/author/alan_gauld
> Follow my photo-blog on Flickr at:
> http://www.flickr.com/photos/alangauldphotos
>
>

An inconsistency that I have been able to notice is this:
someone suggests to remedy the absence of the do-while with:
while True:
...
if condition:
break
the problem arises if the while has an else of its own because the break
not only blocks the while loop but will also ignore the relative else.

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
-- snip --
>
> An inconsistency that I have been able to notice is this:
> someone suggests to remedy the absence of the do-while with:
> while True:
> ???? ...
> ???? if condition:
> ???????? break
> the problem arises if the while has an else of its own because the break
> not only blocks the while loop but will also ignore the relative else.
>

I will try to make my doubt clearer:
if the only way to terminate a 'while True' loop is by using the 'break'
statement, why is it allowed to add the 'else' statement which will only
contain dead code?

while True:
break
else:
print('dead code')
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-11 21:38:02 -0400, Avi Gross via Python-list wrote:
> Peter, in your own personal finite sample, I am wondering what you might do
> TODAY if you looked at your loops again and considered redoing them for an
> assortment of reasons ranging from using the code for teaching to efficiency
> to just fitting your mood better?
>
> I have seen seasoned authors go back to their early work and groan.

Yeah, I do that. (Un)fortunately I also have other people's code to
groan about so I won't despair too much about the stupidity of my
younger self.


> My guess is that many of us (meaning myself included) often approach a
> problem and go with the first thing that comes to mind. If it fits well
> enough, we move on to the next thing we can do. If not, we may step back and
> evaluate multiple additional options and try another tack.
>
> I have seen not of sort-of redundant code because someone did not plan ahead
> and realize something very similar might be needed later and thus did not
> make a general function they could re-use. Occasionally they may later go
> back and re-do but often, not so much and just keep copying lines and making
> minor modifications. Same general idea.

That certainly happens. I am a bit overly conservative and try to get
away with minimal code changes even if a complete reimplementation of
that unit would be clearly better. Especially if it's someone else's
code and there are no unit tests. But also for my own code.

(As an aside, I notice the same tendency when changing text: Altering an
existing paragraph is hard, especially if someone else wrote it. Also,
while I think I can express myself quite clearly in both German and
English, I'm rarely satisfied when I try to translate between those
languages. I always stick too close to the original).

> And perhaps worse, you may write a loop and later have to keep adding code
> to deal with new requirements and special cases and rather than pause and
> analyze and perhaps start again with a cleaner or more easily extendable
> solution, just keep grafting on things to make the darn current code work.
> Code that has many ways to exit a loop is often an example of this
> happening.

That too. Those little C utilities I mentioned are probably a bad
example because they are so small and had little reason to evolve. But I
do have Perl scripts which I originally wrote 20 years ago and which are
still in use and have been adapted to changing business requirements
again and again in that time. Those do contain some gnarly code.


> So if you looked at your own code now, in the context of the rest of your
> code, would you change things?

Almost certainly. Especially in C I would probably be more cautious
about undefined behaviour now and for different reasons. Back in the
90's I mostly worried about portability: That code could one day run on a
36-bit ones-complement machine with 9-bit chars. These I days I worry
more about overly aggressive optimizations: That pointer is accessed
here so it can't be null, so it can't be null here either so that check
can be optimized away.

I started using Python only 7 years ago, when I had already been using
Perl for almost 20 and C for over 25 years. So my older Python code
probably looks a bit "perly". So they use dicts and map and filter but
not list comprehensions for example. Also some of that code was
partially inherited from other Python programmers who adhered to the
"a real programmer can write Fortran in any language" mindset.


> So when counting the various kinds, are you looking for direct or indirect
> methods too like map/reduce or vectorized operations?

No, because that wasn't the question I was trying to answer. The
question was "do people use do/while loops frequently in languages which
provide them"? I chose C (mostly because it is easier to get useful
numbers with tools like grep and wc than with Perl) and therefore only
the types of loops available in C. (Methodically the main flaw in my
approach is that I only looked at a single language and a single person
and only a tinly sample from that person. To really answer that question
you would have to look at a sizable sample from Github or something like
that).

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
Re: Friday Finking: Contorted loops [ In reply to ]
On Sun, 12 Sep 2021 10:11:15 +0200, jak wrote:

> -- snip --
>>
>> An inconsistency that I have been able to notice is this:
>> someone suggests to remedy the absence of the do-while with:
>> while True:
>>      ...
>>      if condition:
>>          break
>> the problem arises if the while has an else of its own because the
>> break not only blocks the while loop but will also ignore the relative
>> else.
>>
>>
> I will try to make my doubt clearer:
> if the only way to terminate a 'while True' loop is by using the 'break'
> statement, why is it allowed to add the 'else' statement which will only
> contain dead code?
>
> while True:
> break
> else:
> print('dead code')

Because adjusting the parser for one specific special case is not worth
the effort.
it is not the job of the interpreter to sanitise stupid programming

"Special Cases aren't special enough the break the rules"




--
If you stew apples like cranberries, they taste more like prunes than
rhubarb does.
-- Groucho Marx
--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 12/09/2021 09:11, jak wrote:

> if the only way to terminate a 'while True' loop is by using the 'break'
> statement, why is it allowed to add the 'else' statement which will only
> contain dead code?
>
> while True:
> break
> else:
> print('dead code')
>
Because to the interpreter the condition is not part of the
language. It is syntactically correct.

An optimiser OTOH might welkl determine that the condition
will never fail and therefore the else clause never be reached,
in which case it would remove the dead code (possibly emitting
a warning in the process?).

A linter likewise might identify the redundant code.
I don't use any python linters, does anyone know if they do
detect such dead spots?

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/
http://www.amazon.com/author/alan_gauld
Follow my photo-blog on Flickr at:
http://www.flickr.com/photos/alangauldphotos


--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-11 at 18:21:17 +0100,
Alan Gauld via Python-list <python-list@python.org> wrote:

> On 11/09/2021 15:41, Peter J. Holzer wrote:
>
> > How is C's do/while loop more horrible than Pascal's repeat/until?
>
> Because it is very hard to spot or distinguish from a normal
> while loop.
>
> while condition ;
>
> Is a valid (and fairly common) loop in C
>
> so code that has
>
> do{
> code
> }
> while condition;
>
> Looks, for non-trivial cases, like a lot of code followed
> by an empty while loop.
>
> The do is easy to miss and the while loop disguised as
> a repeat termination is confusing.

Well, yeah, except that only a macro would ever write it that way. :-)

At the very least, the code would be indented (making it easier to spot
the "do," before or after you see the while; and my apologies if you
intended it that way and it got lost somewhere between your intent and
my monitor):

do {
code;
}
while(condition);

(Side question: why put the "{" next to the "do," but the "}" and the
"while" on separate lines?)

And I would put the while on the same line as the closing brace (which
is also where I put the "else" in an if statement):

do {
code;
} while(condition);
--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
The topic of looping and our current discussion stimulates me to ask if
someone has categorized the uses of loops and it seems something obvious.
Once you know what kinds of loopy looping there are, it can get easier to
decide which, if any, of the methods to set up a loop make more sense.

Computer languages differ in all kinds of ways including more subtle ideas
of when a variable is within view or not and that can impact looping
methods.

Years ago, in many languages, loops were used simply to COPY something
stored in some array-like format. Languages like C might have a character
string stored in a null-terminated array and the accepted way to copy it
might be to use pointers called p (the source) and q(the destination) in
weird and compact code like:

while (*q++ = *p++);

Now Python does not have some of those operators but copying strings is
fairly trivial with no visible loops but copying some objects (I mean a new
and even deep copy) can use loops, albeit for many objects, there is a copy
functionality available to do it quietly.

If you only want a subset of the values to be taken into a copy, many
languages have a subletting method like var[1:5] and often you have
functions like map/reduce you can pass things to that return an arbitrary
subset based on applying a function.

Python has thus quite a few ways to hide any loops involved in copying so
you will often not see a WHILE or FOR in sight.

For simple (and even sometimes more complex) scenarios, comprehensions of
many types can be used in in-line situations. Generators can supply what can
amount to a sort of deferred and thus distributed loop that is run
interspersed with other things happening.

One reason many applications bring in add-on modules like numpy and pandas
is because they partially fill some gaps and make many vectorized operations
easy. Any operation that works simultaneously on every member in a way that
has no conflict with calculations on other members is an example. If I have
two vector like objects such as A and B, then being able to write 3*A means
modifying all the elements of A to be triple what they were and it does not
necessarily need to happen in any order or even be all done by the same
process. If A and B are the same length (or logically adjusted to be) then
A+B is similarly a vector operation. Quite a few such things are done
routinely with no loops visible in the code that once littered my C code.
Languages like R (and the original S) were built from the ground up so
everything starts with a vector and even a singleton variable is merely a
vector of length 1. Many programs simply do not need loops as it is done for
you.

I have mentioned ways to use objects in Python as a way to hide loops. Of
course that implies an object may use methods that contain small loops, such
as to search and internal list to see if something is already being held, or
to find the end and append another and so on. But you main program may thus
often be written without such looks.

Functional programming techniques, again, can be used to say apply a
function to every item in a list and collect the results in another list or
scalar. You will not see a WHILE or a FOR but a loop happens.

I have sometimes written a program and then after it was working, took
another look and redesigned it in ways that often shorten it substantially
and even speed it up. I admit people reading the code often have no clue
what it does. So especially for teaching Computer Science, many loops remain
a good place to start.

My guess is that if, like me, you often avoid using loops in trivial cases,
you may end up using them in cases that are more complex. You may end up
with mainly cases where you end up having to BREAK or CONTINUE or RETURN
from within a loop, perhaps with multiple exit points. Some of those cases
may well be much more difficult using the hidden loops.

So I was not in any way being negative with Peter about his admittedly
restricted sample of coding practices, or of others who searched a body of
code by many authors. I am saying that people who write code can evolve and
not go back and change older code.

I once inherited code that had nested loops about 9 units deep. Something
like
for in in ...
for j in ...
for k in ...

It was a tad more complex, of course as it tested all variations of
categorical variables. There were additional loops in selected places within
there, as well. It ran slowly in interpreted form. What I ended up doing was
generating a data structure (a data.frame) that contained all combinations
and handed that to a function called pmap that did one row at a time by
setting variables. The problem became way more tractable and quite a bit
faster. And, in this case, I suspect it may have been more readable without
getting lost in all the nesting.

But not all languages and problems are amenable to some approaches, and some
play games with how variables are kept and used. Python has some nice
features that allow a single loop to replace more complex arrangements by
say allowing multiple variables to be instantiated each time around so
something like my deeply nested version can be run in a straightforward way.

I suspect in many cases, a little though of what to feed a loop might be a
great way to simplify the innards of the loop and minimize some of the
concerns about multiple exit methods and so on. But you can add bells and
whistles like the ELSE clause but not get many to actually use it as there
are more standard ways to do that without confusion, especially if it is
confusing to some.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Peter J. Holzer
Sent: Sunday, September 12, 2021 5:44 AM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 2021-09-11 21:38:02 -0400, Avi Gross via Python-list wrote:
> Peter, in your own personal finite sample, I am wondering what you
> might do TODAY if you looked at your loops again and considered
> redoing them for an assortment of reasons ranging from using the code
> for teaching to efficiency to just fitting your mood better?
>
> I have seen seasoned authors go back to their early work and groan.

Yeah, I do that. (Un)fortunately I also have other people's code to groan
about so I won't despair too much about the stupidity of my younger self.


> My guess is that many of us (meaning myself included) often approach a
> problem and go with the first thing that comes to mind. If it fits
> well enough, we move on to the next thing we can do. If not, we may
> step back and evaluate multiple additional options and try another tack.
>
> I have seen not of sort-of redundant code because someone did not plan
> ahead and realize something very similar might be needed later and
> thus did not make a general function they could re-use. Occasionally
> they may later go back and re-do but often, not so much and just keep
> copying lines and making minor modifications. Same general idea.

That certainly happens. I am a bit overly conservative and try to get away
with minimal code changes even if a complete reimplementation of that unit
would be clearly better. Especially if it's someone else's code and there
are no unit tests. But also for my own code.

(As an aside, I notice the same tendency when changing text: Altering an
existing paragraph is hard, especially if someone else wrote it. Also, while
I think I can express myself quite clearly in both German and English, I'm
rarely satisfied when I try to translate between those languages. I always
stick too close to the original).

> And perhaps worse, you may write a loop and later have to keep adding
> code to deal with new requirements and special cases and rather than
> pause and analyze and perhaps start again with a cleaner or more
> easily extendable solution, just keep grafting on things to make the darn
current code work.
> Code that has many ways to exit a loop is often an example of this
> happening.

That too. Those little C utilities I mentioned are probably a bad example
because they are so small and had little reason to evolve. But I do have
Perl scripts which I originally wrote 20 years ago and which are still in
use and have been adapted to changing business requirements again and again
in that time. Those do contain some gnarly code.


> So if you looked at your own code now, in the context of the rest of
> your code, would you change things?

Almost certainly. Especially in C I would probably be more cautious about
undefined behaviour now and for different reasons. Back in the 90's I mostly
worried about portability: That code could one day run on a 36-bit
ones-complement machine with 9-bit chars. These I days I worry more about
overly aggressive optimizations: That pointer is accessed here so it can't
be null, so it can't be null here either so that check can be optimized
away.

I started using Python only 7 years ago, when I had already been using Perl
for almost 20 and C for over 25 years. So my older Python code probably
looks a bit "perly". So they use dicts and map and filter but not list
comprehensions for example. Also some of that code was partially inherited
from other Python programmers who adhered to the "a real programmer can
write Fortran in any language" mindset.


> So when counting the various kinds, are you looking for direct or
> indirect methods too like map/reduce or vectorized operations?

No, because that wasn't the question I was trying to answer. The question
was "do people use do/while loops frequently in languages which provide
them"? I chose C (mostly because it is easier to get useful numbers with
tools like grep and wc than with Perl) and therefore only the types of loops
available in C. (Methodically the main flaw in my approach is that I only
looked at a single language and a single person and only a tinly sample from
that person. To really answer that question you would have to look at a
sizable sample from Github or something like that).

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"

--
https://mail.python.org/mailman/listinfo/python-list
RE: Friday Finking: Contorted loops [ In reply to ]
Stefan,

Agreed that writing code to handle all possible eventualities is usually
overkill and results in bloated software delivered very late or not at all.

My point is that often OTHERS start adding requests afterward that seem
trivial to THEM as they have no idea what it takes. I have often done some
kind of data analysis for someone and made a few graphs and suddenly they
ask if I can add something else to the graph such as a few horizontal lines
showing where a danger zone lies, or some kind of average. No problem but to
do that means the new info has to have been made available or can be
calculated and often even means my function needs to take more arguments or
a wider data.frame. Then they reconsider and ask if instead of a line, can I
color the background above that point. Well, yeah, but now I might need to
calculate another column to use to guide that feature. Ah, but can you show
a series of related such graphs as a unit, or perhaps combine several
unrelated graphs in a 3 by 2 matrix. Argh! Sure, I can do that but you did
not ask me to before I started. I now might toss out much of my original
code and rewrite something so all the things needed are made first and then
the graphs are made and recombined in the right output format. This means
that what used to make a graph will now make a data structure to return that
can be used later to recombine into a bigger consolidated graphic.

Does the story end here? Nope. Tons more requests like removing color and
using shades of gray or dotted lines so it can be printed on any printer,
changing the point size of text and other characteristics and introduce
mathematical symbols and equations along the axes and I swear an amazing
number of such fine tunings including taking a series of these things into
one multi-page PDF.

If this was a paid gig and someone offered me a fixed sum, should I tolerate
almost any changes? If this was a regular paid job and this made me late and
not get other things done?

My bottom line is that it may not be reasonable to make a detailed top-down
design and stock with it BUT that code written by ever-changing requirements
can end up badly too. I shudder at times I wrote decent code full of
comments explaining well and a while later had a mess where the comments
lagged behind changes in the code as there was no point in bothering to
update them unless it stopped changing. And, often, by then, I was no longer
interested in spending any more time and sometimes just removed all the
comments and moved on! Good luck to anyone coming along to maintain or
improve the code.

I have to think about when to make a function. Something trivial is often
not worth is. And making a very abstract function that can do a dozen things
if invoked just right with many arguments is sometimes a tad too much when a
few simpler functions might do as well with less overhead and especially
when the uses have fairly little in common. Some languages may discourage
you if the repeated code needs to do things in the current environment and
thus only part of the functionality can be moved away.


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Stefan Ram
Sent: Saturday, September 11, 2021 10:56 PM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

"Avi Gross" <avigross@verizon.net> writes:
>I have seen not of sort-of redundant code because someone did not plan
>ahead

From my experience, the "plan ahead" approach (waterfall model)
often is less applicable than the "code is design" (Reeve) +
"refactoring" (Fowler) approach. (However, in some fields, planning
ahead is a requirement).

>and realize something very similar might be needed later and thus did
>not make a general function they could re-use. Occasionally they may
>later go back and re-do but often, not so much and just keep copying
>lines and making minor modifications. Same general idea.

I remember having read a discussion in the Web.
The question was something like:

How many times do you have to write a piece of code,
before you create a function for it?

I believe I still remember two answers:

- One time.

- Three times.

The justification I can't remember, but what I would come up
with now would be:

(for "one time":) Functions structure your code. You don't have
to wait for repetitions as an "excuse" to create them.

(for "three times:) Relax. Don't overengineer. You need to have
at least /three/ repetitions to be able to see a clear pattern.


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

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-12 10:28:22 -0700, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> On 2021-09-11 at 18:21:17 +0100,
> Alan Gauld via Python-list <python-list@python.org> wrote:
> > On 11/09/2021 15:41, Peter J. Holzer wrote:
> > > How is C's do/while loop more horrible than Pascal's repeat/until?
[...]
> > so code that has
> >
> > do{
> > code
> > }
> > while condition;
> >
> > Looks, for non-trivial cases, like a lot of code followed
> > by an empty while loop.
> >
> > The do is easy to miss and the while loop disguised as
> > a repeat termination is confusing.
[...]
> (Side question: why put the "{" next to the "do," but the "}" and the
> "while" on separate lines?)
>
> And I would put the while on the same line as the closing brace (which
> is also where I put the "else" in an if statement):
>
> do {
> code;
> } while(condition);

Me too.

I also checked two C books from "?e olde times" (K&R, 1st editiion,
German translation; and "A Book on C" by Kelley/Pohl) and both nestle the
while on the same line as the closing brace.

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
RE: Friday Finking: Contorted loops [ In reply to ]
Some of what I read makes me chuckle.

Yes, large units of code, and even smaller ones, may be a chore to figure
out. Arguably harder when you use indentation and the next/last parts are
not even on the same screen as the rest. Sometimes you want to use a
split-screen in some editor to line up the two parts or some other
technique.

But my suggestion is to COMMENT things well and I mean too much!

do {
<CODE>
} while <COND>

Why not add a comment at the top like:

# The following loop has a WHILE clause controlling it at the end.

do { # until the while clause below
<CODE>
} while <COND> # End of the do loop.

My code tends to have brief comments especially when I have nested
constructs such as multiple nested loops or in sequence, or if statements
inside others. The comment often looks like

... # END of inner if

... # END of outer if

The point is that places where the way of writing a program may not be as
obvious as you want, may be the places you comment to make up for that.

Do people read the comments? Are they extra verbiage or in the way? Who
knows. And, of course, as I noted earlier, it is one more thing that gets in
the way.

There are languages which allow you to add some kind of labels in the code
and you can label a loop with something like "doo_wop:" and inside a nested
loop, you can break or continue to the named label and thus jump out
multiple levels if needed. The point is not to have that feature, but
perhaps have an option like:

do label {
code
} label while ...

Something that uniquely allows you to associate the end of the loop right
next to the end. Since the label can be anything allowed, it could by
something that suggest it is a while loop.

I appreciate programming environments that let you do complex, often nested,
things. But with great power can come great responsibility to use it well
and make sure others can figure it out.


-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Peter J. Holzer
Sent: Sunday, September 12, 2021 4:49 PM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 2021-09-12 10:28:22 -0700, 2QdxY4RzWzUUiLuE@potatochowder.com wrote:
> On 2021-09-11 at 18:21:17 +0100,
> Alan Gauld via Python-list <python-list@python.org> wrote:
> > On 11/09/2021 15:41, Peter J. Holzer wrote:
> > > How is C's do/while loop more horrible than Pascal's repeat/until?
[...]
> > so code that has
> >
> > do{
> > code
> > }
> > while condition;
> >
> > Looks, for non-trivial cases, like a lot of code followed by an
> > empty while loop.
> >
> > The do is easy to miss and the while loop disguised as a repeat
> > termination is confusing.
[...]
> (Side question: why put the "{" next to the "do," but the "}" and the
> "while" on separate lines?)
>
> And I would put the while on the same line as the closing brace (which
> is also where I put the "else" in an if statement):
>
> do {
> code;
> } while(condition);

Me too.

I also checked two C books from "?e olde times" (K&R, 1st editiion, German
translation; and "A Book on C" by Kelley/Pohl) and both nestle the while on
the same line as the closing brace.

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"

--
https://mail.python.org/mailman/listinfo/python-list
Re: Friday Finking: Contorted loops [ In reply to ]
On 2021-09-12 17:11:58 -0400, Avi Gross via Python-list wrote:
> Yes, large units of code, and even smaller ones, may be a chore to figure
> out. Arguably harder when you use indentation and the next/last parts are
> not even on the same screen as the rest. Sometimes you want to use a
> split-screen in some editor to line up the two parts or some other
> technique.
>
> But my suggestion is to COMMENT things well and I mean too much!
>
> do {
> <CODE>
> } while <COND>
>
> Why not add a comment at the top like:
>
> # The following loop has a WHILE clause controlling it at the end.
>
> do { # until the while clause below
> <CODE>
> } while <COND> # End of the do loop.

Because those comments don't tell me anything that I as a C programmer
don't already know. Even though do/while loops are relatively rare, I've
seen hundreds of them. Seeing "do {" and recognizing it as the top of a
do/while loop takes absolutely no conscious thought - reading a comment
does.

> My code tends to have brief comments especially when I have nested
> constructs such as multiple nested loops or in sequence, or if statements
> inside others. The comment often looks like
>
> ... # END of inner if
>
> ... # END of outer if

Those are a bit better, but they still don't help much. What is the
"inner if", what is the "outer if"? Chances are that I have to find the
corresponding if to find out - I can do that without a comment, too.

There are end-of-construct comments which I do find useful (at least
occasionally) but those are semantic.

Imagine a somewhat longish function which read several files which are
comprised of records which are comprised of field.

for file in files:

some setup for each file here

for record in file:

some setup for each record here

for field in record:

process field

do some postprocessing for the record

do some postprocessing for the file

If each of these blocks is longer than a few lines you might lose track
where you are, so some comments might help:

for file in files:

some setup for each file here

for record in file:

some setup for each record here

for field in record:

process field

# end of field loop

do some postprocessing for the record

# end of record loop

do some postprocessing for the file

# end of file loop


Note that the comments say which part of the input the loop is
processing, not just that it is the end of a loop or "the outer loop",
"the intermediate loop" and "the inner loop" or some other purely
syntactic information.

(In most cases I would just break up such a function into smaller
functions instead of adding comments, though)

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"
RE: Friday Finking: Contorted loops [ In reply to ]
Peter,

Choosong when and how to comment is an invidual thing and certainly the
interpreter does not care.

Yes, I gave an example where my comment used inner/outer as the words but
more often I am more explicit along the lines you mention. Sometimes I
include most of the text into the comment such as
if x <10 {
... MANY LINES
} # END if x <10

But please understand the goal is many fold. One simple goal is that by
having to comment the code, you sort of have to explain it to yourself and
use the opportunity to see if it makes sense and matches any requirements or
perhaps even adds new functionality not already documented.

Secondarily, it is for you to read much later when returning to the code to
refresh your memory.

In many organizations, including where I worked, there can be levels of code
review that work better if others have a clue what they are reviewing or
why.

And of course, others often take over your code or examine it.

At one point I was doing field support on a project, way back when it meant
something to carry a beeper. I had written some of the code but the vast
majority was done by others on the team. When I got beeped at 3 AM from a
place like Japan, I often had to make rapid decisions on how big a problem
was and whether I should wake someone up, including developers and their
management or even rarely upper management. I often dove into the code to
find the likely locus of a problem and even to see if I could spot the place
that might be patched. That often let me wake up the right person and work
with them to expedite an emergency change. Even in less chaotic or major
times, I had to work with getting a problem acknowledged and scheduled for
inclusion in a future release. Being able to read all kinds of source code
and figuring it out quickly was important and sometimes comments were
helpful. In particular, some people did not need to be woken up if I was
able to see the problem was not in their code!

Comments do often have a rather weird purpose. Sometimes we collected
metrics on how many lines of code were new or changed between releases and
unless the tools removed comments, ...

But I have found over the years that too many comments are badly done. For
example, rather than ending every line of a function definition with all
kinds of things that clutter things, it is often better to place a few block
comments above a function definition explaining the general purpose of the
function, what inputs are expected on the command line, what assumptions are
made about them, whether it uses any other resources (including dreaded
global variables) and what it returns or what errors it may generate and so
on. You can also discuss the overall idea of how the function does the job.
Then, within the function, you can have smaller mainly one-liners like:
# This section checks if the variables are all within expected bounds.
...
# Combine ...
...
# quit if not satisfied
...
# Make the changes requested.
...
# return successfully with a structure holding ...
...

Again individual taste. My personal commenting style has evolved and varies
from language to language. In many cases, I have used well-chosen variable
names that are meaningful to me but not keywords. Sadly for some others, I
sometimes choose variable names in other human languages, sometimes
transliterated as sticking to ASCII requires. Most people are not able to
even guess, so say commenting in Hungarian or German or Hebrew may only be
of use to me and other weird people.

I do find that for frequent enough usage of something, such as an object
like a deque, you get to know it so well that you may stop commenting on how
you are using some built-in feature as it seems routine.

-----Original Message-----
From: Python-list <python-list-bounces+avigross=verizon.net@python.org> On
Behalf Of Peter J. Holzer
Sent: Monday, September 13, 2021 3:28 PM
To: python-list@python.org
Subject: Re: Friday Finking: Contorted loops

On 2021-09-12 17:11:58 -0400, Avi Gross via Python-list wrote:
> Yes, large units of code, and even smaller ones, may be a chore to
> figure out. Arguably harder when you use indentation and the next/last
> parts are not even on the same screen as the rest. Sometimes you want
> to use a split-screen in some editor to line up the two parts or some
> other technique.
>
> But my suggestion is to COMMENT things well and I mean too much!
>
> do {
> <CODE>
> } while <COND>
>
> Why not add a comment at the top like:
>
> # The following loop has a WHILE clause controlling it at the end.
>
> do { # until the while clause below
> <CODE>
> } while <COND> # End of the do loop.

Because those comments don't tell me anything that I as a C programmer don't
already know. Even though do/while loops are relatively rare, I've seen
hundreds of them. Seeing "do {" and recognizing it as the top of a do/while
loop takes absolutely no conscious thought - reading a comment does.

> My code tends to have brief comments especially when I have nested
> constructs such as multiple nested loops or in sequence, or if
> statements inside others. The comment often looks like
>
> ... # END of inner if
>
> ... # END of outer if

Those are a bit better, but they still don't help much. What is the "inner
if", what is the "outer if"? Chances are that I have to find the
corresponding if to find out - I can do that without a comment, too.

There are end-of-construct comments which I do find useful (at least
occasionally) but those are semantic.

Imagine a somewhat longish function which read several files which are
comprised of records which are comprised of field.

for file in files:

some setup for each file here

for record in file:

some setup for each record here

for field in record:

process field

do some postprocessing for the record

do some postprocessing for the file

If each of these blocks is longer than a few lines you might lose track
where you are, so some comments might help:

for file in files:

some setup for each file here

for record in file:

some setup for each record here

for field in record:

process field

# end of field loop

do some postprocessing for the record

# end of record loop

do some postprocessing for the file

# end of file loop


Note that the comments say which part of the input the loop is processing,
not just that it is the end of a loop or "the outer loop", "the intermediate
loop" and "the inner loop" or some other purely syntactic information.

(In most cases I would just break up such a function into smaller functions
instead of adding comments, though)

hp

--
_ | Peter J. Holzer | Story must make more sense than reality.
|_|_) | |
| | | hjp@hjp.at | -- Charles Stross, "Creative writing
__/ | http://www.hjp.at/ | challenge!"

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