On Mon, 30 Nov 2020 14:45:26 +0900
"Stephen J. Turnbull" <turnbull.stephen...@u.tsukuba.ac.jp> wrote:

> Paul Sokolovsky writes:
>  > Also to clarify, [cowboy attitude] referred to difference in
>  > approaches in response to particular issue(s) raised. One thing is
>  > to say "it's hard to implement it better with the limited VM
>  > infrastructure and resources we have" (that of course leads to
>  > further questions/discussion), it's different thing to say to the
>  > same matter "issue exists, but it's not really an issue".  
> Of course those are *different*.  Where I differ with you is on
> whether "I understand the case are describing and that you want to do
> something about it, but we don't consider that a problem" is "cowboy
> attitude".

Right, all people are different. That's great!

> My experience is that the development community will care when it
> perceives that a change serves the greater community (eg, f-strings
> and data classes, which are universally loved), or when a sufficiently
> large coalition of committers can be convinced.  That's what you need
> to do, and accusing the core developers of cowboy attitude is not a
> good start IMO.

Sorry, but there may be a suggestion of tactics of sneaking somebody's
"pet feature" past the attention of core developers by employing
sycophant techniques. That's certainly not me. Let the criticism begin.
Both of "doing it" and "not doing it".

>  > Maybe one of these years would be good time, after so many
>  > usability changes, to also tighten up theoretical side with
>  > block-level scoping.  
> Maybe it is.  I certainly hope not, because I like Python as it is,

But then you've already lost, because today's CPython (3.9) is not like
that of a year ago, and that one is not like that of 2 years ago, and
it all has been changing at alarming pace. So, calling for "stop the
world" right now seems to be a bit ungrounded, if anything, newer
changes proposed take inspiration in the changes already done.

> where I rarely have to deal with declarations separate from
> instantiation, and code is highly dynamic without a compiler
> complaining, perhaps even going on strike, any time I want to do
> something whose semantics I know to be sound even though the compiler
> can't prove that from the syntax.

Good news is that it all stays. But if you want all that, perhaps you
appreciate that some other people may want different things too. Like,
more speed (JIT), better scalability to complex codebases, tighter
formal side (syntax/semantics), etc.

> Yes, I know you claim that your proposed syntax won't be in my face,
> and quite possibly you're right with respect to the obstreperous
> compiler.  But I also know that you make claims that are provably
> false, such as not making me use the syntax.  True, short of XKCD 538
> you can't make me write it, but if it exists somebody will make me
> read it.

Ok, it will be it will be a fun cute read, calling for existing
memories (or for youngest of us actually teaching them useful things,
which apply outside Python too).

>  > The simplest answer is that they don't (interact with existing
>  > overdynamic features).  
> You say "overdynamic", I say "works for me".

... And some say "slow".

>  > They are new enough, opt-in concepts, and so can start from blank
>  > page.  
> You're BS-ing here -- you back off in the next sentence (quoted
> below).  And from the community's point of view, no syntax is truly
> opt-in because we often work with Other People's Code.  We need to
> read it, and often in open source we are modifying code whose style is
> "owned" by someone else -- if I were to work on code you maintain, I'm
> pretty sure you wouldn't hesitate to query "shouldn't this variable be
> block local" or even refuse to accept code that didn't have the block
> locals you think it should have.

But if you anticipate that there may be people who will use block-local
vars in Python "when they should have been", don't you think that
"saving" them from that by simply not letting them hold of block-scoped
vars is a bit ... umm, backward way to tackle the issue?

Beyond that, "it's going to be a fun cute read". If anything, we can
judge by experience of others. If you see a "let" in JavaScript code,
you can google up "javascript let" and in a minute you will be back to
your pleasurable code-reading. And "let" ("still", "so far") doesn't
appear that often in JavaScript code. Unlike it's counterpart "const"
which has the same block scope, but very obvious semantics, so many
people won't even google it on first sight (only later).

Do you think it would be worse than that with us? I don't.

> A lot of effort and persuasion (and more or less silent acceptance of
> the slings and arrows from outraged dynamicists) went into the
> introduction of type hints.  I think this will require more of the
> same (although maybe not: type hints are intentionally pervasive for
> those who use them, these declarations will presumably be occasional).

And block scope is initially introduce as internal compilation pipeline
feature at all, but with an immediate notice: it's not intended to be
hidden forever, many other languages offer it as "public API", so
let's be getting used to "measure up" it for Python too.

And strangely, this latter notice is getting more (surface) attention
than the initial idea to resolve corner semantic cases for
existing or to-be-added constructs. 

>  > Alternatively, if debuggers, etc. are tied to locals() (vs more
>  > low-level code object introspection), could add
>  > implementation-defined support for them in locals() for simple
>  > implementations like CPython (block-local names will be mangled).  
> Sure, but we don't have an implementation of that support yet, do we?

Only idea and a quick prototype, which still allows to get some "feel"
of what it may be like.

> And adding the syntax will impose burdens on other implementations
> that claim to support the full language,

Oh, so again, it's a bit too late to get conscientious in that regard,
after stuffing f-strings and walrus operator into the language,
shaking up dictionaries from ol' good "mapping" computer-science data
structure into some adhoc, CPython-specific little monster, etc. 

> as well as quite possibly
> inducing implementation differences here, unless you specify the
> debugger support etc.  My point is that these are the kinds of
> complications that frequently delay acceptance of features for a
> release or two.

The claim was that block scoping is not a rocket science, but baseline
compiler science. The underlying machinery is not complex (it's
variable name rewriting, that's all). Surely implementation always has
its own side, but overall, this feature should be a smaller (but
"deeper") change than many others.

Aspects of debugger support is not part of the language
(syntax/semantics), but an implementation detail of a particular
implementation. Certainly, if debugger support is important for such
one, it will be addressed.

>  > > I suspect that when I'm reading other people's code I'd almost
>  > > certainly read a let/const var = init_val as suite- local in such
>  > > contexts, while in my own code I'd probably want to use it as
>  > > statement-local a lot.  
>  > 
>  > It's unclear how block-level scoping can be useful for
>  > single-statement scopes (beyond special cases like
>  > comprehensions), because well, that single statement will be
>  > assignment to such a variable (but nothing will read it). I even
>  > suspect we might imagine different things when talk about this,
>  > perhaps examples would help.  
> By "if statement" I mean
>     if foo():
>         pass
>     elif bar():
>         pass
>     else:
>         pass
> That is a single conditional *statement* with three suites that each
> might constitute an individual block or together constitute a single
> block (encompassing the if and elif condition expressions as well).

Right. And more specifically, this "if" statement may be a block with
other statements (at the same level), with which it shares block scope.

> I
> believe that's how the Python Language Reference uses "statement".
>  > 1. We have adhoc block-scope-alikes already.  
> Yes, there's the problematic deletion of exception-capture variables,
> but I don't think the plural is justified.

But "adhoc" is not a swear-word. It means that each case was addressed
with its own approach, each somewhat (or quite) different. What's
proposed instead is a common way to address them, a couple of more
cases "on the plate", and hopefully, some of the future challenges too.

>  Comprehensions are
> *expressions*, not suites. 

Yes. But expression can be used as a statement. And block/suite is
defined as "one or more statements". That's how we can apply machinery
for "block scope" to expressions.

> Python is a *high level* language: the
> fact that
>     [x for x in y]
> effectively expands to
>     list((x for x in y)) ,
> implicitly defining a generator function and iterating that, doesn't
> bother me at all.

That's good, because how it's actually implemented in the code is
implementation detail, which should bother people working on the
compiler. And block scoping is initially introduced exactly to address
hurdles the compiler has with implementing some language features.
(Where "hurdles" include "being less optimal than could be".)

> It's an expression, and there's no reason for its
> internals to be available to the scope it occurs in, any more than v
> or x in
>     def foo(y):
>         v = []
>         for x in y:
>             v.append(x)
>         return v

>From the point of view of lambda calculus, function abstraction,
application, and alpha/beta conversion all go in the same pack, so what
you write is definitely right ;-). Implementation-wise however, some
constructs are less efficient than other, e.g. functions are almost
often heavier-weight than expressions/statements (even in machine
code). That's why a baseline compiler optimization is inlining. Here we
vice-versa, "outline" a comprehension expression to a function. That
can be improved upon. 


> that given that generator expressions exist, "list((x for x in y))" is
> about as simple a semantics and implementation as you could ask for.

Absolutely right. Simple implementation. But not the most efficient
one. And with block-scoping infrastructure available, avoiding function
overhead would be almost as easy, but tad more efficient in the end.

But most importantly, a common infrastructure will be reused to address
different cases, and that's the main motivation here.

>  > 2. We have on the plate cases where block scope may help.  
> I'll take your word for that.

One case is "undefined behavior" in case of not-matching with pattern
matching, another case is peculiarities with "for" loop variable
closure-capturing, on python-idea. Again, how block scoping helps there
is that the same proven, generic (thus easy(er) to explain) machinery
would be used. It's not a "great enabler" or something. Alternative
solutions exist. Quite adhoc and/or more complex/less efficient IMHO. 

> I don't know that I've ever run into
> any, and I do know that I've never thought "Damn, I wish I could use
> block locals here" or "I wish the author of this code had used block
> locals here" in Python

But that's good, isn't it? If anything, that would be a reason to
"keep calm and not worrying", isn't it? There's no conspiracy going on
to put everyone in an uncomfortable position of realizing that they
"did it all wrong all this time", and all their variables should have
been "new variables on the block". That's totally not the case.

> (though I occasionally use block scope in C).

Oh, so we're on that track already, right? It's just that we got used
to think that "Python is special". Because we've been told that so many
times. But after peering into it for enough time, it seems that Python
is much less of that special snowflake it's drawn as sometimes. Well,
that's how I arrived here. So, please hold on to that path.

> Of course *I* don't matter, but the relative balance between folks
> with your experience and folks with mine does.

Yep, that's why we run discussions, trying to show insights we've got
to other people, to check if they see something similar in there.

>  > 3. So, convert to "real" block scoping there.  
> Whoa!  First you have to convince the core devs that block scope
> really does help, and that it's the best way to improve the language's

Well, but you might be suggesting that I'm a kind of titan on whose
shoulders lies the task of conveying some sacred knowledge to "the core
devs". If it's like that, "all is lost" already (for a few years,
though some things in Python history were actually lost for decades).

First, "my idea" is not mine. Block scoping is again a well-known
feature used in many other languages. I just once saw and was amazed by
seemingly right-on-the-surface idea to apply it to Python needs, and
try to spread gospel of this revelation.

In all fairness, the best outcome could be now is that some of the core
devs says something like: "Yeah, I wanted to try that idea several years
ago. But then I went on Hawaii vacation for a month (much better spend
of time than this stuff), and on return, started renovation in the
house, that's how I forgot about it."

Otherwise I fully understand it will be a long thorny path. But
somebody should start it.

> ability to express solutions to these issues.  I'll trust you that it
> *does* address the issues.  But whether it's best is entirely unclear
> to me.  Perhaps there are are semantic tweaks like changing the
> intuitive explanation of comprehension from "a list comprehension is
> equivalent to an obvious inlined for statement" to "a list
> comprehension is list applied to the obvious genexp".
> You don't like that particular semantic tweak because its

But I absolutely like it! I just don't sit with blissful smile
on my face contemplating the object of my liking, but use it as
motivation to rise up and say: "That's nice, but we can do
better!" (Some other things I actually don't like, e.g. "except as e"


>  > If you *really* need block-level local, perhaps just being able to
>  > use it (without rehashing half of the language) is good enough, for
>  > starters.  
> You continue to overstate your case.  Nobody *really* *needs* block

But you overstate your worry about the block scopes, and than
apparently I overstate my comforting those worries.


>  > > But requiring a "block" statement to create a slope in common
>  > > cases like a one-armed if or for is equally inelegant (and surely
>  > > more common).  
> But not necessarily equally costly if misunderstood, and the "always
> need a block statement to create a block" approach is easier to
> understand and explain correctly.  And I disagree with you that mere
> verbosity is "inelegant".  Concise syntax is a virtue, but so is
> consistent syntax.  IMO, elegance lies in achieving both in the same
> construct.  I'm not sure if elegance is possible here, consistent with
> existing Python syntax.

Here you respond to your own quote, and I'm losing track of what
arguments apply to. So, no response from me.


>  > [When] you intuitively expect special scoping rules for at least
>  > the "case" line itself, [...] the block scope is the best well-
>  > proven formalism in the proglanguage theory/practice which matches
>  > that requirement.  
> Sure, but Python is not a Lisp.  Adding arbitrary user-defined block
> scopes is not just a matter of one more pair of parentheses.

So, we want be adding Python's analog of parentheses, which is indented
statement suite. Because well, that's not a cheap as a pair of parent
in LISP, so *unconditionally requiring* new indented block just for
block scope vars is too much. We'll use existing intended blocks. This
follows ideas how it's done in most statement-based languages (except
that many use braces instead of indentation).

> So
> "best" has to be constrained by "Pythonicity", and I don't think your
> computer-scientific proofs can handle Pythonicity yet.

You know, "Pythonicity" term lost much of its charm over the very last
few years. You started your previous mail with mentioning a case of
f-strings, saying that "people waited for string interpolation since
Python 1.5". I was there at that time, and remember *quite different*
story. I remember regular sabotage spies from the Perl-land trying to
seed confusion in the happy Python-island. But those were detected
quickly and their harmful influence were humbly but with a firm hand
rejected. Because explicit is better than an implicit. Because there's
one way to do it. And if you have one way to say explicitly that you
format a string with '"%s" % foo', why would there would be a need to
hide formatting inside strings themselves and confuse the innocent?

The suddenly, .format()! And f-strings were a fatal blow to
the Pythonicity As We Knew It.  

With that introduction in mind, the solution I advocate is exactly
Pythonic, trust me. It's based on the idea that there's no need to
hamper readability and learnability by introducing heavy-weigth
indented blocks without good need. Instead, it reuses existing practice
of "variable annotations keywords" like "global" and "nonlocal".

In this way, it *differs* from the tradition of LISP and other
functional languages, which, due to their expression (vs statement)
orientation, indeed usually have a dedicated form for lexical scoping:

(using ML-like syntax)

    var1 = expr1,
    var2 = expr2

Which is itself an expression, so you can write:

(let x = 10 in x) + 1

We don't need all that (well, we don't let most of that), and thus we
don't need to burden ourselves with "let" being a block statement.

Best regards,
 Paul                          mailto:pmis...@gmail.com
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
Message archived at 
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to