Using WPF Elements from F#

WPF and F#? It’s not a natural mix — Visual Studio doesn’t provide templates or tooling for F# WPF projects, and WPF’s implicit architecture normally implies mutable view models which are at odds with F#’s preference for immutable data types. But sometimes a project comes along which seems like a great fit for F#, and for a WPF front end. A great example is data visualisation. Retrieving and processing the data is exactly what F# does well, and innovative ways of presenting data are much easier to implement on WPF than on any other platform; and in a visualisation scenario the main view model is typically immutable.

I’m going to look at two ways of combining F# and WPF. I’ll be using the Chart control from WPF Elements as my main example, but a lot of what I talk about here is equally applicable to any other WPF control, built-in or third-party.

Solution 1: Hybrid C# and F# Solution

The traditional way of using F# in a WPF application is to put the F# code into a class library, then invoke that class library from a C# or Visual Basic WPF application. This works very easily — a C# application can call a F# class library just as easily as it can a C# class library, with full intellisense and debugging and everything else you’d expect.

For this example, I’m going to keep the F# class library very simple. In reality, you probably wouldn’t create a separate class library for something this basic. F# really starts to shine when you’re doing a bit more processing on your data, but to keep things simple I’m not going to do much more than download it.

The data I’m going to use is the London Borough Profiles from the Windows Azure Datamarket. This is dead easy to use in F# 3.0 thanks to the OData type provider:

open Microsoft.FSharp.Data.TypeProviders
 
type Boroughs = ODataService<"https://api.datamarket.azure.com/GreaterLondonAuthority/LondonBoroughProfiles/">
 
let dataContext = Boroughs.GetDataContext()
dataContext.Credentials <- System.Net.NetworkCredential(YourUserName, YourAccountKey)

For my view model, I want to extract just a subset of this data, so I define a couple of F# types to surface it:

open System.Collections.Generic
 
type BoroughInfo = {
  Area : string
  MaleLifeExpectancy : float
  FemaleLifeExpectancy : float
  Employment : float
}
 
type ViewModel = {
  Boroughs : List<BoroughInfo>    // not BoroughInfo list -- see below
  National : BoroughInfo
}

These are F# immutable record types. We don’t need to modify the data, so immutable types are easier to write and we don’t need to muck around with all that tedious INotifyPropertyChanged stuff. The view model is going to include a list of entries for individual boroughs, plus a ‘dummy’ borough representing national averages so I can display them alongside the per-borough data.

One gotcha is that the WPF Elements charting DataSeries expects an IList as its ItemsSource. The F# list type doesn’t implement IList, so we have to be sure to make ViewModel.Boroughs a BCL List instead of a F# list.

Now we can build our view model:

let (national, boroughs) =
  dataContext.LondonBoroughProfiles
  |> Seq.filter (fun r -> r.MaleLifeExpectancy20072009.HasValue && r.FemaleLifeExpectancy20072009.HasValue)
  |> Seq.map (fun r -> { Area = r.Area; MaleLifeExpectancy = r.MaleLifeExpectancy20072009.Value; FemaleLifeExpectancy = r.FemaleLifeExpectancy20072009.Value; Employment = r.EmploymentRate2009.Value })
  |> Seq.toList
  |> List.partition (fun b -> b.Area = "National Comparator")
 
let viewModel = { Boroughs = List<_>(boroughs); National = List.head national }

Most of this should be self-explanatory — we are downloading all the borough data from the data context provided by the OData type provider, filtering out a couple of containers that don’t have data, and mapping away the nullable values. (We could have done some of this using F# query expressions, but it’s not worth it for this data set.) The only thing that may be unfamiliar is List.partition, which splits a list into two lists, the first containing things that satisfy the predicate and the second containing things that don’t. The assignment therefore puts the ‘National Comparator’ pseudo-borough into the ‘national’ list, and the real boroughs into the ‘boroughs’ list.

The end result of all this is a value called ‘viewModel’ of type ViewModel, and we can now consume this from a C# application:

// Code-behind for MainWindow.xaml -- or of course you could automatically
// wire it up using Caliburn Micro.
 
public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
 
    DataContext = Data.viewModel;
  }
}
<e:Chart Margin="12">
  <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding MaleLifeExpectancy}" SeriesBrush="Navy" />
  <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding FemaleLifeExpectancy}" SeriesBrush="Red" />
  <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding Employment}" YAxisTitle="Employment (%)" SeriesBrush="Green" />
  <e:Chart.XAxis>
    <e:ChartAxis LabelRotation="90" LabelStep="1" MajorTickSpacing="1" />
  </e:Chart.XAxis>
  <e:Chart.YAxis>
    <e:ChartAxis Minimum="65" Maximum="90" Title="Life Expectancy (yr)" />
  </e:Chart.YAxis>
  <e:Chart.AlternativeYAxes>
    <e:ChartAxis Minimum="50" Maximum="100" Title="Employment (%)" />
  </e:Chart.AlternativeYAxes>
</e:Chart>

Solution 2: All F# Solution

With F# 3.0, though, it’s now feasible to build WPF applications entirely in F#, without needing to put the user interface into C#. In practice I know most readers of this blog will probably feel more at home in C# than in F# so they’ll want to use F# only for the core data processing anyway — but I think it’s interesting to know how F# 3.0 enables XAML support, plus there are a couple of things that may not be quite so obvious! (This example is based on Steffen Forkmann’s WPF Designer for F# announcement, which is in turn based on Johann Deneux’ XAML type provider.)

The first thing we need to do is create a Windows Application F# project. There isn’t a template for this, but we can take our class library project, go into Properties > Application, and change the Output Type to Windows Application (and add a Program.fs file to contain the application code). Or we can create a new F# Application project and change the Output Type from Console Application to Windows Application.

Next we need the XAML type provider. This is available as a NuGet package from the FSharpx folks. Right-click the F# project, choose Manage NuGet Packages, search for FSharpx.TypeProviders and click Install. (Learn more about FSharpx here.)

We also need to add references to the WPF assemblies (WindowsBase, PresentationCore, PresentationFramework and System.Xaml) and to the WPF Elements DLL.

The last piece of plumbing we need is to handle the licensed controls in WPF Elements. Copy the licenses.licx file from the WPF Elements Sample Explorer to the F# project directory, include it in the F# project and set its Build Action to Embedded Resource.

Now we’re ready to roll, where by ‘roll’ I mean create an actual WPF window.

Right-click the project and choose Add New Item. There’s no XAML template but just choose XML File and change the file extension to .xaml, e.g. MainWindow.xaml. Replace the contents of the .xaml file with the following:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:e="clr-namespace:Mindscape.WpfElements.Charting;assembly=Mindscape.WpfElements"
        Title="MainWindow" Height="500" Width="900">
 
  <e:Chart>
    <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding MaleLifeExpectancy}" SeriesBrush="Navy" />
    <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding FemaleLifeExpectancy}" SeriesBrush="Red" />
    <e:LineSeries ItemsSource="{Binding Boroughs}" XBinding="{Binding Area}" YBinding="{Binding Employment}" YAxisTitle="Employment" SeriesBrush="Green" />
    <e:Chart.XAxis>
      <e:ChartAxis LabelRotation="90" LabelStep="1" MajorTickSpacing="1" />
    </e:Chart.XAxis>
    <e:Chart.YAxis>
      <e:ChartAxis Minimum="65" Maximum="90" />
    </e:Chart.YAxis>
    <e:Chart.AlternativeYAxes>
      <e:ChartAxis Minimum="50" Maximum="100" Title="Employment" />
    </e:Chart.AlternativeYAxes>
  </e:Chart>
 
</Window>

One little nasty to watch out for: the F# XAML type provider currently handles only ‘clr-namespace’ namespaces. So we have to refer to the Mindscape.WpfElements.Charting namespace by name, instead of using the URI. Other than that this is the same XAML as in the C# application.

Finally we need to write some code to launch this window and associate it with our view model. In C#, the project template handled this for us but in F# we need to do it ourselves. Fortunately all the hard work is done by the XAML type provider:

open System
open System.Windows
open FSharpx
 
type MainWindow = XAML<"MainWindow.xaml">  // creates the MainWindow type from the MainWindow.xaml file
 
let loadWindow() =
  let window = MainWindow()  // creates a new instance of MainWindow
  window.Root.DataContext <- Data.viewModel
  window.Root
 
[<STAThread>]
(new Application()).Run(loadWindow())
|> ignore

You can now build and run the application, and you’ll find it works just like the C# one. Of course, it has taken a bit more effort to set up, but that’s a one-off, and you can now enjoy using F# for your interaction logic as well as your business logic.

You can download the source for the F# WPF Elements demo project here. You will need Visual Studio 11 Beta, and a copy of Mindscape WPF Elements (download the free edition including a 60-day trial of the charting controls). (To run the program, you’ll also need to sign up for the free London Borough Profiles data set on Azure Datamarket.) If you have any questions or problems, post in the comments or the support forum!

Tagged as F#, WPF Elements

Codemania: How to not write a for loop

It was great to see so many Mindscape customers at Codemania. We were proud to sponsor the first Codemania and it looks like everyone is looking forward to another one next year!

In the meantime, here are the slides and code samples from the ‘How to Not Write a For Loop’ talk:

And don’t forget that if you attended Codemania then we’re offering you a free copy of Web Workbench Pro.

Tagged as Events, F#

5 1/2 F# features every C# programmer should lust after

C# is a great programming language, but there’s still a bevy of features in other programming languages that I often wish were in C#. I’m doing quite a bit of work in F# nowadays, and I thought it would be fun to jot down a few F# features that I really miss when I come back to C#.

1. The Option type

Tony Hoare, the inventor of the null reference, called it his ‘billion dollar mistake.’ Null is a disaster because it means that every reference type has a magic value that will destroy your program. For value types, we now have ‘normal’ value types and nullable value types to express the difference between, say, ‘this function returns an integer’ and ‘this function might return an integer, or it might not.’ But we don’t have that for reference types.

F# provides the Option type to distinguish between ‘there definitely is a value’ and ‘there might or might not be a value.’ F#’s Option is a bit like Nullable but can be used with any type, value or reference, and comes equipped with helper functions and pattern matching support. Here’s an example of Option in use:

let names = [ "alice"; "bob"; "carol"]
let name = List.tryFind (fun s -> length s < 4) names  // returns an Option
match name with
| Some n -> printfn "%s has a short name" n
| None   -> printfn "They all have long names"

Notice that if we erroneously try to use the option returned from List.tryFind as if it were a real string, the error is caught at compile time:

let names = [ "alice"; "bob"; "carol"]
let name = List.tryFind (fun s -> length s < 4) names  // returns an Option
printfn "%s has a short name" name  // Error! Expected string but got string option

In C#, the ‘not found’ case would be represented by null, and the compiler would not be able to catch the potential error.

The FSharpx project provides some helpers to make it easy to use the F# Option type from C#, though it’s of limited use except in interop because the C# compiler still won’t stop you using nulls even in non-optional situations.

2. Immutable record types

Immutable types are a great way to improve the correctness of programs. Any type that represents a value, rather than an entity which needs to preserve identity as its attributes change, should be immutable. Even quite complex objects, such as expression trees in LINQ or syntax trees in Roslyn, benefit from immutability. Unfortunately, C# makes it far more effort to write immutable types than mutable ones. Here’s two ways to implement a 2D Point type in C#, one mutable (wrong!) and one immutable (right!):

public class MutablePoint {
  public double X { get; set; }
  public double Y { get; set; }
}
 
public class ImmutablePoint {
  private readonly double _x;
  private readonly double _x;
 
  public ImmutablePoint(double x, double y) {
    _x = x;
    _y = y;
  }
 
  public double X { get { return _x; } }
  public double Y { get { return _y; } }
}

The safe, immutable type is more than twice as long!

Contrast this with F#:

type Point = { X : float; Y : float }

It’s short, it’s immutable and as a special wonder bonus it’s got proper value equality built in for free. And I want it in C#, pronto.

3. Object expressions

Object expressions are a great feature for when you want to implement an interface or override a class member without going to the trouble of spinning out an entire class or subclass for it. This can dramatically reduce the amount of code particularly when you need to capture local variables for your implementation or override. (If you’re familiar with Java’s local classes, object expressions are a lot like that.) Here’s an example using the LightSpeed IAuditInfoStrategy interface:

// blame takes a string and returns an IAuditInfoStrategy
let blame x = {
  new IAuditInfoStrategy with
    member this.Mode = AuditInfoMode.Custom
    member this.GetCurrentUser() = x }

In C#, I would have had to write out a ScapegoatingAuditInfoStrategy class with a field to hold the blamee and a constructor to pass the blamee into the class. In F#, I just told the compiler to make me an IAuditInfoStrategy that always blamed x, and it did. I often end up writing lots of little classes to capture small nuggets of code or fragments of state, and it would be great if C# had something like object expressions to make it easier.

More about object expressions here.

4. Partial application

I actually like C# lambda syntax more than F#. This is just as well, because I have to write a lot more lambdas in C# than I do in F#. The reason is that in F# I can use a trick called partial application to reuse a ‘normal’ function just with particular arguments. Let’s see an example.

Suppose I want to double every element in a sequence. I can do that using the LINQ Select operator, or its F# equivalent Seq.map:

// C#
var doubled = values.Select(v => v * 2);
// F#
let doubled = Seq.map (fun v -> v * 2) values

C# code is more concise than F# code, right? Not so fast! In F# we can partially apply the * function and save ourselves writing the lambda!

let doubled = Seq.map ((*) 2) values

Of course you can do this with your own functions too:

let isDivisibleBy x y = y % x = 0
let evens = List.filter (isDivisibleBy 2) values  // rather than (fun v -> isDivisibleBy 2 v)

Partial application reduces the amount of lambda noise in the code, and can also be useful in creating new functions by specialising existing ones. You can read more about partial application in this series and (more concisely) in this article.

5. Pattern matching

I’ve written extensively about pattern matching elsewhere, and it’s too big a topic to explain thoroughly here. Pattern matching allows you to combine programming by cases (like a switch statement) with custom logic (like an if statement) and decomposing composites to get the bits you’re interested in (like a series of property accesses or collection operations). It’s also extensible using active patterns, which means you can build classifiers independently of the routines that use the classification. And patterns compose far more conveniently than imperative code.

One often-overlooked but very powerful feature of pattern matching is that it can be used in a let statement. This allows you to effectively return multiple values from a function without having to create a XxxResult type or explicitly picking apart a tuple. Combined with the F# compiler being able to silently translate C# out-parameters into tupled return values, this creates some neat, readable idioms:

let dict = new Dictionary<string, string>()
let (found, result) = dict.TryGetValue("alice")
 
// C# equivalent
var dict = new Dictionary<string, string>();
string result = null;
bool found = dict.TryGetResult("alice", out result);

There’s much more to pattern matching than this, including recursing over lists, visiting over class hierarchies (discriminated unions), working safely with options, type-checking and casting, and, well, the list goes on. I use pattern matching all the time in F# and I always miss it when I have to come back to C# and write imperative (if-style) code to distinguish between cases.

5 1/2. Async

F#’s async workflows make it easy to write asynchronous code in a readable, easy to understand, top-to-bottom way. This is compelling — so compelling, in fact, that a similar feature is going to be adopted into C#. F# still has a bunch of async features that haven’t made it into C#, notably async agents, but for the core scenario C# programmers no longer need to be envious!

And there’s more

There’s so much in F# that would be a huge boon for C# that I could easily have made this a top 10 list. Some of F#’s features can be used from C# (read Mauricio Scheffer’s great post on ’10 reasons to use the F# runtime in your C# app’) but a lot of the features I miss are part of the language. For example, I’d love to see F#-level type inference in C#. After all, which one of these declarations do you find easier to read?

// C#
public static IEnumerable<TResult> Map<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) { ... }
// F#
let map selector source = ...  // F# infers types and generic type parameters from implementation

Or how about recursive iterators? Or an interactive prompt in Visual Studio, so you could try out snippets or run demos without having to build a console or NUnit project? (Roslyn has a C# Interactive window, but Roslyn’s still some way off!) And looking to the future, F# type providers open up a whole new order of expressiveness beyond standard code generation techniques.

So what’s in your top 5? What F# features do you miss when you go back to C#?

Tagged as F#

F# type providers – as if by magic…

F# 3 will introduce a new feature called type providers. A type provider is a gadget that creates new types for you. The F# team, reflecting their focus on data access, have shipped type providers for databases, DBML and EDMX files, and WSDL and OData services. If you use one of these type providers in your F# program, it will give you strong-typed access to the database or service. So from this point of view it’s a lot like the code generator that runs when you create a DBML or EDMX file, or do an Add Service Reference to a Web service or OData service.

But F# type providers can create any kind of type, and they don’t need to consult an external resource to do it. This means a type provider can be used to automagically replace repetitive boilerplate code with a simple declaration.

Consider a vector maths library. Users will want to be able to create vectors with various numbers of dimensions — 2D vectors, 3D vectors, etc. And they might even want to be able to create vectors with the same number of dimensions but different names (for example, Horizontal/Vertical instead of X/Y). In C#, you’d have to write out each vector type by hand. In F# 3, you can ship a Vector type provider, and users can create their desired vector types from that:

type Vector2D = Vector<"X", "Y">
type Vector3D = Vector<"X", "Y", "Z">
type VectorHV = Vector<"Horizontal", "Vertical">
 
let v1 = Vector2D()
v1.X <- 100.0
v1.Y <- 200.0
let v2 = VectorHV()
v2.Horizontal <- 300.0
v2.Vertical <- 400.0

Each of the created types is a real compile-time type, with type safety enforced by the F# compiler. For example, if the type provider supplies a dot product operation with vectors of the same kind (only), the F# compiler will check that the user doesn’t take dot products between vectors of different kinds:

let v1 = Vector2D()
let v2 = Vector2D()
let vh = VectorHV()
 
let v1v2 = v1.DotProduct(v2)  // okay
let v1vh = v1.DotProduct(vh)  // type checks

The created vector types work exactly as if you had written them longhand, but without all the effort, and without the limitation of having to guess what types your users will need.

Implementing a type provider

The F# team have indicated that they’ll be shipping the source for some sample type providers soon, which will include some handy helpers which should rather simplify the process of writing type providers, but for now it’s still not too difficult to implement type providers directly against the interfaces. Here’s an outline, albeit with plenty of rough edges.

The first thing you need to do is create a F# 3.0 library project. At the moment, this requires the Visual Studio 11 preview (the full version, not the Metro apps version). And you’ll need to apply TypeProviderAssemblyAttribute to that library:

[<assembly: TypeProviderAssembly>]
do ()

Next, you’ll need to implement the type provider class itself. This is a normal F# class which implements the ITypeProvider and IProvidedNamespace interfaces, and has the TypeProviderAttribute:

[<TypeProvider>]
type VectorProvider() =
  interface ITypeProvider with // ...
  interface IProvidedNamespace with // ...

A type provider can provide multiple kinds of types, but for this example I’m going to assume that the provider only does Vector types. This keeps my implementation simple because I don’t need to keep dispatching on ‘what kind of type is the user creating.’ This makes it pretty easy to implement IProvidedNamespace:

// Cheating for simplicity
type Vector() = inherit obj()
 
[<TypeProvider>]
type VectorProvider() =
  interface IProvidedNamespace with
    member this.ResolveTypeName(typeName) = typeof<Vector>
    member this.NamespaceName with get() = "Mindscape.Vectorama"
    member this.GetNestedNamespaces() = [| |]
    member this.GetTypes() = [| typeof<Vector> |]

What’s that do-nothing Vector type for? Well, when the user of the type provider writes Vector<…>, F# wants to interpret “Vector” as a type name. The real type providers included with F# 3.0 create synthetic types to carry the desired provider names, but I’m too lazy to do that, so I’ve just created a dummy type to carry the name “Vector” for me.

For a simple demo, much of the ITypeProvider implementation can also be kept trivial:

[<TypeProvider>]
type VectorProvider() =
  let invalidation = new Event<EventHandler, EventArgs>()
  interface ITypeProvider with
    member this.GetNamespaces() = [| this |]
    member this.Dispose() = ()
    [<CLIEvent>]
    member this.Invalidate = invalidation.Publish

The meat of the type provider is in the remaining ITypeProvider methods: GetStaticParameters, ApplyStaticArguments and GetInvokerExpression.

What can the user specify about the type?

GetStaticParameters specifies what parameters the user can pass to the type provider when they create a type. In our case, we want the user to be able to pass the names of the axes of their vector type — that is, the parameters are an arbitrary number of strings. However, GetStaticParameters doesn’t have a way to indicate “any number of parameters,” so we have to settle for, for example, “you can pass 7 parameters, but they’re all optional.” (In reality you’d make the first one mandatory, but I want to keep things simple.) If we later need to support 8-dimensional vectors, we can simply update the limit in the type provider. The parameters are going to become property names, so they need to be strings. We’ll create a helper method to produce ParameterInfo objects with the right name, data type and optionality.

module Helpers =
  let stringParameter index defaultVal =
    { new ParameterInfo() with
      override this.Name with get() = sprintf "axis%d" index
      override this.ParameterType with get() = typeof<string>
      override this.Position with get() = 0
      override this.RawDefaultValue with get() = defaultVal
      override this.DefaultValue with get() = defaultVal
      override this.Attributes with get() = ParameterAttributes.Optional
    }
 
open Helpers

and then use this to specify what parameters the user can provide to the Vector type provider:

member this.GetStaticParameters(typeWithoutArguments) =
  [1..7] |> List.map (fun i -> stringParameter i "")
         |> List.toArray

This is enough to enable the user of our library to type Vector<"X", "Y"> with intellisense on the parameters. Now we need to actually create a type to realise the user’s specification.

Building the concrete type

Building the type from the parameters provided by the user is the job of the ApplyStaticArguments method. For the Vector demo, I’ll just create a class with properties named for each of the user parameters, and a DotProduct method. (A better provider would create an immutable value type, but I want to keep it simple.)

At the moment, it seems that F# requires ApplyStaticArguments to create a physical assembly on disk. If you build the type in memory, you get strange path errors. I’m not sure if there’s a way around this, but for now I’ll just live with it and litter my temp directory with temporary assemblies.

So the code generator for vector types looks something like this:

module Helpers =
  let makeClass body name =
    let code = "namespace Mindscape.Vectorama { public class " + name + " {" + Environment.NewLine + body + Environment.NewLine + "} }"
    let dllFile = System.IO.Path.GetTempFileName()
    let csc = new Microsoft.CSharp.CSharpCodeProvider()
    let parameters = new System.CodeDom.Compiler.CompilerParameters()
    parameters.OutputAssembly <- dllFile
    parameters.CompilerOptions <- "/t:library"
    // Ignoring error checking
    let compilerResults = csc.CompileAssemblyFromSource(parameters, [| code |])
    let asm = compilerResults.CompiledAssembly
    asm.GetType("Mindscape.Vectorama." + name)
  let makeVector name argnames =
    let propNames = argnames |> Seq.filter (fun arg -> arg <> null && not (String.IsNullOrWhiteSpace(arg.ToString())))
                             |> Seq.map (fun arg -> arg.ToString())
                             |> Seq.toList
    let props = propNames |> List.map (fun arg -> "public double " + arg + " { get; set; }")
                          |> String.concat Environment.NewLine
    let dotProductBody = propNames |> List.map (fun arg -> sprintf "this.%s * other.%s" arg arg)
                                   |> String.concat " + "
    let dotProduct = sprintf "public double DotProduct(%s other) { return %s; }" name dotProductBody
    let body = props + Environment.NewLine + dotProduct
    makeClass body name

This isn’t as intimidating as it looks! The makeClass function wraps a code string in a namespace and class declaration, compiles it and returns the compiled type. The makeVector function removes empty parameters (remember we had to permit lots of parameters but defaulted unused ones to be blank), then spits out a property for each surviving parameter, and a DotProduct method generated by iterating over the parameters.

It turns out that makeVector is pretty much all we need to implement ApplyStaticArguments. The F# compiler tells us the name of the type the user wants us to provide, and the list of parameters supplied by the user, and all we need to do is pass them on to makeVector:

member this.ApplyStaticArguments(typeWithoutArguments, typeNameWithArguments, staticArguments) =
  makeVector typeNameWithArguments staticArguments

Compiling property and method calls to the created type

We are nearly there! Our type provider now provides types to the user on demand, but the user will still get errors if they try to instantiate or invoke those types. GetInvokerExpression is the final piece of the jigsaw, the piece which tells the F# compiler how to generate code for method invocations on the generated type. It’s not yet clear to me how comprehensive GetInvokerExpression has to be, but for the simple Vector example, we just need to handle a couple of cases — construction and method invocation:

member this.GetInvokerExpression(syntheticMethodBase, parameters) =
  match syntheticMethodBase with
  | :? ConstructorInfo as ctor -> Expression.New(ctor) :> Expression
  | :? MethodInfo as mi -> let args = parameters |> Seq.skip 1 |> Seq.cast<Expression>
                           Expression.Call(parameters.[0], mi, args) :> Expression
  | _ -> let pnames = parameters |> Seq.map (fun p -> p.Name) |> String.concat ", "
         failwith (sprintf "ERROR: Don't know what to do in GetInvokerExpression - %s(%s)" syntheticMethodBase.Name pnames)

The most alarming bit about this code is probably the strange F# type operators. We’re just seeing whether F# wants to compile a constructor or a method call, packaging up the appropriate expression tree, then upcasting to the Expression base type to stop F# whining about type mismatches.

And we’re done!

Well, okay, there’s a lot of tidying up to do. But hopefully the samples promised by the F# team will help with that. And at any rate we now have a Vector library that users can use to define Vector types of arbitrary complexity (well, up to 7 dimensions anyway) with a single line of code:

[<Generate>]
type Vector3D = Vector<"X", "Y", "Z">
 
let v3 = Vector3D()
v3.X <- 1.0
v3.Y <- 2.0
v3.Z <- 3.0

(If you count two lines of code here, well, fair enough, but the GenerateAttribute will be removed before the final release.)

As if by magic…

Obviously, the Vector example is pretty trivial, and for most applications it would be easier to write the boring Vector code longhand rather than writing a whole type provider. But the possibilities for this seem endless. Type providers don’t just have to be about data access. In the same way as dynamic programming already enables users to create their own APIs without having to write their own implementations, type providers allow users to create their own APIs without having to write their own implementations, but this time with all the benefits of type checking, intellisense and so on. And of course type providers can be as sophisticated as you like, far more sophisticated than my simple example.

Oh, and one more thing. Although only the F# compiler can invoke type providers, the types generated by the provider are real, compiled-in types. That means you can use those types from C# or Visual Basic code just by referencing the F# project that declares them.

Yep, this is going to be pretty cool.

Tagged as F#

F# Friday – 1 hour video presentation

So you lapped up Ivan’s Dynamic & Meta Programming in .NET 4 earlier in the week? Thought it was a bit too easy going and want something to sink your teeth into this Friday afternoon? Look no further than Ivan’s presentation on F# programming!

Watch the video online – be sure to rate it highly!

What more could you want on a Friday afternoon? I mean, maybe a beer but…

Question: Do you enjoy learning about F#? Would you be interested in an instructional series on how to work better with it? Drop us a comment if you’d be interested!

Tagged as Events, F#

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top