Hello,

(As the thread continues, and goes from "why did you do that" to
actual technical details/implication, I have little choice (if to
maintain coherent discussion) but go thru existing posts looking into
technical aspects of the proposal.)


On Wed, 2 Dec 2020 10:42:25 +1100
Steven D'Aprano <st...@pearwood.info> wrote:

[First part was answered previously.]

> > # Way to define a constant.
> > my_cnst: const = 1  
> 
> That clashes with type annotations.

"const" is a *type annotation*.

> Constantness is not a type of the 
> value, it's a statement about the name binding.

Your interpretation, my interpretation: 'const is a type annotation
like any other'.

This poses a question of type annotation composability. Outside the
scope of this discussion (a solution exists). All this was mentioned
already in previous discussions.

[]
> It would be better to introduce an independent syntax for constants. 
> Let's say `const`:
> 
>     const x: int = some_expression


Yes, and that was mentioned already. But we'll do that only when we
play enough with "const" as an annotation and see that it's so useful
that is worth being promoted to a keyword. (I'm sure we'll end up
there; but the current state is that not everyone is convinced of
useful of "const" at all. So, no hurry, step by step.) 

[]

> > # Leads to a warning: replacing (monkey-patching) a constant slot.
> > my_cnst: const = 2  
> 
> A warning? What's the use of that?

A use of warning in programming language? A generic question outside
the scope of the current discussion.

> Are your constants *actually constant* or are they just advisory? 

I already answered how my proposal works in this thread. And it's fully
described in the proposal. So, please refer to it.

> If 
> they're just advisory, then we might as well stick with the
> convention to use UPPERCASE names and use a linter that warns if you
> re-bind a "constant".

Maybe you can stick with UPPERCASE names. I'd prefer something more
generic.

> If you can rebind constants by just suppressing or ignoring the
> warning, then people will rebind constants.

If they no what they're doing, let them do that (while they can, until
the "run-time" phase starts.)

> Relevant:
> 
> Sometimes I run GUI applications from the command line. Invariably
> they generate a flood of runtime warnings. Clearly developers are
> paying no attention to warnings.

Outside the scope of the discussion. E.g. C compilers have -Werror for
that.

> > def fun():
> >     # Imports are not allowed at run-time
> >     import mod2
> >     # But you can re-import module previously imported at
> > import-time. import mod  
> 
> That seems like a pointless complication.
> 
> If mod is already imported, why would I need to import it again from 
> inside the function?

You missed the point, it's the opposite situation: "mod" is imported
inside the function to start with. The rest of the discussion is how to
accommodate that in the strict mode, given that "on the surface",
that's prohibited in the strict mode.


[]

> >     # RuntimeError
> >     my_cnst = 3  
> 
> `my_cnst` is inside a function, so it should create a local variable, 
> not attempt to rebind a global constant.

Good catch. "global my_cnst" was clearly missing before that. Fixed in
https://github.com/pycopy/PycoEPs/blob/master/StrictModeTLDR.md

> >     # RuntimeError
> >     mod.func2 = lambda x: 1  
> 
> Yes you already make it clear that rebinding functions is not allowed.

No, you missed the critical part of the proposal: that there're 2
phases of the execution of a Python program: "import-time" and
"run-time". Things at the global scope of that sample show rules for
import-time (lax, even const's can be redefined), while code inside
function executes at "run-time" (strict in all its full glory).

The information about 2 distinct execution phases is presented clearly
even in the TLDR version. Thanks for missing it.

> >     global glb1, new
> >     # RuntimeError: Cannot create new global nameslots at runtime.
> >     new = 1
> >     # Nor can delete existing
> >     del glb1  
> 
> I know "global variables considered harmful", but this looks to me
> like punishing users of globals for being bad by restricting what
> they can do to make their use of globals *worse* rather than better.

They won't be punished much more than the already existing "considered
harmful" background establishes ;-).

> 
> - all globals must be pre-declared and initialised before use;

Already the best practice.

> - functions cannot clean-up after themselves by deleting their
> unneeded globals.

Modules can. Functions? Never saw that, and that's clearly "not
Pythonic". (But one of "dirty Python tricks".)

[]

> >     # Cheats don't work
> >     globals()["new"] = 1  
> 
> That seems like it will probably break a lot of code, assuming you
> can even enforce it.

The code which will be broken - it won't be able to run in the strict
mode. It either will need to be fixed to "not do dirty Python tricks",
or be left forever to work in "standard" mode.

> Is your proposal for globals() to no longer
> return the global namespace dict?

At run-time, it would be wrapped in a read-only proxy. That's all
explained in the proposal. Sorry, did you read it?

> > # Leads to a warning: replacing (monkey-patching) a constant slot
> > (function). 
> > def fun():
> >     pass
> > 
> > 
> > # fun_var is a variable storing a reference to a function (can
> > store ref # to another func).
> > fun_var = fun  
> 
> So is `fun`.

In with the strict mode.

> Are you aware that Python's execution model treats:

I'm aware, yes. Are you aware that the strict mode proposal seeks to
change that?

> 
> - function *objects* as first-class values, same as ints, strings, 
> floats, lists, etc
> 
> - and *names* bound to function objects ("functions") as no different 
> from names bound to any other object?

> You seem to be introducing a complicated execution model,

Not *that* complicated is you think about it.

>  where names 
> bound to functions are different from other names, and functions are
> not first-class values any longer, but either privileged or
> restricted, depending on whether you think "functions are values" is
> a misfeature to be removed or a feature to be cherished.

No, the model is different: function bindings are by default immutable
bindings, which is the best practice for most languages. Only when
proven otherwise, a function binding is promoted (or demoted, depending
on your outlook) to a mutable binding.

> > # Run-time execution starts with this function. This clearly
> > delineates # import-time from run-time: a module top-level code is
> > executed at # import-time (including import statements, which
> > execute top-level code # of other modules recursively). When that
> > is complete, strict mode # interpreter switches to run-time mode
> > (restrictions enabled) and # executes __main__().
> > def __main__():
> >     fun()
> > 
> > 
> > # This statement is not executed when program runs in strict mode.
> > # It is executed when it is run in normal mode, and allow to have
> > # the same startup sequence (execution of __main__()) for both
> > cases. if __name__ == "__main__":
> >     __main__()
> > ```  
> 
> I don't really understand the purpose of your two modes here. In one 
> mode, the interpreter automatically calls `__main__`; in the other
> mode, the interpreter runs the standard `if __name__ ...` idiom and
> then calls `__main__`.

Well, that's because one mode already exists, and another I'm adding in
the proposal.

> How does the interpreter know which mode it is in?

Described in the proposal.

> Presumably there
> must be a "strict" modal switch. If that's the case, why not use the
> presense of that switch to distinguish strict mode from Python mode,
> instead of this convoluted plan of sometimes automatically calling
> `__main__` and sometimes not?

Described in the proposal.

> This mandatory-but-only-sometimes special function seems pointless to 
> me. Just because we're running under strict mode, why should the `if 
> __name__` idiom stop working? It's just code. Your strict mode has to
> go out of its way to prevent it from working.

Described in the proposal.

> I'm sure you know that if this proposal goes ahead, people will 
> immediately demand that `__main__` is automatically called in
> non-strict mode too.

What the people may demand some time later is outside the scope of the
proposal.

> So I can't help but feel you are using this as a
> Trojan Horse to sneak in a stylistic change: replace the `if
> __name__` idiom for automatically calling a special, magic function.

I do not. For the people that you mention above my response is "no".
(Aka: use the strict mode if you want to get tasty goodies, or stick
with the old stuff.)

> That seems to have zero technical benefit.
> 
> What if I want to call my application entry point `main()` or
> `Haupt()` or `entrypoint()`?
> 
> What if I put the `if __name__` idiom *above* the special magic 
> function? Does it still get magically ignored?

Strict mode doesn't change statement-by-statement sequential execution
of the Python programs. Nor there's any magic in it. All is explained
in the proposal.

> 
> 
>     if __name__ == '__main__':
>         print('Starting')
> 
>     def __main__():  # magic
>         print('Running')
> 
>     __main__()
> 
>     if __name__ == '__main__':
>         print('Goodbye')
> 
> 
> I *think* that under your proposal, under regular Python mode, it
> will print Starting, Running, Goodbye, but under your strict mode, it
> will print Starting, Running *twice*, and then exit.

No, it will print Running twice and nothing else.

> Maybe. It's not very clear. It could print Running only, and not
> print Starting or Goodbye at all.
> 
> Your proposed strict mode doesn't seem to actually be limited to
> making Python "stricter" for the purposes of optimization or clarity,
> but also seems to include changes which seems to be more *stylistic*
> changes which (probably) aren't necessary from the implementation:

That's true, and fully disclosed in the proposal (at the very
beginning):

"However, it is also believed that the "strict mode" may also help on
its own with clarity and maintenance of large(r) Python codebases." 

> * globals must be defined in the top level of the module;
> 
> * global constants override local variables;
> 
> * functions aren't variables like everything else;
> 
> * enforced and automatic special entry-point function;
> 
> * discourage the `if __name__` idiom by making it half redundant;

No, it must be presented for compatibility.

> 
> etc. 
> 
> 
> -- 
> Steve

[]

-- 
Best regards,
 Paul                          mailto:pmis...@gmail.com
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/YFVPGEUALYTZL3FPFX6L7XAFPGQEJQ26/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to