On Fri, Nov 27, 2020 at 01:05:45AM +1100, Chris Angelico wrote:
On Fri, Nov 27, 2020 at 12:28 AM Steven D'Aprano email@example.com wrote:
Block scoping adds semantic and implementation complexity and annoyance, while giving very little benefit. No thank you.
Is there a shortage of variable names that you have to reuse the same name "x" for two distinct variables?
I know that "naming things" is classically one of the hard problems of computer science, but this is taking things to an extreme.
I spy the Blub Paradox here. Since you don't use lexical scoping,
Um, actually I do use lexical scoping :-) Most languages, including Python, use lexical scoping :-)
I think you mean *block* scoping, as opposed to function scoping.
It's true that I don't often use block scoping, but come on Chris, this is *me* you are talking too. Do you really think I'm a knee-jerk Blubbite? :-) If anything, I sometimes have to struggle against the opposite tendency, the desire to shoe-horn arbitrary language features and paradigms into the language because they would be cool.
(Thunks. I want thunks. I don't care what they get used for, or how they are spelled, or what they do, so long as I can say "Python has thunks".)
it can be used to make code much clearer and easier to reason about, because - quite the contrary to what you're saying here - you can use distinct variable names, and have a guarantee that the variable can't be misused outside of its intended scope.
You say that as if you are coding in a hostile environment where your nemesis is sneaking around deliberately re-using (*misusing*) your variables after you have finished with them.
You know how Python doesn't have constants? And we say, or at least we said, "if you don't want to re-bind a name, just *don't re-bind it*"?
Surely the same applies to within a function. If you bind a value to a name inside a loop:
for x in seq: y = expression
and you don't want to re-use y outside of that loop, just don't re-use it. As I said in a previous post, if your variable names are so generic that they can be re-used, or your code so large and complicated that you might accidentally re-use a name, the problem isn't the lack of block scopes, the problem is your excessively complicated function and rubbish variable names.
Now Chris, I do get it. In the universe of an effectively infinite number of computer programs, I daresay that there are one or two where there is a specific name that needs to represent two different things at the same time, without forcing them into separate functions:
bow = Ribbon(colour='yellow') tie(bow, old_oak_tree) for archer in troop: let bow = get_weapon() archer.take(bow) assert bow.colour = 'yellow'
and I'm sure you can come up with some actual genuine examples. Fine, I believe you. But I maintain that if we balance the negatives:
- a more complex set of scoping rules means more to learn; - and more to misunderstand; - harder to implement; - knock on complexity (e.g. what happens to `locals()`?); - annoyance factor, e.g. treatment of `except ... as err`;
against the positives, the balance comes out clearly against block scopes.
You're welcome to try to persuade me otherwise by demonstrating that the positive uses of block-level scoping are not as unusual as I expect, and more useful than I think, but please don't assume that because I have come to the opposite conclusion as you, it can only be because I don't understand the feature and have therefore dismissed it as "this weird Blub language".
We're not talking about Haskell Monads here :-)
For just under 30 years Python has done without constants, not because constants are pointless, but because the additional complexity isn't worth the benefit. We can get 95% of the benefit of constants from naming conventions and self-control ("just don't re-bind it") with none of the cost. And my argument is that we can do the same for block scopes: we get 95% of the benefit, with none of the costs, by just *not* re-using names.
(And there are a number of very VERY good - albeit unusual - uses for name reuse. It's not that we can't think of different names. It's that we specifically WANT the same name, since it is serving the same purpose. In the absence of sub-function scoping, we're forced to invent arbitrarily different names, and that doesn't actually improve clarity at all.)
It's fine to re-use names. What we're talking about with block scoping is having two variables with the same name coexisting within the same function at the same time.
That's quite different from sequentially re-using the same variable for two (related or not) purposes.