Programming
collections kotlin
Updated Mon, 12 Sep 2022 07:50:33 GMT

Kotlin: exposing immutable list in API


I am new to Kotlin and am wrestling with the problem of returning immutable versions of internally mutable lists.

I reviewed the following 'Kotlin: Modifying (immutable) List through cast, is it legitimate?' and understand that immutable lists are really just read-only views which do not expose the modification methods.

I want to have a class which exposes an "immutable" List and still want to take advantage of Kotlins automatic getters (without having to provide all the boilerplate for getting the list or a member of the list)

Is the following a bad idea (or will it cause a problem that may be blocked in future releases)

class Foo {
  val names: List<String> = LinkedList;
  fun addName(name: String) {
    (names as LinkedList).add(name)
  }
}

I am looking to allow (for example):

  val foo = Foo;
  println(foo.names.size)

But still prevent the caller from modifying the internals of the class (at least as much as possible). For example removing elements or clearing the backing list.




Solution

The following works:

class Foo {
    private val _names: MutableList<String> = mutableListOf()
    val names: List<String>
        get() = _names.toList()
    fun addName(name: String) {
        _names.add(name)
    }
}

The toList means that if they cast it to a MutableList<String> and try to add to it they will get an UnsupportedOperationException, the _names field holds the real data, and external access is done via the names property





Comments (4)

  • +1 – Thanks jrtapsell, Yes I know I can maintain this second variable as well... but that wasn't sure if needed the additional clutter.. I think it also works like this: val name: List<String> = _names — Oct 14, 2017 at 15:53  
  • +0 – ... although that probably would not prevent the cast — Oct 14, 2017 at 15:59  
  • +0 – The names property just acts as a immutable view of _names, although it would be nice if the clutter could be reduced — Oct 14, 2017 at 16:04  
  • +0 – Using the backing field may simplify the code: link — Nov 06, 2017 at 15:43