Completely lost in trying to mutate property in sequence

160 views Asked by At

I am completely at loss why this code doesn't mutate a member variable in a sequence of types:

for p in prescrs do
    p.ATC <- "A"
    for c in p.Drug.Components do
        for s in c.Substances do
                s.DoseTotal.Adjust <- adjustKg
                s.DoseTotal.Time <- "DAY"
                s.DoseTotal.Unit <- s.DrugConcentration.Unit
                s.DoseRate.Adjust <- adjustKg
                s.DoseRate.Time <- "DAY"
                s.DoseRate.Unit <- s.DrugConcentration.Unit

prescrs is a sequence of Prescriptions which is a very simple 'POCO' defined as a type with member values. I don't have clue why this doesn't work.

I tried a simple test case like:

type IterTest () =
    member val Name = "" with get, set
    member val IterTests = [] |> List.toSeq : IterTest seq with get, set

let iterseq = 
    [
        new IterTest(Name = "Test1")
        new IterTest(Name = "Test2")
    ] 
    |> List.toSeq

iterseq |> Seq.iter(fun x -> x.IterTests <- iterseq)
iterseq |> Seq.iter(fun x -> 
    x.IterTests
    |> Seq.iter(fun x' -> x'.Name <- "itered"))

But here the result is as expected. So, can't even quite reproduce my problem???

Found a solution (without really understanding the problem above). When I first convert the prescrs sequence to a list like:

let prescrs = prescrs |> Seq.toList

and then do the imperative looping, properties do get mutated.

1

There are 1 answers

1
scrwtp On BEST ANSWER

Try this sample:

type Mutable() = 
    member val Iterated = false with get, set

let muts = Seq.init 5 (fun _ -> printfn "init"; Mutable())

let muts2 = muts // try again with let muts2 = muts |> List.ofSeq

printfn "Before iter"

for a in muts2 do
    printfn "iter"    
    a.Iterated <- true 

printfn "After iter" 

muts2 |> List.ofSeq

and check how iter and init are interleaved.

Seqs are lazy, but are not cached once computed. So even if you imperatively try to mutate some of the elements in your prescrs sequence, it all goes away once you pull prescrs again. If you change prescrs into a concrete collection type like list before doing the mutation, you no longer hit the same problem. Note that things might get even trickier if what you have is a seq inside a seq inside a seq.

The best idea would be to avoid mutation in the first place though.