 Hi, everybody. Okay, I'm not gonna talk into the mic. I'm going to talk normally, just like I always would on a stage. So, hi, I'm Anjana, that keel, and today I'm gonna tell you a little bit about persistent data structures, which are a thing that I found out about when I was at the recurse center last fall. By now, you've probably heard of it, woo. Shout out to the fall two batch in the house. Yeah, and when I was there, I found out that there's this thing called functional programming. And one of my batch mates, Sal Becker, who's a functional programming guy, closed your guys, sat me down one day and was like, you know, if you're interested in functional programming, you should probably find out about these things called persistent data structures and gave me a brief overview of what they are. And I was like, that's so beautiful and simple and brilliant and cool. And so that's why I'm here today, to spread my enthusiasm to all of you, hopefully. So, functional programming, brax, it's pretty cool. Make some noise if you agree with that statement. Awesome, I'm not gonna talk really about what functional programming is or why it's cool if you're curious. You can talk to all those people that just made noise. So, but as we saw earlier in a quote from Mary Rose Cook, one thing that functional programming does not have is side effects. So, changing things outside of the particular computation or whatever you're doing within a particular function. And so, one nice thing that goes along with functional programming is immutability, which also rocks. And in order to figure out why immutability is cool, let's talk about rocks, cause rocks rock. So, this is a drawing of a boulder in Central Park and some people hanging out on it, trying to put a little alt text on my slides here. And I'd like to take this moment to read y'all a poem about rocks. 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. It's a poem from the movie I Hard Huckabees 2004, existential comedy, pretty cool, check it out. But the point is that immutability is like rocks. When we have some immutable data, it just sits and is forever. And that rocks because it allows us to avoid a lot of headaches that having mutable data that changes and we can't depend on like rocks can bring about. So, when we're working with mutable data, let's say I have some kind of objects like a little array of some numbers, zero to seven here. I'll give it a name because we like naming things. I'll call it foo because it's boring. And if I want to change something to make this a bit more exciting, like let's say I figure that one could really be a spiffed up by changing it to an exclamation point. I just change it in the data. And so now my thing that's called foo looks different. And that's convenient if I'm like changing things, but it's inconvenient because I have to manage like keeping track of who changed, what about foo, when and how, and that's a lot of overhead. And then if foo changes in some way that I wasn't expecting, somebody else changes it from somewhere, then I could have a bug and that's no fun. So, frowny face. So, if we use immutability, then once I create an object like foo, it is the rock. It just sits and is forever. It can never be changed. So, if I decide that I want something similar to foo but more exciting with that exclamation point in it, I could make, one way I could do it is I could make an entire new object called woo, which has this exclamation point in it. But in all other respects, it looks exactly the same as foo. And that's cool because now if something was depending on foo always being the same, it doesn't break, but I still have my new exciting woo version. So, if I, this is one way of handling immutable data, but it's not great because I had to go through and copy everything else in foo that didn't change, the zero, the two, the three, the da da da. And that takes up a lot of time and a lot of space, right? So, I have to go through everything in my array. I have to make an entire new copy and it's like, and as soon as you get long things or big complicated objects or many, many copies, you run into issues. So, there must be a better way of using immutable data, which rocks as we saw. And spoiler alert, there is persistent data structures. So, the basic idea of persistent data structures is just that the old versions never change. Like as we saw in the really simple copying example, the old versions of an object just sit and are like rocks. And that's cool, but ideally in practice, when we talk about persistent data structures, we're trying to do this in a way that's more efficient when I wanna update something or change something about the old version. And so, we wanna have that efficiency. And so, the idea is to do magic, huh? No, we don't have to make prayers to the gods of time and space complexity. We can actually use a really, really simple idea, which is to reuse unchanged parts of our old versions of the data structure. So, one really simple thing we could do is instead of using like an array itself, we could make it a linked list. So now I have one pointing to two, sorry, zero pointing to one, one pointing to two, et cetera. And that's my foo. And if I wanna change the one to an exclamation point, I can make that exclamation point as a new node and then have that point to the old node of two. So, the exclamation comes before two. But the problem is I'd have to also copy everything that came before the exclamation points. I'd have to make a new copy of zero, point that to the exclamation point. And so now I have my woo object, which is like a partial copy of my old list. And that's cool, because we're saving everything after the list being copied because those numbers two, three, et cetera, we can reuse the old nodes. But if I wanted to change the seven to exclamation point, I would still have to copy everything before it. So in the worst case, it's like the same. So we can probably do better, and we can. Let's talk about trees. So, this is a drawing of some trees. And in particular, when you hear about persistent data structures and trees, you usually hear about tries, which is like a specific type of try, but that's so well actually. I just want to actually myself, so who cares? Anyway, so the basic idea is that now, instead of having our array, we could split it up into nodes that have just parts. And I could split it up individually so that I have zero and a node and one and a node, but they might be lonely. So let's put them with a buddy. So we could have two things in each node, or we could have eight or 32, or however many you want. But the idea is that we have these leaf nodes that contain our values. And then we add intermediate nodes in the tree that kind of pair up those leaf nodes, or put them in groups of 32 or whatever it is. And then we go up and up until we have some kind of root node that unites all of our little nodes and gives us the tree that we previously were calling the array foo. So now foo is our tree. And if I want to change something, all I have to change is one of those nodes at the bottom, not all of them, not a whole sequence. And then I can copy over that node and all of the other nodes between it and the root of the tree. So everything on that path. It's called path copying, unsurprisingly. It works like this. We copy over that zero one node and we change it to a zero explanation point. And then we copy over any of the little intermediate nodes that were previously linking to the rejected boring one node. And ultimately we get a new root, which is our woo. And so here now we are reusing a lot of the old structure of our foo tree. And that's called sharing structure or structural sharing. So here in yellow we can see that all of the leaf nodes containing two, three, four, five, six, seven and then any intermediate nodes that weren't affected by us creating our new zero explanation point node, those are shared between the old version foo and the new version woo. And so in this case this is better than our linked list example earlier because if I wanted to change the seven to an exclamation point, I don't have to copy over all the other numbers. I can just copy that one node and reuse everything on the other side of the tree. And this is, we're talking about updates here, but similarly it works for adding something or popping something off, et cetera. And there's a whole bunch of optimizations you could do to make this really, really, really fast and great, but this is the basic idea is just sharing the old data as much as possible. And by formulating it as a tree like this we can reuse a lot more of a structure than with other solutions. So I thought this was pretty cool when I found out about this at a recur center and I was like, yeah, let me do it in JavaScript. Okay, that's complicated, but it's not. And I'm gonna tell you in a moment what we can do to use these in JavaScript. But first, brief recap. Mutability, cool. Copying things over, not cool because it wastes time and space. Sharing old data, awesome. So if you wanna do this kind of thing in a language like JavaScript, as I did, you could use a couple of libraries that allow you to just plug and play basically these type of persistent data structures. So one is Mori, which is a Clojure script port by David Nolan. It's pretty cool because it has a totally functional API. You can check out the link there for its GitHub, which has really good docs and everything. There's also Immutable.js, which was a JavaScript library created by Facebook. And that, it has a bit less of a functional API. It's got like methods on objects. So it sort of seems like you're changing something, but you're not, you're really not. You're creating new ones. But it's a bit smaller than Mori, so also a valid option. Anyway, and if you use a different language than JavaScript, Google it. There's probably a library. For example, there's PySystems for Python because puns are great. And if you don't want to use libraries, you could also try using a functional language. Like Clojure, for example, which has these things built right in. And so what I've been talking about these trees or tries, whatever, well actually, is kind of inspired by the way that they're implemented in Clojure, which Richiki designed the implementation of those data structures like vectors and hash maps and whatever based on a paper by Phil Bagwell called ideal hash trees, which is some good further reading on this topic. If you're intrigued by this concept, as I was, and you want to learn more, you could check out that paper, go right to the source and read Phil Bagwell's paper and associated articles. Or I highly recommend this series of blog posts by Jean-Nicolas Laurent, called Understanding Clojure's Persistent Vectors that explains a lot more of the optimizations and stuff that you could do here. And yeah, basically persistent data structures are really exciting. And if you want to get into functional programming, you should use them, because immutability rocks. So that's it, thanks very much. I'm Anjanavakil, tweet me at at Anjanavakil. And thanks to all the RC alums that helped me with this talk and taught me about this in the first place, like Sal Becker. And thanks to Big Bang Con for having me. Thank you.