Immutable psandoz/conferences/2017-JavaOne/j1-2017... · PDF file JavaOne 2017 Immutable...

Click here to load reader

  • date post

    18-Apr-2020
  • Category

    Documents

  • view

    4
  • download

    0

Embed Size (px)

Transcript of Immutable psandoz/conferences/2017-JavaOne/j1-2017... · PDF file JavaOne 2017 Immutable...

  • JavaOne 2017 Immutable Collections CON6079

    Immutable Collections [email protected]

    @PaulSandoz

    1

  • JavaOne 2017 Immutable Collections CON6079 2

    Safe Harbor Statement
 The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle’s products remains at the sole discretion of Oracle.

  • JavaOne 2017 Immutable Collections CON6079

    Agenda

    • A recap of unmodifiable collections in the JDK

    • A brief overview of immutable collections in external Java libraries and JVM-based platforms

    • Immutable collections leveraging persistent data structures

    3

  • JavaOne 2017 Immutable Collections CON6079

    When referring to
 immutable collections


    there are no claims made as to the immutability of the collection’s elements

    4

  • JavaOne 2017 Immutable Collections CON6079

    Advantages of immutability

    • Don’t need to think about concurrency and 
 data races

    • Resistant to misbehaving libraries

    • Are constants that may be optimized at runtime

    • Implementations can optimize over time, space for representation and transformation

    5

  • JavaOne 2017 Immutable Collections CON6079

    Immutable collections 
 wish list

    • Manifests immutability
 (of the collections, not their elements)

    • Sealed
 (not publicly extensible)

    • Provide a bridge to mutable collections 
 (not extension of)

    • Efficient construction, updates, and copying

    6

  • JavaOne 2017 Immutable Collections CON6079

    Unmodifiable in the JDK

    • The JDK has the notion of unmodifiable collections

    • Unmodifiable is a runtime property of a collection

    • Modifying (add, put, remove, …) methods throw UnsupportedOperationException

    • No way to directly query

    7

  • JavaOne 2017 Immutable Collections CON6079

    Two forms of unmodifiable

    • Unmodifiable view or wrapper to a source or backing collection 
 
 List uvl = Collections 
 .unmodifiableList(sourceList);

    • Directly unmodifiable
 
 List dul = List.of(1, 2, 3, …);

    8

  • JavaOne 2017 Immutable Collections CON6079

    Immutability with unmodifiable collections

    • When wrapping ensure the source collection is never accessible*
 
 List uvl = Collections 
 .unmodifiableList(new ArrayList(source));
 source = null; 
 
 List dul = stream.collect( 
 collectingAndThen(toList(), 
 Collections::unmodifiableList))

    • List.of and friends are is if the source is never accessible

    9 * Except, of course, to the unmodifiable wrapper

  • JavaOne 2017 Immutable Collections CON6079

    JDK collections as immutable collections

    ✗ Manifests immutability

    ✗ Sealed

    • Provide a bridge to mutable collections

    ✗ Efficient construction, updates and copying

    10

  • JavaOne 2017 Immutable Collections CON6079

    Unmodifiable
 is a reasonable abstraction for

    mutable collections
 but not for


    immutable collections

    11

  • JavaOne 2017 Immutable Collections CON6079

    Guava’s immutable collections

    • Defines sealed types such as ImmutableList, ImmutableMap, …

    • These implement the corresponding JDK mutable collection type 
 (ImmutableList implements List)

    • Copying is smart
 ImmutableList.copyOf(otherCollection)

    12

    https://github.com/google/guava/wiki/CollectionUtilitiesExplained

  • JavaOne 2017 Immutable Collections CON6079

    Guava’s collections are a good compromise

    ✔ Manifests immutability

    ✔ Sealed

    ✘ Provide a bridge to mutable collections

    ✘ Efficient construction (✔✘), updates (✘), and copying (✔✘)

    13

  • JavaOne 2017 Immutable Collections CON6079

    Eclipse collections: something for everyone

    ✔ Manifests immutability

    ✘ Sealed

    ✔ Provide a bridge to mutable collections

    ✘ Efficient construction, updates, and copying

    14

    https://github.com/eclipse/eclipse-collections/blob/master/docs/guide.md#-immutable-collections

  • JavaOne 2017 Immutable Collections CON6079

    Vavr (Java), Clojure, Scala

    ✔ Manifests immutability

    ✔ Sealed*

    ✔ Provide a bridge to mutable collections*

    ✔ Efficient construction, updates, and copying

    15

    * Not completely verified but believed to be mostly true

    https://github.com/vavr-io/vavr https://clojure.org/reference/data_structures#Collections https://docs.scala-lang.org/overviews/collections/overview.html

  • JavaOne 2017 Immutable Collections CON6079

    Vavr (Java), Clojure, Scala

    ✔ Efficient updates (addition, removal, replace, merge)

    • The immutable collection implementations leverage persistent data structures for maps, sets and vectors (non-linked lists)

    16

    https://github.com/vavr-io/vavr https://clojure.org/reference/data_structures#Collections https://docs.scala-lang.org/overviews/collections/overview.html

  • JavaOne 2017 Immutable Collections CON6079

    Persistent data structures • A persistent data structure preserves the previous

    version of itself when modified

    • Hash Array Mapped Tries (HAMTs) are the basis of efficient persistent (immutable) maps, sets, and vectors

    • Provide structural sharing between a new and previous version of a collection

    • Effectively constant time for many operations

    • Cache friendly

    17

  • JavaOne 2017 Immutable Collections CON6079

    Trie

    18

    In computer science, a trie, also called digital tree and sometimes radix tree or prefix tree (as they can be searched by prefixes), is a kind of search tree — an ordered tree data structure that is used to store a dynamic set or associative array where the keys are usually strings

    A trie for keys "A","to", "tea", "ted", "ten", "i", "in", and "inn".

    https://en.wikipedia.org/wiki/Trie

  • JavaOne 2017 Immutable Collections CON6079

    Hash Array Mapped Trie

    • Symbol is a 5 bit sequence

    • String is fixed in size, 32 bits, consisting of 7 symbols (last symbol is truncated to 2 bits)

    • String is the hashCode of an Object (the key)

    19

  • JavaOne 2017 Immutable Collections CON6079

    Hash Array Mapped Trie

    20

    32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01

    1 1 0 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 1 1 0

    0xCAFEBABE

    s1s2s3s4s5s6s7

  • JavaOne 2017 Immutable Collections CON6079

    HAMT properties

    • Wide branching factor, 32

    • Limited tree depth, 6

    • Effectively constant time lookup 
 
 O(log32N) = 
 O(log2N/log232) = 
 O(log2N/5)

    21

  • JavaOne 2017 Immutable Collections CON6079

    HAMT properties • Good structural sharing (for updates, merging and

    splitting) but also good memory usage and cache coherency

    • The basis for vectors, where index is the hash code (see also Relaxed Radix Balanced trees), and multi- maps

    • Can be applied to mutable collections, for efficient construction of an immutable collection

    • Efficiently implemented in Java

    22

  • JavaOne 2017 Immutable Collections CON6079

    A naive implementation

    23

    public class PMap {
 Object[] nodes = new Object[32 * 2];
 
 public Optional get(K k) { return get(k, hash(k), 0); }
 
 private Optional get(K k, int h, int d) {
 int symbol = symbolAtDepth(h, d);
 Object _k = nodes[symbol * 2];
 
 if (_k == SUB_LAYER_NODE) {
 PMap n = (PMap) nodes[symbol * 2 + 1]; 
 return n.get(k, h, d + 1);
 }
 else if (k.equals(_k)) return Optional.of((V) nodes[symbol * 2 + 1]);
 else return Optional.empty();
 }
 
 static int symbolAtDepth(int h, int d) {
 return (h >>> (d * 5) & (32 - 1));
 }
 }

  • JavaOne 2017 Immutable Collections CON6079

    A naive implementation

    24

    public class PMap {
 Object[] nodes = new Object[32 * 2];
 
 public Optional get(K k) { return get(k, hash(k), 0); }
 
 private Optional get(K k, int h, int d) {
 int symbol = symbolAtDepth(h, d);
 Object _k = nodes[symbol * 2];
 
 if (_k == SUB_LAYER_NODE) {
 PMap n = (PMap) nodes[symbol * 2 + 1]; 
 return n.get(k, h, d + 1);
 }
 else if (k.equals(_k)) return Optional.of((V) nodes[symbol * 2 + 1]);
 else return Optional.empty();
 }
 
 static int symbolAtDepth(int h, int d) {
 return (h >>> (d * 5) &