windweller
windweller

Reputation: 2385

immutable val vs mutable ArrayBuffer

mutable vs. immutable in Scala collections

Before I post this question, I have read the above article. Apparently if you store something in val, you can't modify it, but then if you store a mutable collection such as ArrayBuffer, you can modify it!

scala> val b = ArrayBuffer[Int](1,2,3)
b: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

scala> b += 1
res50: b.type = ArrayBuffer(1, 2, 3, 1)

scala> b
res51: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 1)

What is the use of using val to store a mutable ArrayBuffer? I assume the only reason b changes is because val b holds the memory address to that ArrayBuffer(1,2,3).

If you try var x = 1; val y = x; x = 5; y, the output will still be 1. In this case, y stores an actual value instead of the address to x.

Java doesn't have this confusion because it's clear an Object can't be assigned to an int variable .

How do I know when is the variable in scala carrying a value, when is a memory address? What's the point of storing a mutable collection in a immutable variable?

Upvotes: 3

Views: 2104

Answers (4)

Andrew Cassidy
Andrew Cassidy

Reputation: 2998

What's the point of storing a mutable collection in a immutable variable

val a = new ArrayBuffer(1)
a = new ArrayBuffer[Int]()
<console>:9: error: reassignment to val

It prevents the variable from being assigned to a new memory address. In practice though scala encourages you not to use mutable state (to avoid locking, blocking, etc), so I'm having trouble coming up with an example for a real situation where the choice of var or val for mutable state matters.

Upvotes: 3

Marco
Marco

Reputation: 1652

Immutable object and constant value are two different things.

If you define your collection as val means that the referenced instance of the collection will always be the same. But this instance can be mutable or immutable: if it is immutable you cannot add or remove items in that instance, vice versa if it is mutable you can do it. When a collection is immutable to add or remove items you always create a copy.

Upvotes: 2

harp seal pup
harp seal pup

Reputation: 504

A simple answer is that vals and vars are all references. There're no primitive types in Scala. They're all objects.

val x = 1

is a reference named x that points to an immutable integer object 1. You cannot do 1.changeTo(2) or something, so if you have

val value = 5
val x = value
var y = value

You can do y += 10 This changes y to reference a new object, (5 + 10) = 15. The original 5 remains 5.

On the other hand, you cannot do x += 10 because x is a val which means it must always point to 5. So, this doesn't compile.

You may wonder why you can do val b = ArrayBuffer(...) and then b += something even though b is a val. That's because += is actually a method, not an assignment. Calling b += something gets translated to b.+=(something). The method += just adds a new element (something) to its mutable self and returns itself for further assignment.

Let's see an example

scala> val xs = ArrayBuffer(1,2,3)
xs: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

scala> val ys = ( xs += 999 )
ys: xs.type = ArrayBuffer(1, 2, 3, 999)

scala> xs
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 999)

scala> ys
res1: xs.type = ArrayBuffer(1, 2, 3, 999)

scala> xs eq ys
res2: Boolean = true

This confirms xs and ys point to the same (mutable) ArrayBuffer. The eq method is like Java's ==, which compares object identity. Mutable/Immutable references (val/var) and mutable/immutable data structures (ArrayBuffer, List) are different. So, if you do another xs += 888, the ys which is an immutable reference pointing to a mutable data structure also contains 888.

Upvotes: 4

Robin Green
Robin Green

Reputation: 33033

How do I know when is the variable in scala carrying a value, when is a memory address?

Scala always runs on the JVM (.NET support was discontinued), so types that are primitive types on JVM will be treated as primitive types by Scala.

What is the use of using val to store a mutable ArrayBuffer?

The closest alternative would be to use a var to store an immutable Seq. If that Seq was very large, you wouldn't want to have to copy the whole Seq every time you made a change to it - but that's what you might have to do! That would be very slow!

Upvotes: 0

Related Questions