Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ocaml - Accessing components in an array of records

I have a array of record type tt - originally with more components ;-) - and like to change its values within a for loop:

type tt={mutable x: int};;
let f0={x= -1};;
let max=10;;
let ff=Array.create max f0;;
for i=0 to max-1 do ff.(i).x <- i;done;;

Nevertheless, all fields of ff have the value 9 instead of having values from 0 to 9. Is ff.(i).x correct? I also tried

for i=0 to max-1 do f0.x <- i;ff.(i) <- f0;done;;

but with the same result... (I'm using OCaml version 4.00.1) What is wrong? I would be happy if somebody could give me a hint!

like image 808
Miguel Garcia Avatar asked Dec 22 '12 09:12

Miguel Garcia


3 Answers

This is a classic mistake that beginners do with Array.create and mutable state. I have explained it in detail there. The summary is that Array.create n foo does not create copies of foo (how could it?), it creates an array of cases all pointing to the same foo.

like image 84
gasche Avatar answered Nov 15 '22 10:11

gasche


The problem is that all cells of the ff array contain the same element, namely f0. You need to create a fresh element of type tt for each cell. This is a way to do so:

type tt={mutable x: int};;
let max=10;;
let ff=Array.init max (fun i -> {x= i});;

Now you can modify a cell without affecting the other cells.

like image 29
jrouquie Avatar answered Nov 15 '22 12:11

jrouquie


The problem is that, since the record is mutable, it is stored by reference and not by value as you would expect from a non mutable data type (as an integer) so when you do

let ff=Array.create 10 f0;;

you are actually storing 10 references to the same record. And then each iteration of

for i=0 to max-1 do ff.(i).x <- i;done;;

just updates the same reference multiple times, so since last iteration is with i = 9 then the only real record contained in the array gets that value.

What you need to do is to create 10 different record such with:

# type tt = {mutable x: int};;
type tt = { mutable x : int; }
# let f = Array.init 10 (fun i -> { x = -1});;
val f : tt array =
  [|{x = -1}; {x = -1}; {x = -1}; {x = -1}; {x = -1}; {x = -1}; {x = -1};
    {x = -1}; {x = -1}; {x = -1}|]
# f.(2).x <- 2;;
- : unit = ()
# f;;
- : tt array =
[|{x = -1}; {x = -1}; {x = 2}; {x = -1}; {x = -1}; {x = -1}; {x = -1};
  {x = -1}; {x = -1}; {x = -1}|]
like image 3
Jack Avatar answered Nov 15 '22 12:11

Jack