Question

Minimal Working Example (Scala 2.9.2):

object Main extends App {
  class A {
    var a=0
  }
  val b = Array.fill(2)(new A)
  b(1).a = 9
  println(b(0).a) //prints 0
  println(b(1).a) //prints 9

  val a = new A
  val c = Array.fill(2)(a)
  c(1).a = 9
  println(c(0).a) //prints 9
  println(c(1).a) //prints 9
}

A related question is "Is it the same with imported Java classes?" How can I workaround, if I need to fill an Array inside a function with copies of an instance passed as argument? [Regarding identical copies, it was worth to me to check out the easy cloning library.

Just adding the workaround to a function call, based on answers:

  class A {
    var a=0
  }

  def f(a: => A) {             // "=>" added
    val b = Array.fill(2)(a)
    b(1).a=9
    println(b(0).a) //prints 0
    println(b(1).a) //prints 9
  }

  f(new A)

Another way is to declare a function, not a value def a = new A:

object Main extends App {
  class A {
    var a=0
  }
  val b = Array.fill(2)(new A)
  b(1).a = 9
  println(b(0).a) //prints 0
  println(b(1).a) //prints 9

  def a = new A
  val c = Array.fill(2)(a)
  c(1).a = 9
  println(c(0).a) //prints 0
  println(c(1).a) //prints 9
}
Was it helpful?

Solution

The fill method is defined with it's second parameter as "call-by-name". This means that the passed-in block is re-evaluated for every cell in the Array. See in the definition that the type of elem is => T, not simply T:

def fill[T: ClassManifest](n: Int)(elem: => T): Array[T]

So in your first version, the block new A is re-evaluated for each cell, meaning that each cell gets a fresh A object. In the second version, new A is called only once, and that object is placed into every cell.

You can actually see this if you run on the REPL:

scala> val b = Array.fill(2)(new A)
b: Array[A] = Array(A@2049bed2, A@498edd8d)    // two different objects

scala> val c = Array.fill(2)(a)
c: Array[A] = Array(A@31e0c0b6, A@31e0c0b6)    // the same object repeated

OTHER TIPS

Having a look at the signature of fill

def fill[T: ClassManifest](n: Int)(elem: => T)

So it gets a call-by-name argument, which means new A will be executed every time you process a cell in the array.

One fills the array with a single instance of A, the other fills the array with a new instance of A.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top