Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

[deleted]


So, the baked-in async / await wouldn't be useful? For the kinds of apps I'm writing, I can't wait for this - I've made a lot of use of Tasks/PFx, and this really simplifies the mental model for me. In addition, I appreciate that it's consistent throughout the framework (as opposed to Node.js, Twisted, EventMachine, etc.)


"await" will be huge. It will just be a while before most of the .net community figures out how powerful it can really be, much like what happened with lambdas and linq.

Overall though, 4.5 seems like a pretty weak release for 2+ years of work. I hope that 5.0 was being worked on in parallel.


Async/await could have been even huger. What the C# designers don't seem to have noticed is that async/await is very closely related to LINQ and could have been built as a new syntax on top of LINQ. Let me explain.

The core of LINQ essentially the same as the core of F# computation expressions and monadic do-notation in Haskell: two operators Return(x) and Bind(m,f). The name of Return is datatype dependent in LINQ, but its purpose is to create a container with a single thing inside. E.g. for IEnumerable Return(x) creates an IEnumerable with a single item x in it. Bind is called SelectMany in LINQ.

F# has something similar to async/await in the form of asynchronous workflows. It is implemented on top of computation expressions, i.e. monads. The F# async feature is similar to the continuation monad. But the F# designers didn't limit the computation expression syntax specialized to asynchronous computations, it actually works for any monad. For example for sequences (=~ IEnumerable in C#) and parsers and probability distributions. You can also do these same things with LINQ: you can do asynchronous computations and parsers, probability distributions, reactive streams (Rx) and many other things with LINQ.

The trouble is that the C# designers have limited the async/await syntax to just asynchronous computations. That means that you cannot use the very convenient async/await syntax for anything other than the async "monad". Had they not limited this feature and had they built the feature as a new syntax on top of the LINQ operators then you could use it for IEnumerable and parser combinators and anything else that implements LINQ's SelectMany method. Specifically async/await is limited to monads where Bind(m,f) invokes the continuation f exactly 0 or 1 times.

For the people who are familiar with the theory around monads, C#'s async/await basically correspond to Moggi's monadic reflection and reification operators. The async operator reifies a monadic computation (in this case limited to asynchronous computations) into a data structure, and await is the inverse that reflects a computation represented as a data structure into the computation.

That is:

The operator async takes a block of code representing an asynchronous computation returning a value of type T and turns it into a Task<T>, and await takes a Task<T> and runs it as an asynchronous computation returning a value of type T.

The operator reify takes a block of code representing a M-monadic computation returning a value of type T and turns it into a M<T>, and reflect takes a M<T> and runs it as an M-monadic computation returning a value of type T.


What the C# designers don't seem to have noticed is that async/await is very closely related to LINQ and could have been built as a new syntax on top of LINQ.

Considering the C# designers include Erik Meijer and work closely with Don Syme, I find it hard to believe that they didn't notice this. But you're right, it's not as powerful or general as what is in F# (which I really need to learn better, as every time I look at it, I want to code in it).

I suspect the C# designers looked at what one of the biggest problems they have is, and it is asynchronous computation (especially w/ respect to the UI thread) and said that F# async workflows solve this problem. But too generally. What do I mean by that. With the current C# solution the syntatic changes are minimal to a completely sequential program. It's not as general, but easier to write and understand.

I wouldn't be surprised if C# added async workflows full on in a future version, when they'll point to async/await and say "you've been doing it for years -- it's not hard at all!"


The full power of F# async workflows can be had with the same syntax async/await has now. Basically async workflows could have been a more convenient syntax for let! in F# async workflows, in the sense that you can directly apply await inside an expression instead of having to insert a let statement:

    ... Foo(await m) ...
Instead of, in F#:

    let! x = m
    ... foo x ...
It is certainly possible that the C# designers did recognize the possibility to make await work for any monad, but decided against it because it could possibly result in confusing code or worse performance.

If that's the case then it would be great to hear the reason from one of you who are on the C# design team and reading news.yc :)


If that's the case then it would be great to hear the reason from one of you who are on the C# design team and reading news.yc :)

I'd second that. Maybe someone @MS could send this to the Async team?


That's rather interesting actually - nice bit of reading - thanks :)

I did kind of passively think that more syntax was not the way to solve these problems but shrugged it off. I've been slightly worried about the complexity of C# after some awful decisions (nullable types for examples).


Actually I think the syntax is quite nice, it's just a pity that the usefulness is limited to asynchronous computations.


This wasn't mentioned in the article. I'm using "vanilla" threads. But yes it is an improvement for PFx users.


Agree, async is going to be huuuuge :)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: