vvvv / VL-Language

The official repo for the design of the VL programming language
31 stars 0 forks source link

[Quest] Patching async / await in a clear and elegant way #25

Open antongit opened 4 years ago

antongit commented 4 years ago

Hello,

I'm coming from this Forum thread about searching for the better way of patching C#'s async/await. https://discourse.vvvv.org/t/c-await-and-resource-provider/18622

My question was how to patch these very elegant several lines of codes (ok, you have to know, what await is actually doing, but then it becomes pretty clear that it's very nicely expressed in this textual code:

using (var csvFile = new FileStream("mfccs.csv", FileMode.Create))
{
    var serializer = new CsvFeatureSerializer(mfccs, timeMarkers, header);
    await serializer.SerializeAsync(csvFile);
}

The FileStream will be disposed only after the SerializeAsync method finishes. SerializeAsyc returns a running (hot) task (there is the convention that methods named "...Async" start a Task and return it) and only when the task finishes the execution path returns to the innards of the using and because there is nothing more to do it exits the using and disposes the FileStream. I was trying to patch it, but as we have no Tasks, I've converted the Task into an Observable and it is looking like that then:

image

@azeno has mentioned that the patch could be simplified by using the Using [Observable] region, which will already reduce the amount of regions and concepts in the patch. And that:

For example introducing Await as a node shouldn’t be too hard, we can indeed rely on the C# compiler doing the heavy lifting, but the implications of such a feature are quite vast.

When I'm patching wrappers for the C# libraries more and more often I'm hitting the await and every time it is very unclear how to go around it and patch it.

Thank you!

Unfortunately I have no solid idea for the [Proposal]. Or should I make one and copy @azeno thoughts from the Forum thread in there?

Best, Anton

velcrome commented 4 years ago

could an Await region be an answer, that accepts a Task<T> as internal output pin, but outputs the actual result to the surrounding thread?

azeno commented 4 years ago

@velcrome I'd reserve the name Await for now. But yes, as long as we don't have proper language support we could add a bunch of LINQ like operators/regions around Task<T> so working with them becomes similar to working with observables or enumerables. A very good starting point would be this aricle: https://devblogs.microsoft.com/pfxteam/tasks-monads-and-linq/ which also points to a more in-depth explanation https://github.com/iSynaptic/Monad-Comonad-Precis/blob/master/Precis.cs

In other words we could get rid of the need to put everything into the observable world in order to work with tasks.