Reputation: 4231
Why is t.b evaluated on every call? And is there any way how to make it evaluate only once?
type test =
{ a: float }
member x.b =
printfn "oh no"
x.a * 2.
let t = { a = 1. }
t.b
t.b
Upvotes: 13
Views: 2341
Reputation: 17419
The previous responses suggest switching to a class, instead of using a record. If you want to stay with records (for their simple syntax and immutability), you can take this approach:
type test =
{ a : float
b : float }
static member initialize (t: test) =
{ t with b = t.a * 2. }
This is useful if the instance of test
is created by another library (like a data provider from a web service or database). With this approach, you must remember to pass any instance of test
that you receive from that API through the initialize function before using it in your code.
Upvotes: 2
Reputation: 47904
In response to your comments in Brian's post, you can fake copy-and-update record expressions using optional/named args. For example:
type Person(?person:Person, ?name, ?age) =
let getExplicitOrCopiedArg arg argName copy =
match arg, person with
| Some(value), _ -> value
| None, Some(p) -> copy(p)
| None, None -> nullArg argName
let name = getExplicitOrCopiedArg name "name" (fun p -> p.Name)
let age = getExplicitOrCopiedArg age "age" (fun p -> p.Age)
member x.Name = name
member x.Age = age
let bill = new Person(name = "Bill", age = 20)
let olderBill = new Person(bill, age = 25)
printfn "Name: %s, Age: %d" bill.Name bill.Age
printfn "Name: %s, Age: %d" olderBill.Name olderBill.Age
Upvotes: 4
Reputation: 29100
An alternative version of Brian's answer that will evaluate b
at most once, but won't evaluate it at all if B
is never used
type Test(a:float) =
// constructor
let b = lazy
printfn "oh no"
a * 2.
// properties
member this.A = a
member this.B = b.Value
Upvotes: 17
Reputation: 118865
It's a property; you're basically calling the get_b()
member.
If you want the effect to happen once with the constructor, you could use a class:
type Test(a:float) =
// constructor
let b = // compute it once, store it in a field in the class
printfn "oh no"
a * 2.
// properties
member this.A = a
member this.B = b
Upvotes: 13