1

I recently found (see near the end of this page) that it's possible to set properties on initialization, as in the last line of the following. This is very concise:

type Account() =
    let mutable balance = 0.0
    member this.Balance
       with get() = balance
       and set(value) = balance <- value

let account1 = new Account(Balance = 1543.33)

Is there a way to set sub-properties (i.e. properties of properties) in a similarly concise way, without overwriting them completely?

For example, I would like to write something along these lines:

type Person() =
    let mutable name = ""
    let mutable someProperty = ""
    member this.Name
       with get() = name
       and set(value) = name <- value
    member this.SomeProperty
       with get() = someProperty
       and set(value) = someProperty <- value

type Account() =
    let mutable balance = 0.0
    let mutable person = new Person(SomeProperty = "created by an account")
    member this.Person
       with get() = person
       and set(value) = person <- value
    member this.Balance
       with get() = balance
       and set(value) = balance <- value

let account1 = new Account(Balance = 1543.33, Person.Name = "John Smith")

However, the last line produces a compile error which doesn't make complete sense: Named arguments must appear after all other arguments.

Please note this is actually for interop with a C# library, so I can't necessarily construct a new object for the property. I wouldn't use mutable properties like this in F# if at all possible.

Mark Pattison
  • 2,964
  • 1
  • 22
  • 42

1 Answers1

3

Yes, you can do this.

Try the following:

let account1 = new Account(Balance = 1543.33, Person = Person(Name = "John Smith"))

Edits following change to posters question: I'm still not 100% sure if I follow correctly, but a solution could be the following. It doesn't feel particularly functional, but given this is meant to interact with C# classes I don't see that as an issue:

type Account() =
let mutable balance = 0.0
static let mutable person = new Person(SomeProperty = "created by an account")
member this.Person
   with get() = person
   and set(value) = person <- value
member this.Balance
   with get() = balance
   and set(value) = balance <- value
static member GetPerson = person


let account2 = new Account(Balance = 1543.33, Person = Person (Name = "John Smith", SomeProperty = Account.GetPerson.SomeProperty))
Pash101
  • 631
  • 3
  • 14
  • Thanks, although it's not quite the same in the general case - a new `Person` object will be constructed, rather than setting a property on the existing object. – Mark Pattison Mar 10 '16 at 12:30
  • 1
    Maybe I misunderstood the issue, but given how your code is written now a new person object will be created on initialization of an Account type anyway. What is the general case you are looking for? – Pash101 Mar 10 '16 at 13:13
  • I've edited the example to make it explicit that the result will be different. In real life, this is to initialize an object from a C# library so I can't guarantee how the constructor for the property is being called (or even that I can call it). – Mark Pattison Mar 10 '16 at 13:31
  • Please see the edits to my answer – Pash101 Mar 10 '16 at 13:57