0

I have run into this scenario several times recently:

  1. a class has an immutable (indexed?) sequence member
  2. a factory member method creates a new instance with the sequence somewhat modified

What's an efficient way to do this?

class A( xs: IndexedSeq[Int] ) {
    def another: A = {
        val ys = xs.toArray.clone()   // !!!
        ys(7) = 13
        new A(ys)
    }
}

I do .toArray so that I can modify this sequence in place and .clone because I'm afraid that if the original xs was an array already, toArray will just return this and I will modify the objects (meant-to-be-immutable) values. However, this obviously makes two copies if xs was not an Array and I would really like to avoid that. Obviously, I could just check its type, but that seems very inelegant and I'm not too sure if I'd have to check against other mutable sequences which can wrap an Array. What do?

scala> val xs: Seq[Int] = Array(1, 2, 3)
ss: Seq[Int] = WrappedArray(1, 2, 3)

scala> val ys = xs.toArray
ys: Array[Int] = Array(1, 2, 3)

scala> ys(1) = 22

scala> ys
res1: Array[Int] = Array(1, 22, 3)

scala> xs
res2: Seq[Int] = WrappedArray(1, 22, 3)
StokedOver9k
  • 129
  • 1
  • 9

1 Answers1

2

If you don't really need mutability, then the best is just to ask for an immutable sequence; that way you don't need to worry about whether changing the data has side effects.

class A(xs: collection.immutable.IndexedSeq[Int]) {
  def another: A = {
    val ys = xs.updated(7, 13)
    new A(ys)
  }
}
0__
  • 66,707
  • 21
  • 171
  • 266
  • Is that efficient? I suspect that on average I'll be making O(n) updates (xs.size/2). – StokedOver9k Oct 19 '13 at 23:08
  • Although, I admit that I thought that the default was immutable already. Oops. – StokedOver9k Oct 19 '13 at 23:09
  • The type aliases are somewhat split: `Predef.Map` and `Predef.Set` are immutable, while `scala.Seq` and `scala.IndexedSeq` are generic, which is I guess to allow for interaction with arrays. The default factories are immutable, even `Seq(1, 2, 3)` (giving a `List`) and `IndexedSeq(1, 2, 3)` (giving a `Vector`). So that is a bit confusing. – 0__ Oct 20 '13 at 05:34