[Python-ideas] Inline assignments using "given" clauses
Brendan Barnwell
brenbarn at brenbarn.net
Fri May 11 14:08:41 EDT 2018
On 2018-05-11 09:17, Steven D'Aprano wrote:
> Much earlier in the PEP 572 discussion, I strongly argued in favour
> of the
>
> expr as name
>
> syntax on the basis that the most important part of the overall
> expression is "expr", not the assignment target, and therefore that
> should come first. Even though I have accepted that "as" is not viable,
> I still believe that it is preferable to have the expression first, or
> if not first, at least as close to the left as we can get it.
>
> This "given" syntax puts the expr part all the way to the far right of
> the line. A line which is made all the longer for needing to use "given"
> and redundantly state the target name.
>
> It's like we're trying to maximize the distance the eye has to travel
> back and forth when reading.
>
> I have to read to the end of the line before I have any idea where cmd
> has come from or what it is. The fact that it comes from a "given"
> expression comes as a surprise at the end of the line.
>
> Now obviously this doesn't matter if I'm reading lines of code in
> careful detail, but I don't do that all the time. I skim code far more
> than I read it in careful detail, and the closer things are to the left,
> the more likely I am to see them while skimming. The further out they
> are, the easier they are to miss.
>
> I think that "given" will*literally* make reading harder, in that the
> eye has to travel further to spot the relevant expression while skimming
> over code. As I said, I don't think it makes any difference when reading
> closely in detail. But most of my reading of code is skimming to find
> the relevant line or section, and then read closely. I would probably
> skim a hundred lines for every one I read closely.
That is an interesting argument --- interesting to me because I agree
with a lot of it, but it leads me to the opposite conclusion, and also
because it highlights some of the relevant factors for me.
The main part I disagree with is that the most important thing is the
definition of expr. Rather, what I think is most important is the role
of expr within the surrounding expression. For simple cases, it doesn't
much matter which comes first:
if x := do_some_stuff():
if x where x = do_some_stuff():
. . . and it's true the latter is a bit more verbose in that case for
little extra benefit. But when the locally-defined value is used within
a more complicated expression (like the quadratic formula example), I
think readability goes down significantly. To appease Tim, instead of
using the quadratic formula, though, I will use a more realistic example
that comes up fairly often for me: wanting to do some kind of
normalization on a piece of data for a comparison, while keeping the
unnormalized data for use within the block:
if some_condition and (stuff:=
get_user_input()).lower().strip().replace('-', ''):
versus
if some_condition and stuff.lower().strip().replace('-', '') given
stuff = get_user_input():
Now, the latter is still more verbose. But to me it is now more
readable, because the assignment does not disrupt the flow of reading
the surrounding expression. This benefit increases the more complicated
the surrounding expression is.
Your point about reading ease is well taken, but also relevant to me is
that we only read a piece of code *for the first time* once. The
advantage of the given-style assignment is that on multiple readings, it
foregrounds how the assigned value is USED, not how it is DEFINED. This
encourages a "top-down" understanding of the expression in which you
first understand the overall picture, and then later "drill down" into
definition of what the components are.
I wonder if some of the disagreement about the relative merits of the
two cases comes from people focusing on different kinds of examples. As
I said, I think the advantages of "cleft assignment" (i.e., where the
assignment is shunted to the end of the line) become more pronounced as
the surrounding expression becomes more complex. They also become
somewhat greater as the definition of the expression becomes more
complex, because there is more to skip over when finding out how the
value is used. But many of the examples we're seeing are very simple
ones, and in particular have a trivial surrounding expression. (That
is, in something like "m := re.match()" the assigned value is not being
used in any larger expression; the assigned value constitutes the whole
of the expression.)
I'm also finding it useful to think of parallel situations in prose
writing, particularly journalistic-style prose writing. The current
Python behavior, in which assignments must be done before the block, I
think of as akin to something like this:
"The IAAEA (International Association of Assignment Expression
Advocates) is an organization dedicated to the promotion of assignment
expressions. Its president is Eddie McEquals. In a statement
yesterday, McEquals called for a new syntax to bring assignment
expressions to the masses."
The inline-assignment syntax is akin to this:
In a statement yesterday, Eddie McEquals, president of the International
Association of Assignment Expression Advocates (IAAEA), an organization
dedicated to the promotion of assignment expressions, called for a new
syntax to bring assignment expressions to the masses.
The cleft-assignment syntax is akin to this:
In a statement yesterday, Eddie McEquals called for a new syntax to
bring assignment expressions to the masses. McEquals is the president
of the International Association of Assignment Expression Advocates
(IAAEA), which is an organization dedicated to the promotion of
assignment expressions.
Now of course I'm fudging a bit on the details (like whether you have
IAAEA in parentheses or its full expansion), but the point is that the
last version foregrounds the "bottom line" or "predicate" --- what
actually happened. The first one foregrounds the "participants", or
who/what was involved, and saves what actually happened for the end.
But the middle one, to my eye, foregrounds nothing. It stuffs
everything into one big clause where the descriptions of the
participants occur as asides that disrupt the flow of reading. By the
time we get to the predicate, we have to jump back to the beginning to
remember who it is we're talking about,
Again, the difference in readability varies depending on the complexity
of the different components. If we just have "Eddie McEquals, president
of the International Association of Assignment Expression advocates,
delivered a speech yesterday at the organization's convention", the
inline appositive is not so disruptive. But the more complex the inline
definitions become, and especially the more complex the expression in
which they are embedded, the lower readability goes, for me.
--
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is no
path, and leave a trail."
--author unknown
More information about the Python-ideas
mailing list