F#'s asyncs are built on a general meta-programming feature of the F# language, while C#'s is based on a new keyword - F# clearly did the right thing here. (Though I still wish for typesafe macros and more flexible/general user-defined operator/grammar support.) Meta-programming is one area where C# is not evolving to, which is fine.

I think C# made the same mistake with event as they are making with await - they have a language feature that's tied to a particular set of classes in the framework - this seems like a questionable design choice. This added keyword sugar is unnecessary when you could just replace await foo with foo.await(), or Async.await(foo). Similarly, we don't need an event keyword that enforces scope/use restrictions inconsistent with the rest of the language, outputs boilerplate add/remove classes that can't change except between compiler revisions, etc., when an event library that is completely transparent and replaceable is all that is needed. (It also seems inconsistent that fn's that yield a value don't need to be declared as such, but fn's that are async do need to be declared this way.)

There are some cases where the convenience is worth this price - foreach/IEnum and using/IDisposable come to mind - but IMHO events and async don't rise to this level of ubiquity and simplicity. And unlike foreach w/Enumerables (where "get next" is the raison-d'etre of the entire interface) , await also only handles a small subset of actions that you may want to perform with the task, so it seems even more strange.

Still, a language keyword is really the best press (any news is good news) and brings async to the forefront of poeple's minds which is good even if it shouldn't be baked-in as it is - the downside being that perfectly simple code that does not benifit from async may start gaining complexity, just as there are those that use a RDBMS when a text file is all that is called for.

[Hmm, after reading again, seems harsh - C# probably did what was best for C#, and F# for F#- but I clearly like the latter better :) ]

By on 10/30/2010 12:30 PM ()

Hi,

the await is not only suger and you can't just switch to something like Async.await(foo), because just like the iterators it's compiled into a state machine, so that you can use it inside loops and other stuff and it creates the right continuations for you - this is the real power and we don't really get this with F# in this way.

If you did see the paper from D. Syme and T. Petricek (Joinads): this is something to look forward to (I really like the *match*)

By on 11/3/2010 2:08 AM ()

>the await is not only suger and you can't just switch to something like Async.await(foo), because just like the iterators it's compiled into a state machine

Yes, but a reentrant state-machine is not the only implementation that could have been chosen -- other implementations could have been suppplied in library form only, with perhaps after a few competing implementations leading to eventual compiler support, with tooling support there first via IDE plugins. For exampe, consider as input to the async runner a new [] {...list of lambdas...} or for more flexibility as in F#, a lambda that returns the next continuation, etc -- with not much more effort than went into writing a custom state-machine via new keywords, the C# equivelent of builder/computation expressions or type-safe macros could have been supplied to provide a more general solution to expressing asyncs, with the additional benefit of allowing varying implementations of asyncs and providing a mechanism to describe other higher-order constructs. (Though I understand they had the convenience of reusing some of the state-machine code for iterators.)

Again, a good example is events -- events generate boilerplate code with special scope semantics that are rarely used because GUI <i>frameworks<i> are actually what supply event and command semantics (perhaps bypassing events all-together and using interfaces or delgates) to real-world applications.

By on 11/3/2010 11:54 AM ()

Hi,

the await is not only suger and you can't just switch to something like Async.await(foo), because just like the iterators it's compiled into a state machine, so that you can use it inside loops and other stuff and it creates the right continuations for you - this is the real power and we don't really get this with F# in this way.

If you did see the paper from D. Syme and T. Petricek (Joinads): this is something to look forward to (I really like the *match*)

It's done using a different mechanism in F#, but computation expressions support performing computations from within loops as long as the builder exposes For and While methods. The AsyncBuilder class supports these, so the end result for the programmer is pretty comparable when doing async programming in C# and F# (modulo hot/cold start and other conceptual issues).

By on 11/3/2010 9:12 AM ()

BTW: can we hope for interop between F#-async and C# - async?

THAT would be really helpful!

Well ... here is a nice statement: [link:blogs.msdn.com]

By on 10/28/2010 11:46 PM ()

I haven't dig my way to the new stuff yet (but I'm excitet) - but I guess F# will stay on top as long as we have non-mutable as default (and no good readonly - support in C#/VB.net) and tail-recursion (that makes continuation-passing style programming much more performant).

These are just the two pieces I can think of at once - I guess there are a lot more.

And of course the programming-style with F# is just more ... succinct ;)

(If only we would get a better project-space behaviour - the stuff with "order matters" is killing my fun somewhat - and of course: STOP GIVING US STUFF FOR C#/VB.NET - give us type-classes :) )

By on 10/28/2010 11:44 PM ()

F# has great type inference, algebraic data types and lots of other cool features, which makes it generally a great language to work with, not just for parallel computing tasks.

t I guess F# will stay on top as long as we have non-mutable as default (and no good readonly - support in C#/VB.net) and tail-recursion (that makes continuation-passing style programming much more performant).

I don't understand what you mean, can you please elaborate?

By on 10/29/2010 1:58 AM ()

@Stephan: Indeed, there are plenty of other cool features in F# that will make it my language of choice for my next project in scientific or technical programming. I was an instant fan of F#'s syntax and want to explore it some more.

I guess async programming is only one approach to parallelism. Don's blog post hints at a bright future for async now that C#/VB are on board. Interoperability can now take on a high priority.

By on 10/29/2010 8:46 AM ()

Well he asked about concurrent / parallel so one of the big things with this kind of apps is:

If you data doesn't change you can forget a lot of the problems you are facing.

But making non-changing data types in C# is not impossible but the design-patterns and feel of OOP makes it hard. And you can't get either the compiler nor the runtime to enforce this for you (which is true for F# too, and a shame)

In F# everything is inmutable by default and you have to make things mutable explicit or use some mutable CLR-type to work around this barrier. And of course the design of a F# solution should embrace functional programming aspects which lends to working with inmutable data.

Tail recursion is a feature of the CLR that got included for the sake of F# (I don't think that the other compilers produce tail-recursive code).

Lets say you have a function and the very last thing it does is calling itself (just to explain it with an easy example). In C# or VB or whatever the compiler will do the usual - push the env. on the stack, call the method, etc. - so with deep recursion the stack will overflow quite easy.

If you have tail recursion on the CLR "knows" that you never will need the thinks on the stack again, because just after the nested method call your function will return. So after all you end up with some kind of loop instead of a nested method call and you don't overflow the stack.

It's a technique every FP language needs in order to be useable in real life.

I hope this helps (it's somewhat hard for me to explain such stuff because I'm no native english speaker as you will have noticed by now)

By on 10/29/2010 2:19 AM ()

I don't think the default immutability in F# is that important for designing immutable data structures & algorithms. If you don't want something to be immutable in C# you can just make it a read-only property or field. Ok, there's a little syntactic overhead, but nothing that fundamentally impedes your ability to come up with immutable interfaces.

Preventing your users from mutating data really is the trivial part of the immutable data structure & algorithm design. The difficult part is coming up with designs that are not only elegant but also perform well.

IMHO, the lack of compiler/run-time enforced immutability in C# is a non-issue, at least I can't really imagine a scenario where I want to make something immutable, but can't prevent users from mutating it. In the worst case I still can properly document the fact that I want something immutable or side-effect free and rely on the library user not doing something stupid. (Possible future compiler optimizations are a different topic.)

I do agree, however, that the lack of better type inference, pattern matching, tail-recursion and algebraic data types makes it more tedious to write algorithms operating on immutable data in C#.

Also, I did know what tail-recursion is, I'm just not sure whether the lack of it really is a deal-breaker with regard to parallel or asynchronous programming. F#'s async feature certainly will not be "much more performant" than C#'s async implementation, if that is what you meant to imply in your original post.

By on 10/29/2010 6:47 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper