Reputation: 1057
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
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