Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Immutable Class Interop

Tags:

f#

How do F# immutable types interface with C#. I'm just starting to learn F# and I'd like to mix it in with some C# code I have, but I want my F# classes to be immutable.

Let's say we're making a Vector class in F#. Vector.X and Vector.Y should be re-assignable, but only be returning a new Vector class. In C# this would take allot of legwork to make .WithX(float x) clone the existing object and return a new one. Is there an easy way to do this in F#?

I've been searching for some time and I can't seem to find any docs on this. So any help would be great.

And finally, if I imported this class into C# what would its interface look like? Will the F# code restrict me from doing something stupid like Vector.X = 10?

like image 251
Timothy Baldridge Avatar asked Jan 25 '11 20:01

Timothy Baldridge


2 Answers

This will look similar regardless of whether it's C# or F#.

You say "in C# it will take legwork", but cmon, I think

Vector WithX(float x) { return new Vector(x, this.Y); }

is it, right?

In both C# and F#, to prevent assignment to the X property, you author a property with a 'getter' but no 'setter'.

I think you're making all of this out to be harder than it is, or maybe I'm misunderstanding what you're asking.

EDIT

For the (I think rare) case of where there are 20 field and you may want to change just a small arbitrary subset of them, I found a cute hack to use F# and C# optional parameters together nicely.

F# Code:

namespace global

open System.Runtime.InteropServices

type Util =
    static member Some<'T>(x:'T) = Some x

type MyClass(x:int, y:int, z:string) =
    new (toClone:MyClass, 
         [<Optional>] ?x, 
         [<Optional>] ?y, 
         [<Optional>] ?z) = 
            MyClass(defaultArg x toClone.X, 
                    defaultArg y toClone.Y, 
                    defaultArg z toClone.Z)
    member this.X = x
    member this.Y = y
    member this.Z = z

F# client code:

let a = new MyClass(3,4,"five")
let b = new MyClass(a, y=44)  // clone a but change y

C# client code:

var m = new MyClass(3, 4, "five");
var m2 = new MyClass(m, y:Util.Some(44)); // clone m but change y

That is, optional parameters are a nice way to do this, and while C# optional parameters have some limitations, you can expose F# optional parameters in a way that works ok with C#, as suggested above.

like image 69
Brian Avatar answered Sep 23 '22 12:09

Brian


F# Record types have a built in way of doing exactly what you're asking:

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

let v1 = {X=1.; Y=2.}
let v2 = {v1 with X=3.}

How that interops with C#, I'm not sure (edit: see Brian's comment).

Vector will be immutable from any .NET language, since X and Y are implemented as getters without setters.

like image 21
Stephen Swensen Avatar answered Sep 21 '22 12:09

Stephen Swensen