Javimmutable Collections

Banner

  • Why Immutability?
    • thread safety since race conditions are impossible with immutable data structures
    • safe to pass as parameter values or return from methods
      • return value especially nasty with Collections.unmodifiableMap and friends
    • eliminate need for bad stuff like locking and defensive copying
    • Good Advice
  • Kinds of immutable data structures
    • Pseudo-immutability - Collections.unmodifableList, etc
    • Guava ImmutableList, ImmutableMap, etc
      • defensive copying during creation then unchangeable without another full copy
      • no insert, delete, put etc methods provided since they would be slow
    • Functional/Persistent immutability
      • any given copy of structure never changes but mutated variations can be created easily
      • efficient creation of modified versions of data structure
      • insert, delete, put etc methods are provided that return new version of structure reflecting the change
  • Isn’t that slow?
    • NO!!
    • structure sharing makes it efficient
    • re-use almost entire data structure in every modified variation
    • creating variation requires creating ~ log2(n) or log32(n) new nodes
      • log2(1 million) = 20
      • log32(1 million) = 4
      • so changing a value in a 1 million node 32-way trie only creates 4 new nodes and re-uses all others
    • These images illustrate structure sharing concept (though none of them exactly match how javimmutable does things)
  • What about hash maps?
    • mutable hash maps use an integer hash code and a big array indexed by the hash code
      • copying the array on every modification would be too slow
      • but hash code can be stored more efficiently in a trie
    • This image of a string trie illustrates how a trie can be built up from pieces of a string
    • Break integer hash into parts of 4 bits each
      • 0x1234 breaks into parts 1, 2, 3, and 4
      • build tree of arrays
        • each level in tree use appropriate part (first at root, second at depth 1, etc)
    • Images illustrating hash array mapped trie concepts
    • Javimmutable uses 32 element arrays (5 bits per part) at each level of tree
      • Don’t you wind up with a ton of mostly empty arrays?
      • no! - create bit mask with each bit representing an array index
        • 32 bit int mask maps to 32 indexes in array, tree always max depth 7 (root has only 2 bit mask)
        • create array with size == number of 1 bits in mask
        • first 1 bit in mask is index of first element in array, etc
        • modern CPUs have native instruction to determine first 1 bit in an int
        • java provides native method to expose that instruction
      • performance numbers