On Fri, May 28, 2021 at 10:11 PM Steven D'Aprano email@example.com 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.