On 20 April 2018 at 07:46, Chris Angelico <ros...@gmail.com> wrote:
> On Fri, Apr 20, 2018 at 1:30 PM, Stephen J. Turnbull
> <turnbull.stephen...@u.tsukuba.ac.jp> wrote:
>> Christoph Groth writes:
>>  > Wouldn't it be a pity not to liberate assignments from their boring
>>  > statement existence?
>> Maybe not.  While it would be nice to solve the loop-and-a-half
>> "problem" and the loop variable initialization "problem" (not everyone
>> agrees these are even problems, especially now that we have
>> comprehensions and generator expressions), as a matter of taste I like
>> the fact that this particular class of side effects is given weighty
>> statement syntax rather than more lightweight expression syntax.
>> That is, I find statement syntax more readable.
> If you've read the PEP, you'll see that it encourages the use of
> assignment statements whereever possible. If statement syntax is
> generally more readable, by all means, use it. That doesn't mean there
> aren't situations where the expression syntax is FAR more readable.
> Tell me, is this "more readable" than a loop with an actual condition in it?
> def sqrt(n):
>     guess, nextguess = 1, n
>     while True:
>         if math.isclose(guess, nextguess): return guess
>         guess = nextguess
>         nextguess = n / guess
> Readable doesn't mean "corresponds closely to its disassembly",
> despite the way many people throw the word around. It also doesn't
> mean  "code I like", as opposed to "code I don't like". The words for
> those concepts are "strongly typed" and "dynamically typed", as have
> been demonstrated through MANY online discussions. (But I digress.)
> Readable code is code which expresses an algorithm, expresses the
> programmer's intent. It adequately demonstrates something at a
> *higher* abstraction level. Does the algorithm demonstrated here
> include an infinite loop? No? Then it shouldn't have "while True:" in
> it.

Thanks Chris - this is a very good explanation of how we can
(somewhat) objectively look at "readability", and not one I'd really
considered before. It's also an extremely good argument (IMO) that the
loop-and-a-half construct would benefit from improvement.

In my opinion, it's only partially related to the assignment
expression discussion, though. Yes, assignment expressions "solve" the
loop-and-a-half situation. I'm unsure how *much* I like the look of
the resulting code, but I concede that's a "code I like" vs "code I
don't like" situation. But assignment expressions are much more
general than that, and as a general construct, they should be
evaluated based on how many problems like this they solve, and whether
the downsides justify it. We've already had the comprehension use case
marginalised as no longer being a key use case for the proposal,
because they weren't as "obviously" improved as some people had hoped.
So overall, I think assignment expressions have proved to be a bit
useful in some cases, and less so in others.

Clearly any proposal can be picked to death with enough time to look
for flaws. And part of the Zen is "Now is better than never". But I
think in this case, "Although never is often better than *right* now"
applies - we've had some very productive discussions, and you've done
an incredible job of managing them and capturing the results, but it
feels to me that the overall result is that there's likely a better
solution still out there, that needs a new intuition to solve.

> Now, this is a pretty obvious example. I deliberately wrote it so you
> could simply lift the condition straight into the while header. And I
> hope that everyone here agrees that this would be an improvement:
> def sqrt(n):
>     guess, nextguess = 1, n
>     while not math.isclose(guess, nextguess):
>         guess = nextguess
>         nextguess = n / guess
>     return guess
> But what if the condition were more complicated?
> def read_document(file):
>     doc = ""
>     while (token := file.get_next_token()) != "END":
>         doc += token
>     return doc
> The loop condition is "while the token is not END", or "while
> get_next_token() doesn't return END", depending on your point of view.
> Is it "more readable" to put that condition into the while header, or
> to use an infinite loop and a break statement, or to duplicate a line
> of code before the loop and at the bottom of the loop? Which one best
> expresses the programmer's intention?

The version that captures the value and tests it. I agree completely
here. But we do have other options:

def read_document(file):
    doc = ""
    for token in token_stream(file, terminator="END"):
        doc += token
    return doc

(This point about rewriting to use for and an iterator applies to
Chris Barker's fp.readline() example as well).

Sure, token_stream might need a loop-and-a-half internally[1]. But
from the user's point of view that's "low level" code, so not so
important (ultimately, this is all about abstracting intent). And
people maybe aren't used to writing "helper" iterators quite this
freely, but that's a matter of education. So agreed - assignment
expressions help with loop-and-a-half constructs. But we have other
ways of dealing with them, so that's a relatively manageable

It's *still* all about cost-benefit trade-offs, with no clear winner
(in my view).


[1] Although actually not - in *this* case, iter(file.get_next_token,
'END') is exactly what you need. But I concede that it's possible to
demonstrate examples where that isn't the case.
Python-Dev mailing list

Reply via email to