Advanced F# Interop
Tags: fsharp, csharp, dotnet
Published: 2020-09-21 10:31:01

_This is an adaptation of the article that used to be on my personal blog that I neglected. It was originally part of the 2019 F# Advent._

You like F#. I like F#. I also like C# and even when I have control over both ecosystems, getting the two to play nice with each other isn't the easiest of things. Even worse is when you need to use code written by someone that... oh my god, where did they learn to program? Look, we've all been there. Some API's just feel awful, especially when consuming in F#.

So how do you deal with it? For many people they write their own replacement in F#.

![Oblivion guard "Stop right there" meme](https://dev-to-uploads.s3.amazonaws.com/i/34klwturboozpxzlbuxk.jpg)

There's a better way. And it doesn't require that much work.

I've written this mostly in hopes that library authors use this information to provide better F# support when possible, and to help the community to provide better F# support when not.

# Example Library

For the sake of this article I've written every F# programmers' worst nightmare: The most extremely imperative and procedural and impure library I could produce. And you don't have a choice in using something else because your manager is an idiot or something. The library is simple: a single specialized stack type for [Double](https://docs.microsoft.com/en-us/dotnet/api/system.double). You can check it out on [GitHub](https://github.com/Entomy/Advanced-FSharp-Interop).

Normally people assume that if they mark the assembly [CLSCompliant](https://docs.microsoft.com/en-us/dotnet/api/system.clscompliantattribute) then everything is great and every language can consume the API. This is half true. Everything can consume the API. I'm fairly sure everything can also eat dirt, but that doesn't mean you or I want to. I marked the example library [CLSCompliant](https://docs.microsoft.com/en-us/dotnet/api/system.clscompliantattribute), but it's bad. I died inside writing it.

Let's have a look at the API.

~~~~csharp
void Add();
void Add(out Double result);
void Subtract();
void Subtract(out Double result);
void Multiply();
void Multiply(out Double result);
void Divide();
void Divide(out Double result);
//... As well as everything Stack<Double> would already have
~~~~

Let's have a look at just how bad this is, using the stack API for the arithmetic `3 * 5 - 8`.

~~~~fsharp
let stack = DoubleStack()
stack.Push(3.0)
stack.Push(5.0)
stack.Multiply()
stack.Push(8.0)
stack.Subtract()
~~~~

So, that's not great. It works, and it's identical across languages. But man that's not the kind of API we want to be working with in F#. But what about those other methods, the ones with the out parameters?

~~~~fsharp
let stack = DoubleStack()
let mutable result = ref 0.0
stack.Push(3.0)
stack.Push(5.0)
stack.Multiply(result)
~~~~

You see why I say I died inside. Surely there's no hope here. Surely this is so far-gone that you either suck it up and use it as is, or write your own with a F# friendly API.

![Trump "Wrong" meme](https://dev-to-uploads.s3.amazonaws.com/i/vajoj5429mk51ai7o31g.jpg)

Over the course of this article I'll show you how to turn this into a very function feeling API you'd be certain was written natively in F#.

# Functional Push/Pop/Peek

A good starting point is to make Push(), Pop(), and Peek() feel functional, by implementing our own stack pipeline.

~~~~fsharp
let ( |=> )(stack:DoubleStack)(value) = stack.Push(value)
let stack = DoubleStack() |=> 5.0
~~~~

And just like that we have a working pipeline! Right? **No**. We do have a working single operation, but this leaves us with the same situation, in a different coat of paint. Try chaining the pipeline and you'll see the issue. We need to return the stack in the function call.

~~~~fsharp
let ( |=> )(stack:DoubleStack)(value) =
	stack.Push(value)
	stack
let stack = DoubleStack() |=> 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, stack.Peek())
~~~~

That's already looking a good amount better. Still a ways to go though. Let's take care of the other two methods we mentioned.

~~~~fsharp
let inline pop (stack:DoubleStack) = stack.Pop()
let inline peek (stack:DoubleStack) = stack.Peek()
~~~~

This are very straightforward translations. So straightforward that they are inlined. These kind of methods are the easiest to bind, and are something you should already be familiar with. With all these combined, we're now left with something that's starting to look functional, but is still obviously not there yet.

~~~~fsharp
let stack = DoubleStack() |=> 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, peek stack)
~~~~

# Functional Object Initializer

This is a deep one, because while it's not that big of an issue, it's not easy to solve. You can still deal with things though. See, that `DoubleStack()` at the beginning of the pipeline when declaring is a bit annoying. Not the end of the world, but we can do better.

~~~~ fsharp
type Pipeline =
	static member Pipe(left:DoubleStack, right:float) =
		left.Push(right)
		left
	static member Pipe(left:float, right:float) =
		let result = DoubleStack()
		result.Push(left)
		result.Push(right)
		result

let inline private pipe< ^t, ^a when (^t or ^a) : (static member Pipe : ^a * float -> DoubleStack)> left right =
	((^t or ^a) : (static member Pipe : ^a * float -> DoubleStack)(left, right))

let inline ( |=> )(left:^a)(right:float) = pipe<Pipeline, ^a> left right
~~~~

What in the heck is this? I promise this isn't some fancy black magic. Let's go over it one thing at a time.

First is the `Pipeline` type we defined. This must have the same visibility as the function or operator which will be using it. In it we're defining overloads of `Pipe()` which is static. You can define whatever you want here; these are the actual methods that are being called. The first one does what we already defined: it takes a stack and a float, pushes the float onto the stack, and returns the stack. The second one adds the behavior we wanted: it creates a stack, pushes the left value onto it, then pushes the right value onto it, then returns the stack.

Second is some inline and generic trickery which is probably the most intimidating thing to those not familiar with F#'s type system. It's not that bad, I promise. Ignoring the generic part, we have a function called `pipe` with two curried parameters: `left` and `right`. Not so bad. The generic part says that we're considering two _statically resolved_ types: `^t` and `^a`. That static resolution is important, and because of that, this function absolutely must be inlined. It doesn't need to be visible however, so I've taken to making it private, always. The rest of the generic says that on `^t` or `^a`, there will be a static member `Pipe` with the signature `^a * float -> DoubleStack`. Look at those methods we were just talking about. As long as `^a` matches one of their first parameters, we have a matching method. The _seemingly_ repeating code in the definition part of this function just says to call whatever method this resolves to, with the tupled arguments `(left, right)`. There, that wasn't too bad. I'll admit even I still kind of think it's black magic though.

The third part is just a slight modification to our original stack pipeline operator. This also needs to be inlined now. Inlining both functions is extremely important. Similarly, we can change the lefthand parameter to be of `^a`, so that it statically resolves. Then we call the black magic function instead of what we were doing. This is where `^t` and `Pipeline` comes into play. Assuming the library we're working with is third party, we can't add an instance member called `Pipe` to it. And we definitely can't add an instance member to `Double`! This additional parameter is for a type we've defined that will also have these methods, which is why it was declared as static member in the generic. Now it knows to look inside of our own type as well.

How much progress did this make?

~~~~fsharp
let stack = 5.0 |=> 3.0
stack.Multiply()
Assert.Equal(15.0, peek stack)
~~~~

Not a whole lot has changed, but it certainly looks cleaner. Try out longer pipelines, it still works.

There is another, [simpler way](http://www.fssnip.net/7Xj), to accomplish this. Use it when you can, but from my experience it's not possible in many situations, while this approach is. This simpler approach would not work in this instance.

I've found this is most useful when mapping overridden methods to functions so that currying and pipelining is possible. So this often means rearranging parameters. You may find other uses. I don't recommend doing this just because you can.

# Functional Stack Arithmetic

The last remaining thing is those pesky arithmetic methods. Surely by now we've finally run into something we can't fully bind to this functional, pipeline heavy, environment. Right?

Actually this one is really easy, with what we've already set up

~~~~fsharp
let add (stack:DoubleStack) =
	stack.Add()
	stack
~~~~

And so on. That's it. No seriously, that's it. Because of the stack pipeline operators exact symbol (|=>) not only does it render like a pipe arrow thing when using [Fira Code](https://github.com/tonsky/FiraCode) or related fonts, but it also has the exact same precedence and associativity as the function pipeline operator, so there's nothing new to add.

Putting everything together we have:

~~~~fsharp
let stack = 3.0 |=> 5.0 |> mul |=> 8.0 |> sub
Assert.Equal(7.0, peek stack)
~~~~

I told you it was possible. 😉

There's a lot more, but this article has covered a lot and I don't want to provide an overwhelming amount of information. So expect more in the future.

![feelsgoodman.jpg](https://dev-to-uploads.s3.amazonaws.com/i/l69gxh383vo54jsg93ch.jpg)