Weird thing of Array.create in OCaml

1.6k views Asked by At

I'm a newbie at OCaml. And when I do some coding using array in Ocaml I come to a problem I can't understand.
Here is the code:

let a = Array.create 5 (Array.create 5 0);
a.(0).(1) <- 1

I just want to assign 1 to a[0][1] but then things happened: all the element in the first colummn has been assigned. That is, a[0][1], a[1][1], a[2][1], a[3][1] and a[4][1] are all equal to 1 after the code above executed.
If I create the array using:

Array.make_matrix 5 5 0

everything is fine.

My environment:

Ubuntu 13.10
Ocaml 4.01.0
open Core.Std 
3

There are 3 answers

2
camlspotter On BEST ANSWER

This is a common pitfall of Array.create. Use Array.init instead when your array element is boxed.

Array.create initializes the array elements with the same value: if the value is boxed, with the same pointer. In your case, all the elements a.(i) points to the same array created by Array.create 5 0.

Correct code should be

let a = Array.init 5 (fun _ -> Array.create 5 0)

This creates 5 individual arrays.

You should check this Q/A: Ocaml - Accessing components in an array of records

0
newacct On

You only call Array.create twice, so only two arrays are created -- one whose elements all point to the other.

Array.create creates an array and sets each element to a copy of the value given. So it's as if you did this:

let x = Array.create 5 0;
let a = Array.create 5 <some dummy value>;
a.(0) <- x;
a.(1) <- x;
a.(2) <- x;
a.(3) <- x;
a.(4) <- x;

See the problem? All five elements are set to x, a pointer to the same array.

Note that all types in OCaml are basically reference types. (Technically, int and some smaller types like char and bool, and algebraic data types with all no-arg constructors, are implemented as value types. But value types are semantically equivalent to immutable reference types except for physical equality. So you can think of all types as reference types for simplicity.)

0
Jackson Tale On

Just for more information:

Here is the doc of Array: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Array.html

val make : int -> 'a -> 'a array
Array.make n x returns a fresh array of length n, initialized with x. All the elements of this new array are initially physically equal to x (in the sense of the == predicate). Consequently, if x is mutable, it is shared among all elements of the array, and modifying x through one of the array entries will modify all other entries at the same time.
Raise Invalid_argument if n < 0 or n > Sys.max_array_length. If the value of x is a floating-point number, then the maximum size is only Sys.max_array_length / 2.

val create : int -> 'a -> 'a array
Deprecated. **Array.create is an alias for Array.make**.