On Fri, 27 Nov 2020 00:25:21 +1100 Steven D'Aprano email@example.com wrote:
On Thu, Nov 26, 2020 at 02:11:10PM +0300, Paul Sokolovsky wrote:
Using "let" will then give natural way to introduce proper block-level lexical scoping in Python:
Why would we want to do that?
Because without that, when you're doing something simple like turning:
foo.bar1 = bar.bar1.bar2.bar3
# We know that Python doesn't do CSE, and don't want to evaluate # bar.bar1.bar2.bar3 twice, so we cache it in a temporary a = bar.bar1.bar2.bar3 foo.bar1 = a func(a)
- you're in constant fear that some another guy already did something similar before, and you're overwriting "a" (or whatever other good name you (or they) have come up with, like "i", "tmp", etc.).
And of course, that's not just your fears, you heard other fellow programmers talking about it too. The closest one is right higher in this thread: https://firstname.lastname@example.org/message/VKHB72...
Quite for you:
"Even if the helper has nothing to do with the loop and just uses the same generic variable name like "item", it'll break. It's fairly common to reuse the same identifier for different purposes inside functions."
Block-level scoping is too much of a good thing. The right level of scoping is the function, not the block.
This is getting old. It's neither practical nor realistic to refactor each breadcrumb (or vice-versa jumbo written by somebody too respected to teach them about a suggested function size) to a function. A trivial fan-out assignment above is a good example.
(I'm willing to accept at least one exception to this, comprehensions.)
Please meet me on the other side of the rainbow, where what we previously saw as an exception, is actually first shy, blindfolded steps to resolve the general underlying issue.
Block scoping adds complexity to the implementation *and* the semantics of code.
Python already has lexical scoping for functions, extending it to blocks within functions is something a notch above trivial. Semantics of the language re: scoping remains the same. Semantics of the actual code written using it improves, as it allows to reason more locally about how a variable is used.
Block scoping allows shadowing within a function. Some C-derived languages, such as Java and C#, considered that a big enough mistake that they corrected it by requiring variables within a block to be distinct from the variables outside of the block, which is conceptually weird.
Sorry, this is MISRA-style disinformation (https://en.wikipedia.org/wiki/MISRA_C#Criticism). Some adhoc, narrow-use, narrow-purpose codestyles indeed disallow shadowing of variable names. Otherwise, lexical scoping of name bindings is fundamental concept of the computation theory and practice.
The point of scoping is that variables in one scope should be independent of those in another scope, yet here we have this action at a distance where names in one scope can prevent you from using the same name in a different scope.
It's all the same as already for functions in Python. Again, doing it block-level allows for more local, more precise reasoning (e.g. if you declared a let-variable, you know you don't overwrite anything else).
Python does have one example of a pseudo-block scope: the treatment of the except variable:
try: ... except Exception as err: ...
Python does have one example of pseudo-block scope, then a few example of truly block (well, expression!) level scope (similarly implemented in hacky way), and sooner or later will get proper, generic block-level scope. The sooner the better of course. Let the usual denial/anger/bargaining/depression/acceptance cycle begin.
(With pattern matching, we're at bargaining stage, don't you think? Actually, looking at https://discuss.python.org/t/gauging-sentiment-on-pattern-matching/5770 , maybe it's depression.)
Is there a shortage of variable names that you have to reuse the same name "x" for two distinct variables?
But that's the whole point - I (and other people) don't want to know whether it's used 2nd, 3rd, or hundredth time. We want to use it as a generic variable in a very limited scope, knowing that it won't affect semantics of the rest of a program.
I know that "naming things" is classically one of the hard problems of computer science, but this is taking things to an extreme.
Not only hard, but also largely solved. That's why it's easy to predict that Python will get block-scoped things sooner or later (heck, it does, as we know). Saying otherwise is the same as saying "Python will forever lag behind other languages and will plug glaring conceptual holes with hilarious means like IDEs, etc." It's "Thanks but no" from me to such a perspective.