[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