iOS async revisited
In this post weare going to look as async again, but from the perspective of F#.
Xamarin Evolve 2013 #
I have been watching the Xamarin Evolve conference this week and it was good to see Miguel announce full support for F#. Those that follow me on twitter etc, will know that I have been doing F# for quite a while in MonoDevelop and Xamarin Studio. The new support currently entails some new project templates so that you can easily create epic new F# Apps without having to refer to my blog. While its sad that my content now falls into the archives its nice to get official support announced in such a grand fashion.
F# Async #
Kudos to Miguel for covering some history of C#’s async feature right back down to its F# heritage too, which appeared in 2007, thanks to the work of Don Syme and the F# team. You can read more about that on Don Syme’s blog or have a look at the research paper here.
So the highly anticipated async await model in C# that’s just gone beta in Xamarin addin channel? We’ve had it for ages in F#! In fact, I suspect you will have been able to use it for quite some time, even before I started hacking together support for F# in iOS! Anyway, that’s enough of the smugness :-) lets get on and see what it looks like using some of the code from the previous post as a reference.
Ill include the C# version first so that you can see the difference rather than having to open my last post.
// Asynchronous HTTP request
public async void HttpSample ()
{
Application.Busy ();
var request = WebRequest.Create (Application.WisdomUrl);
//async await version
try{
var response = await request.GetResponseAsync();
Application.Done ();
ad.RenderRssStream(response.GetResponseStream());
} catch {
// Error
}
}
One of the advantages of the F# Async model is it’s composable nature and controllability. The key to F# async is that its defined with F#’s computation expression syntax:
Computation expressions in F# provide a convenient syntax for writing computations that can be sequenced and combined using control flow constructs and bindings.
There are several built in workflows: Sequences, Asynchronous Workflows, and Query Expressions. Whenever you use a computation expression it is as follows:- builder-name { expression }
. With that tiny bit of background, lets look at the corresponding F# async code:
member x.HttpSample() =
Application.Busy()
let request = WebRequest.Create(Application.WisdomUrl )
//F# async version
async {try let! response = request.AsyncGetResponse()
Application.Done()
ad(response.GetResponseStream())
with ex -> () } |> Async.Start
You can see there is quite a similarity between this snippet and the C# one and you should be able to figure out what’s happening given the knowledge from the previous post.
One of the first things you will notice the builder - async { ...
, followed by the let!
statement. You can think of the let!
as the C# equivalent of await. let!
starts the computation request.AsyncGetResponse()
, and then the thread is suspended until the result is available, at this point execution continues to the next statment, which in this case is Application.Done()
.
Those of you comparing the difference will notice that in the C# version after Application.Done();
we call ad.RenderRssStream(response.GetResponseStream())
but in the F# version we simply call ad(response.GetResponseStream())
. If we take a quick look at the constructors for the types that hold these methods I can show you the difference a bit better:
The C# version looks like this:
public class DotNet
{
AppDelegate ad;
public DotNet (AppDelegate ad)
{
this.ad = ad;
}
}
The F# one I can show on a single line:
type DotNet(ad: Stream -> unit) =
The main difference is that The C# version has the entire AppDelegate
class is passed in, whereas the F# version just takes a function with the signature Stream -> unit
. In fact the F# version doesn’t even need to be placed inside a type like the C# version, we can use a module, again Ill quote from MSDN:
In the context of the F# language, a module is a grouping of F# code, such as values, types, and function values, in an F# program. Grouping code in modules helps keep related code together and helps avoid name conflicts in your program.
F# Modules #
module DotNet' =
let HttpSample(ad) =
Application.Busy()
let request = WebRequest.Create(Application.WisdomUrl )
//F# async version
async {try let! response = request.AsyncGetResponse()
Application.Done()
ad(response.GetResponseStream())
with ex -> () } |> Async.Start
When we want to call this code we can open the module like you would a namespace:
open DotNet
HttpSample(ad)
Or access it fully qualified by including the module
name:
DotNet.HttpSample(ad)
How would this code look from the context of this sample application?
Here is a snipped from the AppDelegate code which makes use of this module
// This method is invoked when the application has loaded its UI and its ready to run
override x.FinishedLaunching (app:UIApplication, options:NSDictionary) =
x.window.AddSubview (x.navigationController.View)
x.button1.TouchDown.Add
(fun _ -> if not UIApplication.SharedApplication.NetworkActivityIndicatorVisible then
match x.stack.SelectedRow() with
| 0 -> DotNet.HttpSample x.RenderRssStream
| 1 -> DotNet.HttpSecureSample x.RenderStream
| _ -> (new Cocoa(x.RenderRssStream)).HttpSample() |> ignore )
TableViewSelector.Configure (x.stack, [|"http - WebRequest"
"https - WebRequest"
"http - NSUrlConnection" |] )
x.window.MakeKeyAndVisible()
true
There are a few departures from the C# sample code which Ill include below now:
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
window.AddSubview (navigationController.View);
button1.TouchDown += Button1TouchDown;
TableViewSelector.Configure (this.stack, new string [] {
"http - WebRequest",
"https - WebRequest",
"http - NSUrlConnection"
});
window.MakeKeyAndVisible ();
return true;
}
void Button1TouchDown (object sender, EventArgs e)
{
// Do not queue more than one request
if (UIApplication.SharedApplication.NetworkActivityIndicatorVisible)
return;
switch (stack.SelectedRow ()){
case 0:
new DotNet (this).HttpSample ();
break;
case 1:
new DotNet (this).HttpSecureSample ();
break;
case 2:
new Cocoa (this).HttpSample ();
break;
}
}
Firstly we are using an lambda expression for the event handler via the Add method rather than the += handler which we use in C#. We are also using F#’s awesome pattern matching feature on the results of x.stack.SelectedRow()
. This allows you to encode complex logic and also have the compiler assist you by catching non covered cases.
I’m going to leave it there for now as I don’t want to bombard any newcomers with tons of new F# features, and I also don’t want to teach any of my regular F# followers how to suck eggs. If anyone has a preference for more in depth comparisons to the C# version then let me know then I can tailor that into further posts on the subject.
Until next time!