On 04/26/2018 12:12 PM, Tim Peters wrote:
[Larry Hastings <larry@hastings.org>]
I hate to be pedantic--there's enough of that going on in this thread--but I
can't agree with the word "simplifed" above.  I agree that the code using
binding expressions is shorter.  But considering that emit the two code
examples implement the exact same algorithm, to the point where their
bytecode would look nearly* identical, ISTM that the two code examples are
of identical complexity.
In the absence of defining an objectively computable complexity
measure,  I expect you're doomed to arguing taste.

As are you!  I haven't seen any arguments that binding expressions allow us to express programs that were inexpressible in Python before.  I'm not even sure that binding expressions fall under the heading of "syntactic sugar", given their negligible semantics (and, imo, negligible benefit).  What else is left, on both sides of the debate, if not a debate over aesthetics?


  For example, argue
that both spellings have the same formal "cyclomatic complexity"
measure (which they do).  By other formal measures (e.g., total number
of identifier instances), the latter spelling is "objectively
simpler".  By yet others (e.g., total number of non-whitespace
characters divided by total number of lines), the former spelling is
"objectively simpler".

What is this "objective simplicity" measurement you cite?  I understand that the code example cited had fewer identifiers, so when measuring "number of identifiers used" in isolation, the code example using binding expressions had fewer of them.  But this is so narrow as to be almost meaningless.

Perhaps I'm misunderstanding you, but I read this as saying that there's a larger, well-established concept called "objective simplicity", of which this measurement is a part.  Can you tell me more about it?  Google was no help here.


But that all kinda misses the point to me:  the latter spelling is
"obviously simpler" in a way that _actually matters_, for the same
reason, e.g., a case statement with N cases is "obviously simpler"
than the semantically equivalent spelling using N nested if/else
if/else if/else if/else ... blocks.

As I already mentioned, the with-binding-expressions code expresses the same code, the same concept, and likely results in the same bytecode, as the without-binding-expressions code.  In contrast, a switch statement is simpler than a series of nested if statements.  It's a different code construct, it has different (and comparatively restricted) semantics, and it results in simpler (and faster) code.  Whereas the with-binding-expressions code is equivalent to the without-binding-expressions code, semantically, bytecode-ly, etc.  So comparing the with-binding-expressions version of the code to the simplification afforded by a switch statement isn't an apples-to-apples comparison.

In other words: you're really only arguing taste here.  You find it "obviously simpler", but this an aesthetic call on your part and not an objective measurement.  Me, my tastes are different--I find it "needlessly complicated" and prefer the without-binding-expressions version.


If it weren't for that you hate being pedantic, I'd add that you're
overlooking the piles of leading whitespace characters also saved in
the latter ;-)  The number of those saved grows quadratically in the
number of uselessly indented blocks shifted left.

Surely my dislike of being pedantic is irrelevant to your being pedantic.  It seems it's not something you mind doing! ;-)

The nightmare scenario of quadratically right-shifted code is of course solvable in other ways.  Off the top of my head, one could rewrite the code example as follows, without any new syntax:
    def r(value):
        nonlocal reductor
        reductor = value
        return value
    if r(dispatch_table.get(cls)):
        rv = reductor(x)
    elif r(getattr(x, "__reduce_ex__", None)):
        rv = reductor(4)
    elif r(getattr(x, "__reduce__", None)):
        rv = reductor()
    else:
        raise Error("un(shallow)copyable object of type %s" % cls)

It makes this particular code example longer--however it avoids the indenting you seem to dislike.  However: given that "r()" is shorter than "reductor := ", the more elifs you add, the more overall characters you'll save!  With another three or four elifs this version would probably use fewer characters overall.

I'm not seriously arguing that people rewrite their code in this way; I think it's less clear this way.  I suppose my point is, "we already have so many ways To Do It, I'm not in favor of adding syntax to the language to add one more way".


and the density of complexity per line has shot up.
Average non-whitespace character count per line has certainly shot up,
but I don't actually know what you mean by "density of complexity"
there.

What I meant was, stuff-accomplished-per-line.  I guess we could measure that objectively as bytecodes / linecount.  But I meant it more as a subjective measurement, considering factors like "how many unrelated operations occur on this line?" and "how many operations on this line have side-effects?".  I suggest that the with-binding-expressions version has more side effects and more unrelated operations per line, because several lines now fold assignment (side effect) into lines that were previously flow control.


/arry