I'm currently evaluation Xamarin as a replacement for a Phonegap application. The first thing I'm evaluating is building UIs in code. Since most of the example code is in C#, I initially built my test UI with it. In poking through the Xamarin documentation I came across the MonoTouch.Dialog toolkit (hereafter MT.D). MT.D is a declarative framework for creating iOS UIs. Here is the code for the MasterViewController of a UISplitView (this is a minor modification to the code found in the
Xamarin documentation):
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.Dialog;
using System.Linq;
namespace CSharpTabbed
{
public partial class MasterViewController : DialogViewController {
Section testSection;
public MasterViewController () : base (null)
{
Root = new RootElement ("Items") {
new Section(){
new StringElement("Section 1"),
from num in Enumerable.Range(1,10)
select new ImageElement(new UIImage("first.png"))
},
new Section(){
new StringElement("Section 2"),
new Section(){
from num in Enumerable.Range(1,10)
select new StringElement("Item" + num})
}
},
new Section(){
new StringElement("Section 3"),
new Section(){
from num in Enumerable.Range(1,10)
select new StringElement("Item" + num)
}
}
};
}
public override bool ShouldAutorotateToInterfaceOrientation
(UIInterfaceOrientation toInterfaceOrientation)
{
return true;
}
}
}
And the resulting UI:
Since this requires the construction of a lot of collections I thought I would try it in F#. Here is my direct conversion from C# to F#:
1: namespace GoFormz
2:
3: open System
4: open System.Drawing
5: open MonoTouch.Foundation
6: open MonoTouch.UIKit
7: open MonoTouch.Dialog
8: open System.Linq
9:
10: [<Register ("MasterViewController")>]
11: type MasterViewController (window:UIWindow) as this =
12: inherit DialogViewController (new RootElement("Items"))
13:
14: do this.Root.Add [new Section(Elements = new ResizeArray<Element>( [yield new StringElement("Section1") :> Element;
15: for i in 1..10 -> new StringElement("num"+i.ToString()) :> Element]));
16: new Section(Elements = new ResizeArray<Element>( [yield new StringElement("Section1") :> Element;
17: for i in 1..10 -> new StringElement("num"+i.ToString()) :> Element]));
18: new Section(Elements = new ResizeArray<Element>( [yield new StringElement("Section1") :> Element;
19: for i in 1..10 -> new StringElement("num"+i.ToString()) :> Element]))];
20:
21: override this.ShouldAutorotateToInterfaceOrientation toInterfaceOrientation =
22: true
namespace System
namespace System.Drawing
namespace System.Linq
type MasterViewController =
class
inherit obj
new : window:'a -> MasterViewController
override ShouldAutorotateToInterfaceOrientation : toInterfaceOrientation:'a -> 'b
end
Full name: GoFormz.MasterViewController
val window : 'a
val this : MasterViewController
type ResizeArray<'T> = Collections.Generic.List<'T>
Full name: Microsoft.FSharp.Collections.ResizeArray<_>
type: ResizeArray<'T>
implements: Collections.Generic.IList<'T>
implements: Collections.Generic.ICollection<'T>
implements: seq<'T>
implements: Collections.IList
implements: Collections.ICollection
implements: Collections.IEnumerable
override MasterViewController.ShouldAutorotateToInterfaceOrientation : toInterfaceOrientation:'a -> 'b
Full name: GoFormz.MasterViewController.ShouldAutorotateToInterfaceOrientation
This isn't really any better than the C# due to all the casting and the need to interface with Collections.Generics.List. It would also be nice if I could use any collection type I want. To address these issues, I created a library which allows more idiomatic F# usage of MT.D. Usage looks like this:
1: do this.Root.Add [createSection [yield createStringElement "Section1";
2: for i in 1..10 -> createStringElement ("num"+i.ToString())];
3: createSection [yield createStringElement "Section2";
4: for i in 1..10 -> createStringElement ("num"+i.ToString(), "value")];
5: createSection [yield createStringElement "Section3";
6: for i in 1..10 -> createStringElement ("num"+i.ToString(), fun ()->Console.WriteLine "test")]]
This gives compile time checking without having to use a lot of type annotations while still maintaining type safety.
In progress library
here.