Skip to content

Instantly share code, notes, and snippets.

@Mercandj
Last active July 10, 2020 12:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Mercandj/1526737d9aeb5ef37f99f84466050789 to your computer and use it in GitHub Desktop.
Save Mercandj/1526737d9aeb5ef37f99f84466050789 to your computer and use it in GitHub Desktop.

Immutable lists

Introduction

Immutable lists can be misleading. Here I will use Kotlin. This snippet is viable on Java, C#, Swift... too.

I'm assuming you understand why immutable objects are "more robust" to manipulate data.

Here a "book" with "pages".

data class Book(
   val pages: List<String>
)

Developers using your class can create books and get pages. The val means that pages is "final" so developers cannot change the pages reference from an instance of book.

// Developer 1
val pages = ArrayList<String>()
pages.add("Super page 1")
pages.add("Another super page, that's the 2")
val book = Book(pages)

No problem with that, you cannot do that

book.pages = ArrayList<String>() // Impossible

but here come the problems.

Problem 1: Modify input after affectation

Nothing can stop developers to do that

// Developer 1
val pages = ArrayList<String>()
pages.add("Super page 1")
pages.add("Another super page, that's the 2")
val book = Book(pages)

// Developer 2
pages.clear()

after that, your book instance is empty even if you though your object was immutable: playground.

Problem 2: Modify list from the getter

Nothing can stop developers to do that

// Developer 1
val pages = ArrayList<String>()
pages.add("Super page 1")
pages.add("Another super page, that's the 2")
val book = Book(pages)

// Developer 2
(book.pages as ArrayList).clear()

after that, your book instance is empty even if you though your object was immutable: playground.

Conclusion

To solve that, multiple solutions (non exhausive)

  • Use Collections.unmodifiableList(java.util.List<? extends T>)
  • Use org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:X.X.X
  • Do extra copies on constructor and on getter

Perso, to avoid extra library, I love to do that playground

class Book private constructor(
   private val pages: List<String>
) {

   // Plain old get function instead of Kotlin getter syntax to help clients auto completion "get..."
   fun getPages(): List<String> {
      return ArrayList(pages)
   }
   
   companion object {
   
      fun create(pages: List<String>): Book {
         return Book(ArrayList(pages))
      }
   }
}

PS: Illustrated with lists, but same "issue" with Map...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment