Immutable data structures for functional JavaScript

Immutable data structures for functional JavaScript

Presented at O'Reilly Fluent 2017: https://conferences.oreilly.com/fluent/fl-ca/public/schedule/detail/58872

Functional programming has been gaining popularity in the JavaScript community, and for good reason: rejecting side-effects and mutability (in-place changes to data) helps avoid a lot of headaches.

But even if you refuse to mutate objects, you’ll still need to deal with transformations to data. In a purely immutable world, this means you have to create a whole new object each time something changes, which can slow things down and eat up memory, making functional programming seem inefficient.

That’s where immutable data structures come in to save the day—and time and space. Also called persistent data structures, they help you efficiently make new “modified” versions of immutable objects by reusing parts of the old object that you don’t need to change. By making immutability efficient, such data structures are fantastic for functional programming and play a central role in functional languages such as Clojure.

Anjana Vakil explains how the concept of structural sharing makes efficient immutable data structures possible and demonstrates how they work under the hood. Anjana also offers an overview of two libraries—Mori and Immutable.js—that let you easily take advantage of these remarkable data structures in your JavaScript code. You’ll leave armed with a deeper understanding of how immutable data structures work and the practical knowledge to leverage them in your own functional JavaScript projects.

654527a5cff1756177ef0b1bb0af7aa3?s=128

Anjana Sofia Vakil

June 21, 2017
Tweet

Transcript

  1. @AnjanaVakil O’Reilly Fluent 2017

  2. hi! i’m anjana The Recurse Center

  3. functional programming rocks!

  4. functional programming pure functions • input → output • side

    effects • data in, data out mutable state
  5. Immutability rocks!

  6. rocks rock!

  7. Nobody sits like this rock sits. You rock, rock. The

    rock just sits, and is. You show us how to just sit here, and that's what we need. - I ❤ Huckabees (2004) rocks rock!
  8. in A land where mutation reigns...

  9. 0 1 2 3 4 5 6 7 foo

  10. zoo 1 0 3 2 5 4 7 6

  11. zoo 1 0 3 2 5 4 7 6

  12. zoo 1 0 3 2 5 4 7 6 Who

    put a in my zoo?!?
  13. with mutability come overhead & bugs

  14. Mutation must be stopped! (sorry, xavier)

  15. Mutation must be stopped! (sorry, xavier) let’s journey to the

    land of...
  16. immutable data! it just sits, and is (like rocks)

  17. zoo 1 0 3 2 5 4 7 6

  18. new zoo 1 0 3 2 5 4 7 6

  19. new zoo 1 0 3 2 5 4 7 6

  20. new zoo 1 0 3 2 5 4 7 6

  21. new zoo 1 0 3 2 5 4 7 6

    Great! My zoo just sits, and is!
  22. new zoo 1 0 3 2 5 4 7 6

    ...but my code runs like &
  23. copying wastes time & space

  24. isn’t there a better way?

  25. isn’t there a better way? we need a hero...

  26. persistent data structures!

  27. persistent data structures! masters of time & space!

  28. persistent data structures! old versions stay put... masters of time

    & space!
  29. persistent data structures! old versions stay put... ... new versions

    created efficiently! masters of time & space!
  30. What’s the source of their power?

  31. Trees!

  32. zoo 1 0 3 2 5 4 7 6

  33. 1 0 3 2 5 4 7 6

  34. 1 0 3 2 5 4 7 6

  35. 1 0 3 2 5 4 7 6

  36. 1 0 3 2 5 4 7 6 zoo

  37. how do we update things?

  38. 1 0 3 2 5 4 7 6 zoo

  39. 1 0 3 2 5 4 7 6 zoo 1

    0
  40. 1 0 3 2 5 4 7 6 zoo 1

    0
  41. 1 0 3 2 5 4 7 6 zoo 1

    0
  42. 1 0 3 2 5 4 7 6 zoo 1

    0 new
  43. 1 0 3 2 5 4 7 6 zoo 1

    0 new path copying!
  44. 1 0 3 2 5 4 7 6 zoo 1

    0 new Structural sharing! path copying!
  45. 1 0 3 2 5 4 7 6 zoo 1

    0 new Structural sharing! path copying! AWESOME! I can reuse most of the data!
  46. Trees + Sharing Turn & into &

  47. but how do we access things?

  48. but how do we access things? our reveals a secret

    identity...
  49. it’s a Trie! leaves hold values paths represent keys

  50. ape ant bat bee a b a e n p

    t e e t an ba be ap a b
  51. ape ant bat bee a b a e n p

    t e e t an ba be ap a b
  52. ape ant bat bee a b a e n p

    t e e t an ba be ap a b
  53. ape ant bat bee a b a e n p

    t e e t an ba be ap a b
  54. convert index to binary descend trie bit by bit

  55. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 0 1 (1) (0) (3) (2) (5) (4) (7) (6)
  56. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 0 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5]
  57. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 0 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5] zoo[0b101]
  58. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 0 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5] zoo[0b101] zoo→1→0→1
  59. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 0 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5] zoo[0b101] zoo→1→0→1
  60. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5] zoo[0b101] zoo→1→0→1 0
  61. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 1 (1) (0) (3) (2) (5) (4) (7) (6) zoo[5] zoo[0b101] zoo→1→0→1 0
  62. it’s a !

  63. it’s a ! it’s a !

  64. it’s a ! it’s a ! it’s...

  65. bitmapped vector trie!

  66. Let’s talk complexity...

  67. immutable array lookup: O(1) update: O(n) lookup: O(log n) update:

    O(log n) Bitmapped vector trie vs.
  68. zoo[18977] zoo[0b100101000100001] zoo→1→0→0→1→0→1→0→...

  69. zoo[18977] zoo[0b100101000100001] zoo→1→0→0→1→0→1→0→... this is taking forever….

  70. who said the needs 2-way branching?!? ( bit per level)

  71. who said the needs 2-way branching?!? ( bit per level)

    we can choose...
  72. fewer branches - deep trees + small nodes + shallow

    trees - large nodes more branches vs.
  73. 32-way branching is a good balance! ( bits per level)

  74. zoo[18977] zoo[0b100101000100001] zoo→10010→10001→00001

  75. immutable array lookup: O(1) update: O(n) lookup: O(log n) update:

    O(log n) Bitmapped vector trie vs.
  76. immutable array lookup: O(1) update: O(n) lookup: O(log 32 n)

    update: O(log 32 n) Bitmapped vector trie vs.
  77. immutable array lookup: O(1) update: O(n) lookup ≈ O(1) update

    ≈ O(1) Bitmapped vector trie vs.
  78. What about objects? We need non-integer keys too

  79. zoo "k" "m" "b" "l" "g" "f" "w" "t"

  80. hash the to get a number descend trie as before

  81. zoo["g"] hash("g") === 5 === 0b101 zoo→1→0→1

  82. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 1 zoo[hash("g")] zoo[0b101] zoo→1→0→1 0 "k" "m" "b" "l" "g" "f" "w" "t"
  83. 001 000 011 010 101 100 111 110 zoo 0

    1 0 1 1 0 "k" "m" "b" "l" "g" "f" "w" "t" Awesome! I can use whatever s I want! zoo[hash("g")] zoo[0b101] zoo→1→0→1
  84. hash array mapped trie!

  85. Let’s recap! mutability: immutability: copying: & sharing: &

  86. these are some data structures! But how do we use

    them in Javascript?
  87. libraries! immutable.js! Mori!

  88. None
  89. var Imjs = require("immutable"); var a = Imjs.List.of(1,2); // List

    [1, 2] var a2 = a.push(3); // List [1, 2, 3] a.size; // 2 a2.get(2); // 3
  90. var o = Imjs.Map({"a": 1,"b": 2}); // Map {"a": 1,

    "b": 2} var o2 = o.set("a", 3); // Map {"a": 3, "b": 2} o.get("a"); // 1 o2.get("a"); // 3
  91. None
  92. var mori = require("mori"); var a = mori.vector(1,2); // [1

    2] var a2 = mori.conj(a, 3); // [1 2 3] mori.count(a); // 2 mori.get(a2, 2); // 3
  93. var o = mori.hashMap("a", 1, "b", 2); // {"a" 1

    "b" 2} var o2 = mori.assoc(o, "a", 3); // {"a" 3 "b" 2} mori.get(o, "a"); // 1 mori.get(o2, "a"); // 3
  94. immutable.js MORI vs. × JavaScript all the way × Object-oriented

    API × Smaller facebook.github.io/immutable-js swannodette.github.io/mori × ClojureScript under the hood × Functional API × Faster
  95. live long and don’t mutate!

  96. thanks! @AnjanaVakil Icons by EmojiOne Template by SlidesCarnival Inspiration/curiosity by

    Sal Becker & Recurse Center Conference by O’Reilly
  97. J.N. L'orange, Understanding Clojure’s Persistent Vectors, Blog series hypirion.com/musings/understanding-persistent-vector-pt-1 P.

    Bagwell, Ideal hash trees, 2001 lampwww.epfl.ch/papers/idealhashtrees.pdf R. Hickey, Persistent data structures and managed references, QCon 2009 infoq.com/presentations/Value-Identity-State-Rich-Hickey D. Spiewak, Extreme Cleverness: Functional Data Structures in Scala, Strange Loop 2011 infoq.com/presentations/Functional-Data-Structures-in-Scala M. Thatte, What Lies Beneath: A Deep Dive Into Clojure's Data Structures, EuroClojure 2015 youtu.be/7BFF50BHPPo D. Nolen, Immutability, interactivity & Javascript, FutureJS 2014 youtu.be/mS264h8KGwk L. Byron, Immutable Data & React, React.js Conf 2015 youtu.be/I7IdS-PbEgI References & more