If I understand it correctly, this would look like this:
try {
p = async { Buffer.read("foo") };
// do something in between
// now wait for the result
p.value;
} { |e|
// handle error
}
Basically wrapping any kind of blocking operation in its own thread? I guess Routines are cheap enough for that.
Actually, this sounds quite similar to green threads in Go. To be honest, I find this pretty nice. I think it’s a valid alternative to async/await.
For this to work in practice, Buffer.read would need to be blocking, though… So we would need to change all async functions to be blocking and throwing errors instead of using action functions. The question is how to do that without breaking things… It’s the same dilemma. We could add new methods, but this would look pretty weird:
async {
Buffer.readSync("foo");
}
Another solution would be to ask the user to synchronize:
async {
Buffer.read("foo");
s.sync;
}
Also weird, but it wouldn’t require any changes or additions to the Class Library beyond Function.async.
One problem with blocking methods – that are really asynchronous under the hood – is that you couldn’t use them in the following contexts (without wrapping them in async):
AppClock (UI thread)
OSCFunc (network thread)
toplevel
Of course, we could simply to tell users to only call these inside a Routine, but we’d still need to provide good error messages. Essentially, every blocking method would have to ensure that it indeed runs on a Routine and throw an Error otherwise.
Here’s another potential issue with (pseudo)blocking functions:
Methods like Buffer.readSync – even if they may appear to be blocking – internally still need to yield back to the scheduler after sending the Server command and wait for the Server reply. The catch is that while the Routine is waiting, other pending Routines might be resumed. This can lead to suprising concurrency issues!
With async/away, it’s – more or less – obvious that things may interleave:
a = true;
SystemClock.sched(0.1, { a = false });
b = Buffer.readAsync("foo").await;
// 'a' may haven been set to false in between
But the following may be rather surprising:
a = true;
SystemClock.sched(0.1, { a = false });
// this appears to be a truely blocking read operation:
b = Buffer.readSync("foo");
// but 'a' may have been set to false in between!