Peter
Peter

Reputation: 1057

Initializing class instance similar to records in F#

With record types in F# you can use a syntax like this to initialize a record based on another one:

let rr3 = { defaultRecord1 with field2 = 42 }

Is there something similarly concise and elegant for non-record types as well?

I'm working with C# classes and calling their Clone() method and doing assignments to their properties using the <- operator seems a bit off. I also found this article about object expressions but it seems it isn't the thing I was looking for.

Edit: So to sum it up I'm trying to instantiate C# classes in my F# code and I'm wondering if there is some concise syntax for creating an object of a class based on another object's values just like with records in F# using the with keyword.

Upvotes: 2

Views: 472

Answers (1)

Tarmil
Tarmil

Reputation: 11362

You can actually use settable properties in method calls as if they were named arguments. So if your class was implemented with a dedicated Clone method that returns the original type:

type Foo() =
    member val X = 0 with get, set
    member val Y = 0 with get, set
    member this.Clone() = new Foo(X = this.X, Y = this.Y)
    interface System.ICloneable with
        member this.Clone() = box (this.Clone())

then you would be able to do the following:

let foo1 = new Foo(X = 1, Y = 2)
let foo2 = foo1.Clone(X = 3)

But most likely your class only has the ICloneable implementation. In this case the above trick will not work out of the box, because ICloneable.Clone returns obj which doesn't have a settable X property. Fortunately, you can add the required method as an extension:

/// Original class
type Foo() =
    member val X = 0 with get, set
    member val Y = 0 with get, set
    interface System.ICloneable with
        member this.Clone() = box (new Foo(X = this.X, Y = this.Y))

let foo1 = new Foo(X = 1, Y = 2)
let foo2 = foo1.Clone(X = 3) // error FS0039: The field, constructor or member 'Clone' is not defined
let foo3 = (foo1 :> System.ICloneable).Clone(X = 3) // error FS0495: The member or object constructor 'Clone' has no argument or settable return property 'X'. The required signature is System.ICloneable.Clone() : obj.

/// Extension that makes the above trick work
type Foo with
    member this.Clone() = (this :> System.ICloneable).Clone() :?> Foo

let foo1 = new Foo(X = 1, Y = 2)
let foo2 = foo1.Clone(X = 3) // works!

Upvotes: 3

Related Questions