Tasks can't modify nonlocal variables
When a nonlocal variable is modified within a task, the variable's value doesn't actually change outside the scope of the task. As an example:
from parla import Parla
from parla.cpu import cpu
from parla.cuda import gpu
from parla.tasks import *
async def foo():
a = 1
print(a)
@spawn()
def t1():
nonlocal a
print(a)
a = 2
print(a)
await t1
print(a)
if __name__ == "__main__":
with Parla():
@spawn()
async def bar():
await foo()
I would expect this to print
1
1
2
2
but instead, it prints
1
1
2
1
This is a side-effect of the closure capture semantics of Parla tasks (which is different from the closure capture semantics of Python functions). It would be very complex to avoid, since we want changes outside the task to be invisible from inside the task (to allow tasks to be created effectively inside loops among other things). I also think allowing nonlocal changes like this would make the semantics more confusing because of concurrency. I think the correct solution to this is probably to detect this and raise an error. But I'm not the sole designer, so go ahead and debate as you see fit. :-)
Yah, my only opinion on this is that it shouldn't be doing what it does currently. We need to either disallow the nonlocal and raise an error or allow it to bypass our modified capture semantics. Fortunately nonlocals are something of a niche feature, so there's no rush.
After thinking about this a bit more, I think the only way to do this is to allow the end-user to pass a list of names that they want excluded from our closure-capture hack (https://github.com/ut-parla/Parla.py/blob/d82e6d573a5cd5b1e492a99a0106cd90e632961e/parla/tasks.py#L416). That can be yet another spawn keyword.