19

We are encouraged to have immutable variables as much as we can.

But sometimes when I have to modify a list I start to wonder which approach would be better for current situation...

val mutableList = mutableListOf()
// where I can just .add() / .remove() accordingly

or

var immutableList = listOf()
// where I can create a new list (using filter or `+`) each time a change is made

I guess there are different scenarios one is preferred over the other. Hence I would like to know when one should be used over the other

NoOorZ24
  • 2,914
  • 1
  • 14
  • 33
Elye
  • 53,639
  • 54
  • 212
  • 474
  • I would recommend using var list:List, always. it prevents confusion in code, and it's always clear whether you are updating your list or not. I would use val list:MutableList only if logic is simple, or list gets updated frequently. even in normal android app with liveData you usually replace the whole list instead of updating mutable list which will cause issues with your observer. – Amr Jun 21 '22 at 12:25

3 Answers3

17

val -> You could think that you can't reassign for the variable.

//that is ok
var a:Int = 1
a=2
//Even you can reassign but you can't change its type
a= "string"  //that's wrong

//that is wrong
val b:Int = 1
b = 2

ListOf -> You could think that you can't insert/delete/alter any element in the list (can't do anything to the content of the list)

var list:List<Int> = listOf(1,2,3,4) //[1,2,3,4]
//you can read list
list.get(0)
list[0]
//but you can't change(/write) the content of the list (insert/delete/alter)
list.set(0, 100)
list.add(5)
list.removeAt(0)

var mutableList:MutableList<Int> = mutableListOf(1,2,3,4) //[1,2,3,4]
//you can read and write
mutableList.get(0)
mutableList.set(0, 100) //[100,2,3,4]
mutableList.add(5)      //[100,2,3,4,5]
mutableList.removeAt(0) //[2,3,4,5]

SO combine both of them, you will get four cases

Case 1: var mutableList:MutableList = mutableListOf(1,2,3,4)

//you can reassign 
mutableList = mutableListOf(4,5,6,7) //[4,5,6,7]
//you can alter the content 
mutableList.set(0, 100) //[100,5,6,7]
mutableList.add(8)      //[100,5,6,7,8]
mutableList.removeAt(0) //[5,6,7,8]

Case 2: val mutableList:MutableList = mutableListOf(1,2,3,4)

//you can't reassign 
mutableList = mutableListOf(4,5,6,7) //that's wrong

//you can alter the content 
mutableList.set(0, 100) //[100,2,3,4]
mutableList.add(8)      //[100,2,3,4,8]
mutableList.removeAt(0) //[2,3,4,8]

Case 3: var list:List = ListOf(1,2,3,4)

//you can reassign 
list= ListOf(4,5,6,7) //[4,5,6,7]

//you can't alter the content 
list.set(0, 100) //that's wrong
list.add(8)      //that's wrong
list.removeAt(0) //that's wrong

Case 4: val list:List = ListOf(1,2,3,4)

//you can't reassign 
list= ListOf(4,5,6,7) //that's wrong

//you can't alter the content 
list.set(0, 100) //that's wrong
list.add(8)      //that's wrong
list.removeAt(0) //that's wrong

//the only thing you can do is Read
list.get(0)  //return 1
list[0]      //return 1
Leon Chang
  • 471
  • 1
  • 4
  • 14
15

Mutable and immutable list increase the design clarity of the model.
This is to force developer to think and clarify the purpose of collection.

  1. If the collection will change as part of design, use mutable collection
  2. If model is meant only for viewing, use immutable list

Purpose of val and var is different from immutable and mutable list.
val and var keyword talk about the how a value/reference of a variable should be treated.

  • var - value/reference assigned to a variable can be changed at any point of time.
  • val - value/reference can be assigned only once to a variable and can't be changed later point in the execution.

It is completely valid in Kotlin to assign mutable list to a val and add element to it.

val a = mutableListOf(1,2,3,4)
a.add(5)
println(a)

will output

[1, 2, 3, 4, 5]
4

I guess there are different scenarios one is preferred over the other. Hence would like to get to know when one should be used over the other etc.

There are several reasons why immutable objects are often preferable:

  • They encourage functional programming, where state is not mutated, but passed on to the next function which creates a new state based on it. This is very well visible in the Kotlin collection methods such as map, filter, reduce, etc.
  • A program without side effects is often easier to understand and debug (you can be sure that the value of an object will always be the one at its definition).
  • In multithreaded programs, immutable resources cannot cause race conditions, as no write access is involved.

You have also some disadvantages:

  • Copying entire collections just to add/remove a single element is computationally expensive.
  • In some cases, immutability can make the code more complex, when you tediously need to change single fields. In Kotlin, data classes come with a built-in copy() method where you can copy an instance, while providing new values for only some of the fields.

Which one you end up using depends on the use case at hand. For data classes (bundling a few attributes together), it's often a good idea to stick to immutability. For collections, if you use immutable ones just to modify their copies and re-assign the reference pointing to them all the time, you can as well use mutable ones. If you share a collection to many parts of your application that depend on the state remaining constant, use immutable.

Keep in mind that Kotlin collections have different concepts:

  1. Mutable collections: MutableList<T>, MutableSet<T>, MutableMap<T>
    These can be modified at any time.
  2. Read-only collections: List<T>, Set<T>, Map<T>
    These provide a read-only view on the collection, i.e. the collection cannot be modified through that reference. It gives no guarantee about immutability though (another mutable reference to it can still exist and used for modification).
  3. (Proposed, not yet part of Kotlin)
    Immutable collections: ImmutableList<T>, ImmutableSet<T>, ImmutableMap<T>
    These would guarantee true immutability, and provide patterns to build new modified collections based on them. See the Proposal for details.
TheOperator
  • 5,936
  • 29
  • 42