Thursday, May 26, 2016

Using F# modules and types from C#

It's simple to use FSharp modules from C#, but for some reason I always forget exactly how the system works
(maybe too much switching back and forth between Scala/C#/F#/Java...).

Here's some F# snippets and a C# example of how to pull them together. The weird one is C#'s "using static", since the name seems to indicate that it's just pulling in static methods. In addition to pulling in static methods, though, it also pulls in nested types.

namespace FSharpNamespace
type Class2 =
| Something
| OtherThing of int


module FSharpModule
let fn() = 1
type Class1() =
member this.X = "F#"


using System;
// Note that "using FSharpModule" (without "static") isn't legal C#.
// An FSharp module gets compiled into a type, and "using" specifically
// imports namespaces.
using static FSharpModule;
using FSharpNamespace;
using static FSharpNamespace.Class2;
#pragma warning disable 219 // no warnings about unused variables
namespace ConsoleSample
{
class MainClass
{
public static void Main (string [] args)
{
int a = FSharpModule.fn ();
FSharpModule.Class1 b = new FSharpModule.Class1 ();
// using static FSharpModule means we don't have to
// write "FSharpModule." before our types
int c = fn ();
Class1 d = new Class1 ();
FSharpNamespace.Class2 e = FSharpNamespace.Class2.Something;
Class2 f = Class2.Something;
// Allowed by "using static FSharpNamespace.Class2"
Class2 g = Something;
Class2 h = NewOtherThing (1);
}
}
}
view raw main.cs hosted with ❤ by GitHub


Consuming from F# is slightly simpler:

module FSharpConsumer
let a = FSharpNamespace.Class2.Something;
// Notice that in F# we use "open" for both modules and namespaces.
// See the F# spec section 14.1.3 Opening Modules and Namespace Declaration Groups
// for precise details.
open FSharpNamespace
let b = Class2.Something;
let c = Something;
let d: FSharpModule.Class1 = FSharpModule.Class1();
open FSharpModule
let e = fn()
let f = new Class1();


Here's the F# specification for more details.