Cross Platform C#

You, Too, Can Build Xamarin Apps with F#

Let's break away from C# somewhat and learn how F# is a great fit for crafting mobile applications.

A couple years back I wrote an article for this very column covering how you could leverage many different languages in your Xamarin apps. In it, I included an F# portable class library that was referenced by the main application written in C#. That's still a completely valid approach, but I thought it was a good time to follow that up with a look at how, these days, you can use F# to build the entire app, and why it's a great fit.

F# often gets typecast as being useful for things in the math or science realms, due to its type system and built-in support for things like units, but what often gets lost in the conversation is how great it can be for "normal" everyday applications, as well.

This article isn't meant to be a real introduction to the F# language or its many features. Instead, I'll provide a quick look at how you can use F# to concisely define an application using the same underlying frameworks you'd be using from C#. No prior F# exposure is needed here, so don't worry if you're brand new to it.

As an example, I'll build out a small application written using Xamarin.Forms that allows the user to enter and search for a company, and displays the name and logo for that company on the screen.

File -> New Project

Since I wrote that article, the tooling story around building mobile F# apps has vastly improved. In fact, Xamarin ships F# templates right out of the box, so when starting a new project you can choose between C# and F#. Let's start there and see what a default Xamarin.Forms app looks like in F#:

namespace FSharpForms

open Xamarin.Forms

type App() =
  inherit Application()

  let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
  let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")
  do
    stack.Children.Add(label)
    base.MainPage <- ContentPage(Content = stack) 

One of the nice things about F# is how terse and expressive it can be. Obviously, this app isn't doing a whole lot yet, but the code to get there is extremely minimal. If you've worked with Xamarin.Forms in C# the classes here should feel familiar, because they're the same. While F# is a very functional-focused language, it is multi-paradigm, allowing you to mix in imperative and object-oriented constructs as needed. Here, you create a Label with some default text, stuff it into a StackLayout and slap that on the screen. In just a few lines of code you have a working app and UI. This will be powered by the Clearbit Autocomplete API, which is free.

Getting Some Data
Most apps require some sort of data ingestion, and this one is no different. In C# you might normally reach for HttpClient, which is a great option and also available to you in F# because this is .NET, but instead I'm going to bring in a standard F# library called F# Data to really take advantage of the language. You can add this to your application by installing the FSharp.Data package from NuGet. With that installed, modify the application slightly to fetch JSON from the API and simply stuff it into that label for now, as shown in Listing 1.

Listing 1: FSharpForms, Modified
namespace FSharpForms

open Xamarin.Forms
open FSharp.Data

type App() =
  inherit Application()

  let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
  let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")

  let search() = 
    let json = Http.RequestString 
      "https://autocomplete.clearbit.com/v1/companies/suggest?query=microsoft"
    label.Text <- json

  do
    stack.Children.Add(label)
    base.MainPage <- ContentPage(Content = stack)

    search()

As you can see, this code is almost identical to the original version. A search function is defined that requests the search results for "microsoft" and then puts the JSON response into the label. Clearly, this still isn't a very useful application, but you can start to see how little it took to start adding some real functionality.

Don't Block the UI
If you looked at that last chunk of code and were suspicious about it locking up the UI, you're completely justified. As written, that HTTP request would lock up the UI thread for the duration of the call, which makes for a very bad UX.

F# makes asynchronous programming a breeze (and its async workflow was the inspiration for what eventually made it into C# with async and await), so let's make that search function asynchronous:

let search() = async {
  let! json = Http.AsyncRequestString 
    "https://autocomplete.clearbit.com/v1/companies/suggest?query=microsoft"
  label.Text <- json
}

Looks pretty much the same, right? All you had to do was wrap the function in an async workflow and switch to using the async-ready version of RequestString. You can think of the "let!" symbol here as an await if you're coming from C#. Finally, you just need to tweak how the function is invoked:

search() |> Async.StartImmediate

This will kick off the asynchronous computation immediately from the current thread, meaning that when that "let!" from earlier returns, it will leave you back on the UI thread where it's safe to change the label's text.

Alternatively, you can use Async.Start, which starts the process in the thread pool, and explicitly marshal the UI mutation calls back to the app's UI thread if you prefer. With just a few extra characters here -- not even extra lines -- the app now handles its network request in the background and leaves the UI responsive while it runs.

Parse the Response
Showing raw JSON to the user is hardly a useful experience, so next the app should parse that JSON to display the result in a more useful way. If you were doing this in C#, your first steps would likely be to pull in a library like Json.NET and start defining some model classes to represent the JSON response. You can absolutely do that in F#, as well, but instead, let's look at how the JSON type provider lets you avoid writing all that boilerplate.

In a nutshell, type providers take some sort of data source and create a strongly typed model and API for you at design and compile time. If that sounds weird or confusing, don't worry at all, because you don't need to understand it to easily take advantage of it.

To get started you'll create a type based on the actual JSON data. This can be written as an inline JSON string, a local file or even a URL:

type Company = 
  JsonProvider<"https://autocomplete.clearbit.com/v1/companies/suggest?query=microsoft">

The compiler will go out and determine the model types based on the result of that query, even giving you IntelliSense for those discovered types as you write your apps, which makes for a pretty incredible developer experience. Now all that's needed is to tweak the search function to use that type:

let search() = async {
  let! json = Http.AsyncRequestString 
    "https://autocomplete.clearbit.com/v1/companies/suggest?query=microsoft"
  let company = Company.Parse json |> Seq.head

  label.Text <- company.Name
}

Calling Company.Parse on the returned JSON yields a collection of companies, so this version of search simply grabs the first one and assigns its name to the label in the UI. With two lines, you created rich types for the model and parsed the JSON into them.

Adding an Image
Displaying the name is nice, but let's make things a little more visual and add the company's logo to the UI. Xamarin.Forms and F# make this just a few new lines as well. First, create the image element:

let image = Image(Aspect = Aspect.AspectFit)

Next, add it to the layout:

stack.Children.Add image

Finally, in the search function, you'll need to set its image source to the logo URL:

image.Source <- ImageSource.FromUri (Uri company.Logo)

That's it! If you run the app now you'll see Microsoft's name and logo printed to the UI with just a few extra lines of code.

Accepting User Input
Displaying the Microsoft logo is nice and all, but wouldn't it be great if you let users search for any company they want? Let's go ahead and enable that. First, tweak the StackLayout a little bit to have its content start at the top, and add the entry element:

let stack = StackLayout(VerticalOptions = LayoutOptions.Start, 
  Margin = Thickness(15., 30.))
let input = Entry(Placeholder = "Enter a company name")

Add that input to the stack:

stack.Children.Add input

Update the search function to construct the query URL based on that input:

let search() = async {
  let url = sprintf "https://autocomplete.clearbit.com/v1/companies/suggest?query=%s" 
    (Uri.EscapeUriString input.Text)
  let! json = Http.AsyncRequestString url
  let company = Company.Parse json |> Seq.head

  label.Text <- company.Name
  image.Source <- ImageSource.FromUri (Uri company.Logo)
}

The only changes here are in constructing the URL, so the rest of the function remains identical to what it was before. Finally, instead of triggering the search immediately, you can tie it to the Completed event on the input:

input.Completed.Add (fun _ -> 
  search() |> Async.StartImmediate)

Now if you run the app you can enter any company you like into the text input, and upon hitting return, the app will fetch and display the name and logo it finds (see Figure 1.) Not bad for just a few lines of code!

[Click on image for larger view.] Figure 1. The Final UI Showing Search Results for Microsoft and Xamarin

Wrapping Up
While this is an admittedly trivial app, it does demonstrate many of the kinds of things that all apps will need to do. In about 30 lines of code it defines a UI, reacts to user input, requests data from a web service, parses that data into a fully typed model and then presents that data visually. Listing 2 shows the entire app definition.

Listing 2: FSharpForms, Modified and In Full
namespace FSharpForms

open System
open Xamarin.Forms
open FSharp.Data

type Company = 
  JsonProvider<"https://autocomplete.clearbit.com/v1/companies/suggest?query=microsoft">

type App() =
  inherit Application()

  let stack = StackLayout(VerticalOptions = LayoutOptions.Start, Margin = Thickness(15., 30.))
  let input = Entry(Placeholder = "Enter a company name")
  let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")
  let image = Image(Aspect = Aspect.AspectFit)

  let search() = async {
    let url = sprintf "https://autocomplete.clearbit.com/v1/companies/suggest?query=%s" 
      (Uri.EscapeUriString input.Text)
    let! json = Http.AsyncRequestString url
    let company = Company.Parse json |> Seq.head

    label.Text <- company.Name
    image.Source <- ImageSource.FromUri (Uri company.Logo)
  }

  do
    stack.Children.Add input
    stack.Children.Add label
    stack.Children.Add image
    base.MainPage <- ContentPage(Content = stack)

    input.Completed.Add (fun _ -> 
      search() |> Async.StartImmediate)

F# has a reputation for being complicated, and it's easy to be intimidated by some of the terminology you'll hear around functional programming circles. The reality is that, while some things can be complicated or different if you're coming from an object-oriented world, none of that prevents you from taking advantage of the language. You still get access to the .NET Framework features you know and love, plus everything else F# brings to the table. None of this is meant to disparage C#, either, which is a fantastic language, as well, but hopefully this helps encourage some of you to play around with F# for things you're building. You just might find it's more practical and less specialized than you had thought.

About the Author

Greg Shackles, Microsoft MVP, Xamarin MVP, is a Principal Engineer at Olo. He hosts the Gone Mobile podcast, organizes the NYC Mobile .NET Developers Group, and wrote Mobile Development with C# (O'Reilly). Greg is obsessed with heavy metal, baseball, and craft beer (he’s an aspiring home brewer). Contact him at Twitter @gshackles.

comments powered by Disqus

Featured

Subscribe on YouTube