4 ms·
If you want to write async code in .NET, use F#. You can compose and BeginOp EndOp functions into a function that returns an Async<T> I've probably screwed up
by fleitz 16y ago
If you want to write async code in .NET, use F#.
You can compose and BeginOp EndOp functions into a function that returns an Async<T>
I've probably screwed up the exact function name but here's the psuedo code.
Example:
Imagine a C# class as follows
public class Foo {
public AsnycResult BeginGetBar(int bar_id) { // something }
public Bar EndGetBar(AsnycResult result) {
// something
return bar;
}
}
Now to consume in F# create an extension method
type Foo with
member x.AsyncGetBar = Async.FromAsyncResult(x.BeginGetBar, x.EndGetBar)
Now to use it
let somefunc = async {
let x = new Foo();
let! bar = x.AsyncGetBar(10);
// do something with bar
}
What F# does is create a call back that is the rest of the function after the let!/do! statement, basically your code is split into a call back everytime you use a let!/do! binding.
For a more interesting example lets say you want an async file copy.
let copy s1:Stream s2:Stream =
let buffer:byte[] = Array.init 8192
let rec copy = async {
let! read = s1.AsyncRead(0,buffer.Length,buffer)
match read with
| 0 -> ()
| x -> do! s2.AsyncWrite
return! copy()
}
The nice part about this is that copy is a fully reusable piece of code async code. So anytime you're in an async block and need to copy a file, so...
let move s1 s2 = async {
do! copy s1 s2
do! delete s1
}
- dinkumthinkum 16y agoWhy not just write it in C#.
- fleitz 16y agoBecause in F# you can write that code today rather than in a year or two when C# 5.0 is released. Also, the pattern used by F# to do this sort of thing is exposed to the user so you can create any kind of monad instead of just one for async. In F# this behavior is integral to the language and not just syntactic sugar for a couple 'special' cases. So instead of learning one syntax for continuations and another for async, sql, etc, etc. You just have one system to learn that can be applied to many different problems, and you don't have to wait for Anders to bless your problem as important enough to have syntactic sugar added. The other thing to note is that there will be many 'special cases' about using this code that don't work with typical C# code because of its mutability. It's similar to all the weirdness around using the yield statement. Like how you can't have an out parameter on a method that uses a yield statement and some weirdness around exceptions.
- kevingadd 16y agoSo far it seems like they're doing a good job of reducing the special cases when it comes to this feature. It handles exceptions correctly, and you can 'await' any object that implements a trivial interface, so it's not just limited to the APIs they've decided to bless.
- jules 16y agoWith this new extension to the C# language you can do the same in C#, it's the whole point of this extension. Actually the C# way of doing it seems to be a bit nicer than F# even.
- MichaelGG 16y agoBut a: F# has had this for a while, and b: this isn't a language feature. It's a general workflow feature, and async is just one way of using it. Contrast that to C#, where it's specific functionality baked into the compiler and not something that can be extended via a library.
- bad_user 16y ago"async" in F# is based on monad comprehensions, making it a feature you could've come up yourself. Personally I don't like magic keywords baked in the compiler.
- trezor 16y agoEven though I never fully got the hang of F#, I must agree on this one. I like C# as a language, but too many magic keywords just starts smelling wrong. Having a compiler do work for you and simplify your code is nice and you wont see me complain about this feature in particular. On the other hand, I've made enough monadic extension classes (NullSafety, Object-transactions, etc) and extension methods to cover up for short-comings as I've seen them in my projects, and it always bugs me how this effectively forces me to clutter up my syntax. Consider the following code var x = GetSomeObject() // can be null .SubProperty // can also be null .Indexer[index]; // can also be null This code can cause NullReferenceExceptions all over, so to do it safely, you need to add a bunch of if (object == null) checks. With my NullSafe-extensions, the expression looks like this: var x = GetSomeObject().AsNullSafe() .Do((x) => x.SubProperty) .Do((x) => x.Indexer[index]) .Value; // can be null or default Within the C# type-system, there is no way to get around this clutter and massive use of lambdas. Granted, it looks better than the corresponding code with manual null-checks for every step, but with lambda expression comes the cost of not being able to debug & correct code at runtime.