Chapter 17

Packaging Your Code & Interfacing with .NET Libraries

Main Page

Introduction

In this chapter, we discuss two pragmatic topics: how to package your code for consumption, and how to consume code in other libraries. The intra- and inter-language capabilities of .NET languages offer a certain appeal for many developers, enabling them to apply the most appropriate language to the task at hand without sacrificing overall system compatibility.

Organizing Your F# Code

Namespaces

A namespace is the highest level of code organization. A namespace enables us to organize our code into logically related areas of functionality by grouping program elements under a common naming umbrella. The namespace becomes an intrinsic part of the name of the elements within it. Namespaces are used primarily to structure our code hierarchically and to avoid namec conflicts. To specify a namespace, you use the following syntax:

namespace [parent-namespaces.]identifier

Let’s suppose we’re creating an enterprise application, and we decide to divide the functionality into several tiers – a UI tier, a business tier, and a database tier. To keep code logically and semantically separated, we could define namespaces that segragate this functionality, e.g.:

namespace UI
namespace Business
namespace Database

We can include “sub” or “child” namespaces under a “parent”, to further refine and separate out our code’s functionality, using dot notation e.g.,:

namespace Database.SQLServer
namespace Database.SQLServer.Client
namespace Database.MySQL

Namespaces cannot directly contain values and functions. Instead, they can contain modules, types and do bindings. Namespaces can be declared explicitly (as shown above) with the namespace keyword, or implicitly via declaring modules.

Namespaces can span multiple files in a single project or compilation unit. The term namespace fragment describes the part of a namespace that is included in one source file. Namespaces can also span multiple assemblies. For example, the System namespace includes the whole .NET Framework, which spans many assemblies and contains many nested (“child”) namespaces.

Modules

Another grouping mechanism that F# provides is the module. An F# module is a simple mechanism for grouping types, values, function values, and the code in do bindings. F# compiles a module into a common language runtime (CLR) class that has only static members.  We declare modules using the following syntax:

// Top-level module declaration

module [accessibility-modifier] [qualified-namespace.]module-name
    declarations

// Local module declaration

module [accessibility-modifier] module-name =

   declarations

Modules impact identifier scope. Inside a module, identifiers are all visible to one another, but are not visible externally. To reference identifiers defined in external modules , your code must full qualify the identifier names, e.g., MyModule.myIdentifier or use the open keyword as discussed in Chapter 2.

By default, each module is contained in a single source file. The entire contents of the source file make up the module, and if the module isn’t explicitly named, it gets the name of its source file, with the first letter capitalized, e.g., a file named fileIO.fs would produce a module called FileIO.

Top Level Modules

To explicitly name a module, we use the following syntax at the top of the F# source file:

module [accessibility-modifier] [qualified-namespace.]module-name
declarations

When we explicitly define a module in this way, we are defining a top-level module.  Providing a top-level module is optional, and if we choose to do so, the module name must appear as the first declaration in the source file. A top-level module lends its name to the entire source file, which means that all elements in the source file are intrinsically compiled into the static class produced by the compiler. Note that you do not need to indent structures within a top-level module to have them be included in the module. In the following example, we show an F# file (program.fs) that contains a top-level module called Utils:

module Utils

 

let ReverseString s = ()

let IsPrime = ()

The way this is written, this code defines two functions that are named Utils.ReverseString and Utils.IsPrime. If we were to omit the top-level module declaration, these functions would have been part of the default module Program, which would have been generated by F# based on the name of the file, program.fs, with the first letter capitalized.

Local Modules

In contrast to top-level modules, F# enables us to define local modules, which are used to name and organize small sections of a larger file. To define a local module, you use the following syntax:

module [accessibility-modifier] module-name =

   declarations

Note the equal sign (=) at the end of the module name, as well as the indented module declarations.

Similar to namespaces, module names can contain dots, allowing us to organize and structure the name into a hierarchy of meaningful parts.  In the following example, we have a file (program.fs) that will provide for us the default top-level module name Program. Within program.fs, we define two local modules that organize and scope the contained constructs:

// Default module generated is Program

module Employee =

    let mutable Name = ""

    let CalcPay emp = ()

module Company =

    let GetEmployees = ()

    let Hire e = ()

This code defines two local modules, Employee and Company. Emplopyee and Company define two separate naming scopes. To access CalcPay from outside this file, for example, clients would need to access Employee.CalcPay, as this is it’s full name. Continuing with this example, here is a snippet of code used to access CalcPay:

open Program
Employee.CalcPay 123

Because Employee is a module in its own right, we can also code this call as follows:

open Program.Employee

CalcPay 123  


Nested Modules

F# also enables is to nest modules within one another. Nested modules must appear indented under their parents and their names cannot include dots.  In the following example, we define three local modules with increasing degrees of nesting. Through this example, we also demonstrate how modules introduce scope:

// Default module generated is Program

 

module GrandPa =

    let Name = "Philip"

 

    module Dad =

        let Name = "Adam"

   

        module Son =

            let Name = "Tom"

The following code snippet makes use of these nested modules:

open Program.GrandPa

 

let printNames =

    printfn "%s" Name

    printfn "%s" Dad.Name

    printfn "%s" Dad.Son.Name

As you can see here, the same identifier, Name, can be used in each module without any problems, due to the fact that the full name, e.g., Dad.Name, is unique.

Module Aliases

It is sometimes convenient to provide short or distinct names to modules. This can help with potential name clashes and/or save a bit of typing. To access a module and give it an alias, you use the following syntax:

module alias = existing-module-name

Let’s look as an example. Here, we define a long module name, and define a function inside the module:

module MyVery.Long.Module.Name

let MyFunc() =

    printfn "MyFunc"

We can access MyFunc in another file using a module alias, like this:

module MyModule = MyVery.Long.Module.Name

MyModule.MyFunc()

Note that some older texts say that you can access namespaces using this syntax. As of this writing, this is deprecated functionality. You are now only able to alias modules.

Order Matters

F# requires that types, values and functions are defined before they can be used. This means that if you require a particular construct in a definition, this construct must be already defined. Let’s consider an example.

Suppose we have two modules, Company and Employee. As part of an Employee’s definition, definition we want to record information about the Company. This means that the Employee module will need information from the Company module.  

If we build our F# application using the command-line compiler, fsc, we need to pass the Company.fs file to the compiler followed by Employee.fs, e.g., fsc Company.fs Employee.fs –o Corp.exe. This will compile fine; however, if we switch the order of the files, we’ll get a compilation error to the effect that the module Company is not defined.

This ordering “rule” is reflected in Visual Studio as well. In the Solution Explorer window, the order in which the files are listed is the order in which they are compiled, i.e., that they are passed to the F# compiler. To change the ordering of the files, you can right-click on a file name (in Solution Explorer) and select Move Up or Move Down, among other options.

You must be asking yourself what to do if we have classes that are circularly dependent. Recall from our discussion of types that in order to define types that reference one another, we must use a conjoined definition using the and keyword, as in the following example where Actor depends on Film and Film on Actor :

type Actor(f: Film) =

    do ()

and Film(a: Actor) =

    do ()

What this means in terms of modules is this: classes that are circularly dependent must be defined in the same module using the and keyword.

Execution

Program execution begins with the last module passed to the compiler. All of the elements in this file/module execute, starting from the top of the file and working toward the bottom, as you’d expect. If your program consists of more than one module, none of the other modules’ top-level statements will execute until one of their values is accessed.

 Let’s look at an example. In this example, we have three files: Module1.fs, Module2.fs and Program.fs. These are listed in order below (#light is defined in each):

// Module1.fs

printfn "I am Module1"

let sayHello() = printfn "Module1 saying hello!"

// Module2.fs

printfn "I am Module2"

let sayHello() = printfn "Module2 saying hello!"

// Program.fs -> module Program implied

printfn "I am the main program"

 

Assume these are compiled in the order shown, making Program.fs the last module passed to the compiler. As a result, when the program begins executing, all of Program.cs’s top-level will run. This also means that, as written, none of the statements in Module1.fs nor in Module2.fs will execute. The output of this program, as expected, is I am the main program.

If we augment the Program.fs file to open and use these other modules, the top-level statements in the modules may or may not execute. Merely opening the module is not sufficient to stimulate execution, nor is calling a function. To ensure that a module’s top-level statements execute, a client must access one of the values in the module via a running function or expression. In the following, updated code, Program.fs opens both modules, calls a function in each, and accesses a value in only one of them:

// Module1.fs

printfn "I am Module1"

let public mod1Val = 100

let sayHello() = printfn "Module1 saying hello!"

// Module2.fs

printfn "I am Module2"

let public modVal2 = 200

let sayHello() = printfn "Module2 saying hello!"

// Program.fs -> module Program implied

open Module1

open Module2

 

printfn "I am the main program"

Module1.sayHello()

let m2 = Module2.modVal2

Module2.sayHello()

The output of running the application, i.e., running Program.fs is as follows:

I am the main program
Module1 saying hello!
I am Module2
Module2 saying hello!
Press any key to continue . . .

As shown, Module1’s top-level statement is not executed, since we never accessed its value (mod1Val). We merely called Module1’s sayHello function, which executed correctly. In contrast, we did access Module2’s value (modVal2), which stimulated F# executing its top-level statements. We also called a function in Module2, which executes, as expected.

Functions

F# also supports encapsulation and scoping via local functions, a.k.a., inner functions (as discussed in Chapter 8). Inner functions are those that are defined within other functions. In functional programming, we implement inner functions to hide complexity from clients, e.g., the client does not need to know a function is recursive, and to break up complex functions into manageable parts. From the perspective of code organization, it’s a technique that you should be aware of. Here is an example of an inner function from the F# Wikibooks:

let sumOfDivisors n =

    let rec loop current max acc =

        if current > max then acc

        else if n % current = 0 then loop (current + 1) max (acc + current)

        else loop (current + 1) max acc

    let start = 2

    let max = n / 2     (* largest factor, apart from n, cannot be > n / 2 *)

    let minSum = 1 + n  (* 1 and n are already factors of n *)

    loop start max minSum

 

printfn "%d" (sumOfDivisors 10)

(* prints 18, because the sum of 10's divisors is 1 + 2 + 5 + 10 = 18 *)

Signature Files

A signature file is a mechanism for controlling the accessibility of a module’s types, values, functions, etc. You can create a signature file per F# source file. Each signature file shares the name of the source file with which it’s associated, expect that it has an .fsi extension.

A signature file describes the namespaces, modules, types, and members of its associated source file. We use signature files to control which elements of the source file are exposed to the outside world, and which remain private to the file itself. As a rule of thumb, constructs not listed in the signature file are considered to be private to the file itself.  If no signature file is found in the project (or via the command line), F# employs default accessibility as specified via public, internal and private.

The format of a signature file is rather simple. For each type, method, etc. that we want to expose, we use the signature for the element, which acts as a complete specification of the functionality being exposed. The syntax for a type signature is the same as that used in abstract method declarations ala interfaces and abstract classes. Signature files work with Intellisense, too. To expose a value or function using a signature file, we use the keyword val. To expose a type, we use the keyword type

Signature files can include attributes that further refine the information exposed to clients. The two attributes used in signature files are [<Sealed>] and [<Interface>], which describe types that cannot be extended (Sealed) and types that are interfaces (Interface) respectively.

Generally, you auto-generate signature files using the command-line compiler option –-sig and then manually remove the entries that you want to keep private.

The MSDN documentation describes several rules regarding signature files, reproduced here for your convenience:

There are several rules for type signatures:

  • Type abbreviations cannot be hidden by signatures.
  • Records and discriminated unions must expose either all or none of their fields and constructors, and the order in the signature must match the order in the implementation file. Classes can reveal some, all, or none of their fields and methods in the signature.
  • Classes and structures that have constructors must expose the declarations of their base classes (the inherits declaration). Also, classes and structures that have constructors must expose all of their abstract methods and interface declarations.
  • Interface types must reveal all their methods and interfaces.

The rules for value signatures are as follows:

  • Modifiers for accessibility (public, internal, and so on) and the inline and mutable modifiers in the signature must match those in the implementation. Editorial comment: I found that I could override accessibility via the signature file. For example, in my module (below), the SuperCalc type class is marked public, but I could cause it to be marked internal by the compiler via the signature file. It appears as though the signature file can override the accessibility modifiers in the code.
  • The number of generic type parameters (either implicitly inferred or explicitly declared) must match, and the types and type constraints in generic type parameters must match.
  • If the Literal attribute is used, it must appear in both the signature and the implementation, and the same literal value must be used for both.
  • The pattern of parameters (also known as the arity) of signatures and implementations must be consistent.

As of this writing, Visual Studio 2008 using F# CTP 1.9.6.16 does not produce valid signature files. If I compile my application using the Visual Studio-generated FSI files, the compiler reports problems with the files  -  issues with val and incomplete structures. That said, the command-line compiler seems to produce valid signature files just fine.  So, for now, to generate signature files, I’d suggest using the command line.  Let’s look at an example. Our example application consists of two files: Module1.fs and Program.fs:

// Module1.fs => Module1 module name

type Calc() =

    member this.Add x y = x + y

   

type public SuperCalc() =

    member this.Mul x y = x * y

// Program.fs

open Module1

let c = new Calc()

let sum = c.Add 1 2

 

To produce a signature file for Module1.fs, we execute the following command-line command:

fsc -–sig:Module1.fsi Module1.fs

The compiler will produce a file called Module1.fsi. Here’s what it looks like:

#light

 

module Module1

type Calc =

  class

    new : unit -> Calc

    member Add : x:int -> y:int -> int

  end

type SuperCalc =

  class

    new : unit -> SuperCalc

    member Mul : x:int -> y:int -> int

  end

 

Now, I’d like to hide SuperCalc from the outside world. To do this via the signature file, I open Module1.fsi in the Visual Studio (or any) editor and remove the SuperCalc entry. The updated signature file looks like this now:

#light

 

module Module1

type Calc =

  class

    new : unit -> Calc

    member Add : x:int -> y:int -> int

  end


Now I can compile the program as follows:

fsc Module1.fsi Module1.fs Program.fs

Signature files are optional.If present, they must precede their implementation files in compilation order on the compiler command line. If you’re using Visual Studio to build your projects, this means ensuring that each signature file comes before it’s associated implementation file in the Solution Explorer.

Executing the above command produces Program.exe, which contains the correct modules with the specified accessibility. The Calc class is public, while the SuperCalc class is marked as internal. You can use .NET Reflector to verify this.

My recommendation is that you rely on in-situ accessibility modifiers, i.e., modifiers specified in the F# code itself, rather than rely on specifications in the sig file. To my mind, this is simpler, as you only need to specify accessibility once and only once. It also reduces the number of files you need to maintain. That said, many F# programmers like to use signature files for two reasons:

·         They can be used to make entities public for the duration of the file (because signature files are per implementation file), but then private to the subsequent files of the project.

·         They can provide a documented, public interface to consumers, which can be a clean, condensed and easy-to-read format vs. having consumers wade through lots of code.

Deploying Your F# Code

You’ve built something useful in F#. Now you’re ready to deploy it. A great deal has been written about how to build, sign, version and deploy .NET applications. I am not going to rehash that material here.

Creating F#-based assemblies is no different from creating assemblies in other .NET languages. Using F#, you create .NET EXEs and DLLs. The F# compiler supports a host of options , including those for static linking libraries, defining debug directives, etc. The F# EXEs and DLLs that you create are linked to create one or more .NET assemblies. Please consult the MSDN library regarding the options you have with respect to deploying .NET assemblies. Don Syme’s Expert F# also covers deployment in detail.


The AutoOpenAttribute

The AutoOpen attribute can save your clients a bit of work. If you want to set up your own assembly or module so that the F# runtime automatically makes available its contents, you can apply the AutoOpen attribute at the assembly or module level.[1]  Here is what the MSDN documentation has to say:

You can apply the AutoOpen attribute to an assembly if you want to automatically open a namespace or module when the assembly is referenced. You can also apply the AutoOpen attribute to a module to automatically open that module when the parent module or namespace is opened.

Interfacing with the .NET Libraries

F# Server, C# Client

Once you’ve developed, tested, debugged and packaged your F# code, you may need to integrate it into a larger system. It’s not far-fetched to assume that some of the libraries in this larger system are written in C#. In this section, we’ll demonstrate how to create an F# library (DLL) and access if from C#. To get started, we’ll create a new Visual Studio solution called Fusion. This solution will consist of an F# library project and a C# Console project.

Simple Interactions

In our solution, the F# library defines project a namespace FSharpCalc and a top-level module CalcEngine from which it exposes a type Calculator and a function GCD. Here are the definitions:

namespace FSharpCalc

 

module CalcEngine

 

// Calculator type

type Calculator() =

    member this.Add x y = x + y

    member this.Sub x y = x - y

    member this.Mul x y = x * y

    member this.Div x y = x / y

   

// Greatest Common Divisor function

let rec GCD x y =

    if y = 0 then x

    else GCD y (x % y)

When we compile this code, we produce a DLL called FSharpCalc.dll.

Note that the namespace is important in that it enables the C# client to access the contents of the library via its standard using directive. If you omit the namespace in the F# code, the default module machinery kicks into gear, which causes the module to be named after the source file. My recommendation is to use namespaces whenever you can. Using namespaces has several benefits including making the code clear and transparent, helping to avoid name collissions, and simplifying consumption.

In our sample solution,  the client is a simple C# Console application that exercices the F# library’s functionality. In order to access library, the C# project needs a reference to the FSharpCalc.dll. Once it has a refernece, the C# client accesses the library’s namespace via a standard using directive. From there on in, the client can create Calculator objects, call their methods, call the global GCD function, etc. Here is the source code for the C# Console application.

using System;

using FSharpCalc;

 

namespace CSharpClient

{

       class Program

       {

              static void Main(string[] args)

              {

                     var c = new CalcEngine.Calculator();

                     int s = c.Add(1, 2);

                     int p = c.Mul(3, 5);

                     int g = FSharpCalc.CalcEngine.GCD(8, 20);

                     Console.WriteLine("Sum={0},Product={1},GCD={2}", s, p, g);

                     Console.ReadLine();

              }

       }

}

While simple, this example demonstrates the core ideas of calling F# code from C#. To be pragmatic, let’s add some functions to the CalcEngine module that deal with more sophisticated data types such as arrays, lists and events to see how to deal with them properly. Along these lines, we have added the following function to the F# library:

// Sum a list using fold (we could use sum as well)

let SumList (lst) =

    let accumulate acc x = acc + x         

    let sum = Array.fold accumulate 0 lst

    sum

This function accepts a list of values and uses Array.fold to compute the arithmetic sum. Since we’re using the Array type to conduct the fold operation, F#’s type inference system will expose an Array type to client, i.e., C# will see the argument lst as an array type. This means that the client is expected to pass in an array argument. This is exactly what the C# client does, as shown here:

using System;

using FSharpCalc;

 

namespace CSharpClient

{

       class Program

       {

              static void Main(string[] args)

              {

                     int[] myIntArray = new int[5] { 1, 2, 3, 4, 5 };

                     int sum = CalcEngine.SumList(myIntArray);

                     Console.WriteLine("sum of 1-5 = {0}", sum);

                     Console.ReadLine();

              }

       }

}

 

To make the F# code more generic, we can replace the Array implementation and expose the collection as an IEnumerable by using the Seq type.

// Sum a list using fold

let SumList (lst : #seq<'a>) =

    let accumulate acc x = acc + x         

    let sum = Seq.fold accumulate 0 lst

    sum

Of course, the type argument the client supplies must implement a plus (+) operator for us to avoid a run-time error (x = acc + x could fail). Let’s update the C# client to an IEnumerable:

using System;

using System.Collections.Generic;

using FSharpCalc;

 

namespace CSharpClient

{

       class Program

       {

              static void Main(string[] args)

              {

                    // Pass in a List<T>

                    var myList = new List<int>(new[] {10, 20, 30, 40});

                     var sum = CalcEngine.SumList(myList);

                     Console.WriteLine("sum of 10-40 by tens = {0}", sum);

                     Console.ReadLine();

              }

       }

}

We can also calls functions that accept arguments of type unit and return unit as well (unit -> unit). For example, we can add the following code to FSharpLib:

// Function that takes nothing and return nothing

let printHello() =

    printfn "Hello from FSharpCalc.CalcEngine!"

and call it from C# like this:

CalcEngine.printHello();

Note that when we define the function in F#, we use the empty ( ). This ensures that C# sees the function as a function type and not a property.

Events

Because F# is a fully-supported .NET language, almost every construct you define in F# can be consumed by C# and other .NET languages. The tricky part is getting the F# types and the C# types to align. Let’s look at an example that can be somewhat vexing – events.

In order to define events in F# that can be consumed by C#, you need to use delegates and the [<CLIEvent>] attribute. In the following example, we reconstruct the FSharpLib to define an event that’s fired whenever the Add method is called:

// Calc Library

 

namespace FSharpCalc

 

module CalcEngine

 

open System

 

// Event arg

type AddEventArgs(msg: string) =

    inherit EventArgs()

    member this.Message = msg

 

// Event delegate

type AddEventDelegate = delegate of obj * AddEventArgs -> unit

   

// Calculator that can now raise an event

type Calculator() =
    // Create Event<handler, args>:

    let ev = new Event<AddEventDelegate, AddEventArgs>()

    member this.Add (x: int) (y: int) =

        let sum = x + y
        // Fire event

        ev.Trigger(this, new AddEventArgs(String.Format("Added {0} and {1}", x, y)))

        sum

 

    // Magic attribute that exposes the event to other .NET languages

    [<CLIEvent>]

    member this.OnAdd = ev.Publish

In this example, when we define the AddEventDelegate via the delegate keyword, the F# compiler generates a MulticastDelegate. The MulticastDelegate is general purpose, and is generally sufficient to implement cross-language events; however, if you want, you can specify the specific delegate type that F# should use via the DeletegateEvent (vs. using the plain Event as we’ve done above). In the following example, taken from a hubFS post by Tomas Petricek, you can see how these classes are used:

// Declare class for testing, which can be used from C#

type Test() =

  // Declare event with 'EventHandler' delegate

  let evt1 = new DelegateEvent<System.EventHandler>()

  // Declare event that'll use standard F# generic delegate type

  let evt2 = new Event<System.EventArgs>()

  // Expose the first event as C# event

  [<CLIEvent>]

  member x.Event1 = evt1.Publish

  member x.Foo1() = evt1.Trigger([| box x; box System.EventArgs.Empty |])
     // trigger it

 

// Expose the second event as C#-compatible event

[<CLIEvent>]

member x.Event2 = evt2.Publish

member x.Foo2() = evt2.Trigger(System.EventArgs.Empty) // trigger it!


High-Order Functions

Another interesting situation that arises when building F# components for C# consumption revolves around high-order functions. When you design an F# function that accepts function arguments, or returns a function, how do you call this from C#?

We answer this question by way of an example. First, we define an F# function, filterStringsFromList that filters a list of strings based on a filtering function. The caller will pass filterStringsFromList the filtering function to use. This example was adapted from Robert Pickering’s Foundations of F# book:

let filterStringsFromList f (l : List<string>) =
    new List<string>(l |> Seq. filter f)

 

As you can see here, we’re using standard F# high-order function semantics. The first parameter to filterStringsFromList is a standard F# function. The second parameter is a list of strings to filter. Under the covers, F# exposes high-order function parameters via built-in type called FastFunc. This means that .NET client applications that want to call this function need to work with FastFunc types. To gain access to the FastFunc type, we include a reference to the FSharp.Core.dll in our C# project. The FSharp.Core.dll includes a helper type, FuncConvert that C# applications can use to wrap local functions, making them compatible with F#’s FastFunc type.

In the following C# client example, we use the types defined in FSharp.Core.dll to call the HighOrder.filterStringsFromList function defined in our F# library:

static void PrintJNames()

{

    var names = new List<string>(

        new string[] { "Jessica" , "Kimberly", "Jill" , "Melissa" });

    Converter<string, bool> pred = s => s.StartsWith("J");

    FastFunc<string, bool> ff = FuncConvert.ToFastFunc<string, bool>(pred);

    IEnumerable<string> jnames =
        HighOrder.filterStringsFromList(ff, names);

    foreach (string name in jnames) {

        Console.WriteLine(name);

    }

}

A few notes about the code sample are in order. The Converter class is a .NET class used to convert one type to another. Here, we are using it to wrap a lambda function and create a delegate, which is required by FuncConvert.ToFastFunc. We then use FuncConvert.ToFastFunc  to convert this delegate into a FastFunc so that we can pass it into the F# filterStringsFromList function.

While this works perfectly well, I think it’s fair to say that working with FastFunc objects  is somewhat awkward. Luckily, we have a simpler solution. If we begin in F# by defining our filterStringsFromList function using a delegate vs. a raw function, this makes calling the function from C# simpler. Let’s see what it looks like:

namespace FSharpLib

 

open System

open System.Collections.Generic

 

module HighOrder =

    // New version that uses delegate vs. raw F# function for filter function

    let filterStringsFromList (del : Predicate<string>) (l : List<string>) =

        let f x = del.Invoke(x)

        new List<string>(l |> Seq. filter f)

The new version of filterStringFromlist is only slightly different from the original. The first argument, the Predicate, is now a .NET class that inherits from the MulticastDelegate class. We can use any MulticastDelegate-derivate to expose our F# function arguments to the .NET-world-at-large. Often, we use the delegate types from the System namespace’s Func<> family of classes, e.g., Func<T, TResult>. Please consult the MSDN documentation for details on Func<> delegates.

Now that F# is exposing its function argument like this, we can bypass FastFuncs and instead use C#’s lambda functions directly. We demonstrate this in the following example:

using System;

using System.Collections.Generic;

using FSharpLib;

 

namespace CSClient {

    class Program {

        static void Main(string[] args) {

            var names = new List<string>(

                new string[] { "Jessica" , "Kimberly", "Jill" , "Melissa" });

            var jnames =

                HighOrder.filterStringFromList(s => s.StartsWith("J"), names) ;

            foreach (string name in jnames) { Console.WriteLine(name); }

        }

    }

}

Clearly, this is much cleaner and more intuitive than the original code. The moral of this story is: if you’re writing high-order functions that you intend to be callable by C# and other .NET clients, expose your arguments via delegates.

C# Server, F# Client

In contrast to accessing F# from C#, it’s more likely that your F# code will leverage libraries already written in C# and other .NET languages. This section deals with this scenario.

Simple Interactions

You can use F# to consume libraries written in other .NET languages. We do this all the time when using classes from the .NET Base Class Library (BCL). In the following example, we build a C# library that exposes a class for downloading Web pages. We then consume this library from an F# Console application. Here is the code for the C# library:

using System.Net;

using System.Text;

 

namespace CSLib

{

       public class HttpHelper

       {

              public string GetWebPage(string url)

              {

                     var req = new WebClient();

                     var payload = req.DownloadData(url);

                     return new ASCIIEncoding().GetString(payload);

              }

       }

}

Consuming this library from F# is straight forward. We simply add a reference to the C# library in our F# project, open the exposed namespace, and make calls as usual. Here is the F# Console application:

#light

 

open CSLib

 

let hh = new HttpHelper()

let yahoo = hh.GetWebPage("http://www.yahoo.com")

printfn "%s" (yahoo.ToString())

Lists and Collections

Lists and collections are fundamental to programming. With the inclusion of generics (and the upcoming contravariance and covariance support in C# 4.0), the majority of developers will probably use the generic-based collections defined in System.Collections.Generic. Let’s write a C# class that uses these data structures, and then examine how to access them from F#.

using System.Collections.Generic;

namespace CServer

{

    public class MyType

    {

        public List<string> GetNames() {

            return new List<string>(

                new string[] { "Jess" , "Chee", "MissyP" });

        }

 

        public int CountThese<T>(IEnumerable<T> e) {

            int count = 0;

            foreach (object o in e) {

                ++count;

            }

            return count;

        }

    }

}

We can use these (very contrived) methods from F# as follows:

open System.IO

open CServer

 

let o = new MyType()

let names = o.GetNames()

names |> Seq.iter(fun name -> printfn "%s" name)

 

let c = o.CountThese (seq { 1..10 })

printfn "count = %d" c


As you can see, it’s straight-forward to access C# lists and enumerables from an F# client.


ref and out

By default, in .NET, value types are passed by value. This means that a copy of the value is passed into a function or method. In contrast, reference types are passed via their memory addresses, meaning that a change to the argument is, in reality, a change to the original. To override this default argument-passing behavior, C# uses two keywords, ref and out. Both keywords instruct the C# compiler to pass arguments by reference. The only difference between the two keywords is that out arguments must be initialized (set to a value) before the called function exits. ref parameters are not subject to this restriction.

From F#, when we call a function or methods that uses ref and/or out parameters, we need to use reference cells to ensure changes in the values are reflected back to us. In the following example, we create a simple C# class with methods that do not use ref or out, use ref, and use out:

namespace CServer

{

    public class MyType

    {

        public void foo(int i) {

            ++i;

        }

        public void bar(ref int i) {

            ++i;

        }

        public void quux(out int i) {

            i = 999;

        }

    }

}

We can see the effect of calling these methods from F# using the following F# Console application:

#light

 

open System

open CServer

 

let x = new MyType()

 

let a, b, c = 123, 456, 789

 

Console.WriteLine("before: {0} {1} {2}", a, b, c);

 

x.foo a

let b' = ref b

x.bar b'

let c' = ref c

x.quux c'

 

Console.WriteLine("after : {0} {1} {2}", a, !b', !c');

Console.ReadLine() |> ignore

As you can see, to call methods that accept ref and out arguments , we use F# reference cells. Since we are not modifying the core value (we are modifying the reference cell), we do not need to make the value mutable. Recall that in order to dereference these cells, we use the bang (!) operator. Note that in the case of calling method foo, we do not use reference cells, since the argument is not decorated with ref or out.

Of course, passing reference types, i.e., object-based types, is done without argument decoration. We see this in the following example:

namespace CServer

{

    public class MyType

    {

        public int MyNum = 123;

        public void foo(int i) {

            ++i;

        }

        public void bar(ref int i) {

            ++i;

        }

        public void quux(out int i) {

            i = 999;

        }

        public static void ModMyType(MyType o) {

            o.MyNum = 12345;

        }

    }

}

 

Given this C# server code, we can it from F# with standard object (reference) semantics, as shown here:

open System

open CServer

 

let x = new MyType()

printfn "before: x.MyNum = %d" x.MyNum

MyType.ModMyType(x)

printfn "after : x.MyNum = %d" x.MyNum

Console.ReadLine() |> ignore


Cleaning up resources

In F# programming, you will probably call into the .NET libraries and leverage classes from the BCL. Many of the classes in the BCL manage finite resources, e.g., file handles, graphics contexts, etc. allocated by the underlying operating system. In order to avoid memory leaks, etc., you need to deallocate these resources when you’re through using them. The standard protocol for doing this in .NET is to use the IDispose interface, call the Dispose method for the given resource object. To make calling Dispose natural and painless, F# provides two keywords: use and using.

The use keyword takes the following form:

use value = expression

It provides the same functionality as a let binding with the added feature of instructing the F# compiler to call Dispose on the value when the value goes out of scope. The following example shows how to leverage the use keyword to automatically close a file:

open System.IO

 

let writeToFile filename (str: string) =

   use theFile = File.CreateText(filename)

   theFile.WriteLine("{0}", str)

       // F# calls theFile.Dispose() automatically here

 

writeToFile @"c:\temp\poem.txt" "Mary had a little lamb..."


The using function has the following form:

using (expression) function-or-lambda

In a using expression, expression creates the object that must be disposed. The result of the expression (the object that must be disposed) becomes an argument to the subsequent function or lambda expression. The following example demonstrates the using expression with a lambda. Of course, you could replace the lambda with a function call that takes a single argument of the type created:

open System.IO

 

let writeToFile filename (str: string) =

    using (File.CreateText(filename)) (fun theFile ->

        theFile.WriteLine("{0}", str)

    )

writeToFile @"c:\temp\song.txt" "You are my sunshine, my only sunshine..."

The using function and the use binding are nearly equivalent ways to accomplish the same thing; however, the using keyword provides more control over when Dispose is called. When you leverage using, Dispose is called at the end of the function or lambda expression; however, when you utilize the use keyword, Dispose is called at the end of the containing code block, when the use-d object goes out of scope.

COM Server, F# Client

We can use F# to call COM servers.  The good news here is that accessing COM via F# is pretty much the same as accessing it via C# and other .NET languages. The beauty of COM is that it is a language-agnostic interface, resulting in uniform client access.

Because .NET has been around for a while, and has matured, you may find a managed wrapper already available for the COM components you’d like to access, e.g., Microsoft Office 2007. In cases where a managed wrapper does not exist, you can access the COM objects directly.

To access COM objects directly from F#, run the type-library import tool (TLBIMP) on the executable (DLL or EXE) that contains the definitions of the COM objects. TLBIMP will create an OO wrapper assembly around the COM objects contained in the executable. The resulting assembly can be used like any other assembly – you add a reference to the assembly in your Visual Studio project or use the-r switch on the F# compiler. Once loaded, the assembly provides convenient access to the underlying COM components.

In the following example, based on one from Pickering’s book, we run TLBIMP on the Speech API DLL executable to generate a wrapper around the COM object model. On my machine, the Speech API is found here:  C:\Windows\System32\Speech\Common.

Now that we have a wrapper DLL, we can use Visual Studio to add a reference to it. Once we’ve done that, we can use the classes exposed by the wrapper to access the underlying COM functionality. In the following F# example, we create an instance of the main speech class and have the computer say something:

open speech

let sp = speech.SpVoiceClass()

sp.Speak("I'll be back.", SpeechVoiceSpeakFlags.SVSFDefault) |> ignore

While writing this chapter, I experimented with other COM servers. What I found was that TLBIMP and F# converted all the required constructs to F#-consumable types – very convenient!

P/Invoke

The last interop scenario that we’ll consider is using platform invoke, more commonly referred to as P/Invoke. The P/Invoke plumbing, which is an intrinsic feature of the CLR, enables F# to call unmanaged code, e.g., code in the Windows API and other C-based DLLs.

To use data structures, classes and functions from external libraries, e.g., the Windows API, you need to tell F# where these constructs reside. This means telling F# the name of library, e.g., USER32.DLL, and the names of the specific constructs you want to access. To do this, we open the System.Runtime.InteropServices namespace and use the the DllImport attribute. The general syntax is:

[<DllImport( arguments )>]
extern declaration


In the following example, we use P/Invoke to display a message box:

open System.Runtime.InteropServices

 

[<DllImport("user32.dll")>]

extern int MessageBox(int32, string, string, uint32)

    // hwnd, text, caption, type

 

MessageBox(0, "Hello from F#!", "F# Survival Guide", 0u)   

DllImport tells F# where the external function (or structure) lives. The extern keyword tells the F# compiler that the referenced function is defined outside of the current file or module. Together, DllImport plus extern give us access to external constructs.

Given the C-based history of the Windows API, many API calls take pointers as arguments. When dealing with APIs that take pointers as arguments, we need to tell F# that the argument is a pointer via using the asterisk symbol (*) in the function definition, and using the address-of symbol (&&) when calling the function. In the following example, we use F# to call the GetDiskFreeSpace function defined in kernel32.dll.

open System.Runtime.InteropServices

 

[<DllImport("kernel32.dll")>]

extern bool GetDiskFreeSpace(

    string lpRootPathName,

    uint32* lpSectorsPerCluster,

    uint32* lpBytesPerSector,

    uint32* lpNumberOfFreeClusters,

    uint32* lpTotalNumberOfClusters)

   

let mutable spc, bps, fc, tc = 0ul, 0ul, 0ul, 0ul

let ok = GetDiskFreeSpace("c:\\", &&spc, &&bps, &&fc, &&tc)

printfn "Results %d %d %d %d" spc bps fc tc

System.Console.ReadLine()

Note that many Windows APIs accept structures and pointers to structures as arguments. To call these APIs, you need to define F#-centric definitions of the structures that you can pass into the API.

For example, let’s look at the GetLocalTime() function defined in kernel32.dll. This function takes a pointer to a SYSTEMTIME structure. F# does not ship with a definition of this structure, nor does it support the concept of a “header file” from which to draw definitions. Therefore, we need to define type-mappings ourselves, mapping F# types to C types. In the following example, we demonstrate how to do this, using GetLocalTime() as an archetype:

open System

open System.Runtime.InteropServices

 

[<Struct>]

type SYSTIME =

    val wYear: int16

    val wMonth: int16

    val wDayOfWeek: int16

    val wDay: int16

    val wHour: int16

    val wMinute: int16

    val wSecond: int16

    val wMilliseconds: int16

 

[<DllImport("kernel32.dll")>]

extern void GetLocalTime(SYSTIME* t)

 

let mutable t = new SYSTIME()

GetLocalTime(&&t)

printf "Local date and time: "

printfn "%d-%d-%d %02d:%02d" t.wYear t.wMonth t.wDay t.wHour t.wMinute

Console.ReadLine() |> ignore

As you can see, we defined an F# structure that matches, field for field, the C-based structured defined in the API documentation. We then repeat the use of the technique of passing the function a pointer to the relevant construct.

Whenever you shuttle types from .NET to unmanaged code, you’re implicitly working with a .NET component called the marshaller. The marshaller is responsible for shipping managed type to unmanaged code and vice versa. The marshaller can handle many cases of type-shuttling transparently; however, it’s not omnipotent, and occasionally needs some help. Some APIs, for example, accept complex structures that themselves contain pointers, etc. When working with these types, you may need to help the default marshaller via using the MarshalAsAttribute defined in System.Runtime.InteropServices.

This class tells the runtime how to shuttle and transform data between the managed and unmanaged worlds. A full discussion of marshalling complex data structures is beyond the scope of this “survival guide” text. For more information, check out the MSDN documentation on .NET marshalling via P/Invoke and the Web site http://www.pinvoke.net. It is a wiki-style site that documents P/Invoke signatures, etc.

What You Need to Know

·         Namespaces enable you to broadly organize your code in a consistent, cross-assembly manner. I recommend always defining your own namespaces for any non-trivial project.

·         Modules provide a way to organize your code at the file level. F# compiles modules to a class containing only static members.

·         Modules come in two flavors: file-level or “top-level” that encompass the entire contents of a given file and “local” that help subdivide a larger file into logical sections. Local modules can also be nested.

·         Modules may be aliased. This is usually done to abbreviate long module names.

·         The load order of modules matters. Forward references do not exist by default in F#.

·         Signature files provide a way to document and publish the public interface to your module.

·         You can package your F# code in assemblies consisting of EXEs and DLLs. This is no different from any other .NET language.

·         F# is interoperable with C# and other .NET languages.

·         F# can call into COM servers.

·         F# can call into the core Windows API via P/Invoke.

 

Please visit us at the CTO Corner (www.ctocorner.com) for more information and an up-to-date blog.

 



[1] We will look at an example of this when we discuss packaging and deployment of F# libraries.

 

Feedback

We welcome your feedback. If you have comments or questions about this chapter, please feel free to e-mail us at

Keep Reading

Next Chapter...