I was thinking about introducing new opcodes for implementing static variables. Not sure though. All of the ideas actually do the same thing. The difference is approach.

On Fri, May 28, 2021 at 6:57 PM Chris Angelico <rosuav@gmail.com> wrote:
On Fri, May 28, 2021 at 10:11 PM Steven D'Aprano <steve@pearwood.info> wrote:
> On Fri, May 28, 2021 at 04:20:15AM +1000, Chris Angelico wrote:
> > def f():
> >     static x = 0
> >     x += 1
> >     yield x
> >
> > next(f())
> > next(f())
> > next(f())
> >
> > will yield 1 every time?
> I think that this example has just about convinced me that Chris'
> approach is correct. I wasn't thinking about generators or recursion.
> I think that closure nonlocals are almost as fast as locals, so we might
> be able to use the closure mechanism to get this. Something vaguely
> like this:
>     def func():
>         static var = initial
>         body
> is transformed into:
>     def factory():
>         var = initial
>         def func():
>             nonlocal var
>             body
>         return func
>     func = factory()
> except that the factory is never actually exposed to Python code.

I think that would probably work, but even better would be if the
outer function didn't actually exist. A bit of playing around suggests
that LOAD_DEREF could just work here. If you have multiple levels of
nonlocals, the function flattens them out into a tuple in
f.__closure__, identifying them by index. Statics could be another
level of nonlocals that doesn't actually require a function as such.

In terms of describing the semantics, I think this is probably the
cleanest way to give a pure-Python equivalent.

> It would be nice if there was some way to introspect the value of `var`
> but if there is a way to do it I don't know it.

No idea about other implementations, but in CPython, you can look at
f.__closure__[*].cell_contents, but you'd need to know the mapping
from static name to lookup index. I think the corresponding names are
in f.__code__.co_freevars, but I'm not sure if there are any other
things that go in there.

> We might not even need new syntax if we could do that transformation
> using a decorator.
>     @static(var=initial)
>     def func():
>         body

Hmm, there'd need to be some transformations, since the code generator
is always going to use lexical scope. You can't magically change a
LOAD_GLOBAL into a LOAD_DEREF with a decorator - the only way would be
to do some fairly hairy rewriting, and you might lose a lot of the
efficiency. This really needs proper compiler support, and if it gets
compiler support, it may as well have dedicated syntax.

Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/7CXYEBUKVCLB3O6APOG5TUMPACWFVUGY/
Code of Conduct: http://python.org/psf/codeofconduct/