Open
Description
I am trying to write a Viper function which retains state between calls, preferably using a closure. The following produces an unexpected result (all testing on a Pyboard 1.1 running V1.17):
def foo():
x : int = 0
@micropython.viper
def inner() -> int:
nonlocal x
q : int = int(x)
q += 1
x = q # x never increments
return int(x)
return inner
bar = foo()
bar() # 0
bar() # 0
Oddly similar code using a global works:
x = 0
@micropython.viper
def foo() -> int:
global x
q : int = int(x)
q += 1
x = q
return int(x)
foo() # 1
foo() # 2
foo() # 3
Attempting this with a class produces a type error
class Foo:
def __init__(self):
self.x : int = 0
@micropython.viper
def bar(self) -> int:
q : int = int(self.x)
self.x += q # ViperTypeError: can't do binary op between 'object' and 'int'
return int(self.x)
foo = Foo()
To date my "best" solution is to use a closure with an integer array to contain state:
from array import array
def foo():
x = array('i', (0,))
@micropython.viper
def inner() -> int:
i = ptr32(x)
r = i[0]
i[0] += 1
return r
return inner
bar = foo()
bar() # 0
bar() # 1
bar() # 2
It would be good if nonlocal
worked as expected and if there were a solution to the problem of accessing integer bound variables.
Incidentally the speedup using Viper in my actual application is phenomenal :)