 All right, so everyone back, everyone back from pizza. OK, I'm going to keep this quite short, because that was nice and long, and I hope the panel is going to be nice and long and involved as well. So I'm Jamie. I work for With Associates. We're a digital agency. We build stuff on the web platform, some of it's with Rails, and increasingly, a lot of it's with Ember. Last month, Shimon demonstrated his new project called Ancient Oak. And it's an immutable data trees library written in JavaScript. He's kind of come from the closure, closure script background and brought some of those ideas into a sort of micro library. And he gave this really sort of thorough explanation of how it works under the hood, why and how it's efficient, and some of the abstract reasons you might want to use it, but not a real kind of application demo. And I was really captivated with the library, but I think a lot of us in the pub afterwards were kind of trying to think of what I'd use this for. Why would I use persistent data structures in an Ember app or something like that? So for anyone who wasn't here or doesn't know what they are, I've got a probably fairly inaccurate little walkthrough of what I think they mean to an Ember app. So let's say you've got an Ember app, and this is the data structure that your UI is manipulating. And you've got a user object, which has got some fields on it, and a basket which has got some items and some other bits and bobs and that. And you mutate the email, and that implies that the user object has also been mutated. And then let's say you mutate the color here, that implies that this item has been mutated, as is the basket, all the way on up to the user. And Ember makes sure that all those mutations notify every part of the UI or other parts of the app that you might be interested in. And then you bind up other bits of the UI. And it's brilliant until you reach a moment where, actually, you don't want to just hand over a piece of this data to some part of the UI that might go ahead and change it willy-nilly. I think the example of this is, I think this is my next slide. So you've got an edit route. So let's say you have an edit route for your user. You transition into it. And there's an input text field that's bound to someone's name. And it's kind of magic when you use Ember for the first time or Angular. You start editing the name. And immediately, everywhere that it's used also updates. But I think if you're editing your profile, that isn't the expected behavior. So one answer to this is you kind of make a clone of the user, give it to the edit route so that you can kind of edit in isolation in this buffer, make your changes, and then either apply them back to the kind of canonical user model that's in memory or discard them if you want to cancel it. And that totally works. But you've got to remember to copy the model. Like you'll hit a bug where things are changing you didn't expect, and it's because you forgot to copy it. And then you might add something to your template that clobbers the basket. Like maybe it sets a basket property on this copy of the user. You re-apply that to the canonical user, and then your whole basket tree has gone away and you've lost it. It's just got garbage collected or something like that. And that's maybe if you forgot to add the true flag to say this is a deep clone of this object. So this is where that color's good on this projector. So now it's green. This means this is immutable, which means none of this can be changed. All you can do is produce new versions of this tree. And this is what ancient Oak Shimon's library does and what things like, I think it's Mori, which is David Nolan's port of the Clojure Script library. So this thing is effectively frozen, and it really is frozen. Shimon's is unique in that it will do a deep, immutable tree. You feed it this tree from then on in. All you can do is make new versions of it. And then you can hand that thing to edit route. And when edit route sets stuff, or this is the idea, you're not changing that original tree, which is tied to other bits of your application. You're creating a new version of it. But because it's a persistent data structure, and this is kind of where the memory optimization, the efficiency comes in, those fields that haven't changed still point to the old places in memory that shared with the original version of this tree. The only thing that's new is this new thing that you've changed, the thing that you've set in your brand new version. And if you hit Save then on your edit route, you would promote your new version of the user model, let's say, up to be the new canonical version. And it still uses all the old tree. So there are implications there for it being quicker and allocating less memory, and therefore less garbage collection. And with this example, it's so trivial that it doesn't completely make the case. But imagine your tree was much more complex. And the idea of doing a deep clone of your tree, if you just wanted to give it to another part of your app, gave you the sweats a little bit. Even better, rather than simply kind of promoting this new version, you could keep a stack of all the versions. And they're not a complete brand new tree each time. They just point to the bits that are just for them and all the bits that are shared between all the trees. And then flicking between versions is just a matter of picking the one you want and then following it down. And you'll get all the stuff like that stuff is guaranteed to be shared. And it's going to flick over to the other one, and you'll see the new tree. So I wanted to see whether this could be made to work with Ember without giving up on data bindings, without giving up on all the nice stuff, basically. This experiment isn't finished yet, so I'm just going to do a quick walkthrough of where I've got to so far and hopefully plant the seed of where you could go with this and that they're not incompatible ideas. So I think I may be best served by turning mirroring off. Let's say a bit of recursive video recording capture, by the way. OK. So I'm just going to, I think I'm on the new version now. So this is without. So this app looks like, let's see, the root of first. So it's got a user edit root and a basket root. And you can see those in action like that. And so let's have a look at what the edit root looks like, because that's kind of what we're interested in for this purpose. So this is how I've chosen to implement this. And I'm not saying this is the best way to do this, and there are, I think there's a nice concept of a buffered form that you can look into if you're interested in that. But the way I'm isolating this edit view from changing the canonical user record is just to pluck off. This is my clone. Let's get properties. I want to pluck off the name and email from that user object and present it as a new model for my root to work with. If I didn't do that, if I just gave it the user directly, so actually, I'll do that. So if you don't isolate your model, you end up sort of updating bits of the UI that you maybe didn't intend to. And again, this is like the surface example of this problem. Like that isn't a problem, but there might be if you extrapolate it out and imagine bits of UI changing stuff that you didn't intend them to, then there will come a point where you'll get bitten. So as I say, a way to isolate that is now, this root is working on an entirely new clone of the data. When I save it, it's just going to get that user model, get the model I'm currently working with, and then just punch down the properties I've set on this new one onto my old one, and that saves. And then it does update. But other weird stuff could happen here. So this new model that I've created, you could, like I say, set a basket property on that, and you'd end up setting it on the user and clobbering your own basket. And again, so with this example, to discard your changes, all you need to do is forget about this model up here. You can just let it get garbage collected. You don't need it anymore. So this was kind of the toy app I started working with to try and work ancient Oak into the mix. And let's see. This is kind of similar at the moment. I haven't quite got. So ideally, what I wanted to be able to do was just return this.getUser and trust that that is safe. And any updates that this would make, I'm guaranteed to get a new version of the user just inside of this root. And then I can choose to mutate that canonical user, sort of promote that version up to being the main version. But I haven't quite got there yet. But what you can see down here is a versions flag. So now if I go edit Joe Smith, and now I've got a second version. And I can roll back between my versions. And so what I wanted was for all these new versions that have been created of the user model, the user tree, to work in that way that my sort of boxes and sticks diagram demonstrated where you can just pop to a different one. And it's all still pointing to the same original data plus the new stuff that you've added on as the apps progressed. So what I ended up with, the user object that's injected into this app looks a bit like this. It's a new ancient oak. That's not the API for ancient oak. Ancient oak is just a capital I. And then you feed it some data. And then you work with what it returns. And it's all kind of encapsulated in a closure. I've made it sort of object oriented. And it's meant to behave like an ember object. So I feed it my starting data structure, my version one. And then I've tried, broadly, to implement the stuff you'd expect on ember objects on this. So let me just make that a bit bigger. So it's just an object that mixes in array and innumerable. And you see it's got this versions property, which gets set right here. You can see this is an ancient oak's API. So when you initialize this thing, it's going to either feed what you give it or just an empty object to ancient oak, which is going to produce this immutable data tree. And I'm just going to store that as my first version in my array. And then a bit like Ruby has method missing. Ember has unknown property and set unknown property. So I'm using that when you call get on an object in ember. And you haven't explicitly defined the property or a computer property. This will get a chance to do something. So what I'm saying is I'm going to look in current, which is just an alias for the top of the stack of versions. And again, this is ancient oak's API. When you want to get something from it, it's a function. So you just call it with the key. And it will give you back, if it's a primitive, it will give you a string or a number or whatever that primitive is. If it's another tree, it will give you another ancient oak object back. So what you see here is oak or primitive with whatever comes out of the tree for this. And oak or primitive says, if it's another ancient oak object, wrap it in another one of my kind of objectified ancient oak objects. Otherwise, just return the primitive as is. So that's how the getters get implemented. Ancient oak has this dump method, which just gives you a pojo back of your data tree for that particular version. Length is quite nice. Ancient oak's got this reduce function, which acts much as you'd expect. So you can't call length on an ancient oak object, but you can for each on it. And you can reduce it. So that's reducing all the keys it can see. Because of the nature of a raise in JavaScript, you can kind of think of them as a dictionary where the keys are integers. And so object at, you can see that kind of here. Object at is almost exactly like a guess, except instead of a key, you call the ancient oak closure with an index. And then the nicest part of the APIs is patch method here. So what happens is you have your ancient oak immutable data tree. You call patch on it with a kind of subset of a tree that you want applied to your original. And it will go through, kind of merge the two trees and give you a new version back. The original is unaffected. You get a new version back. I push this new version onto this version's array. And then sadly, and this is a part that I'd love to make neater, this bit's OK. So this goes through each key in this new diff for the patch and just calls a notify property change on it. So all the bindings for the rest of the app can update. And then rollback. Rollback's a bit of a shame. So my thought with rollback was, well, this is cool. I can just jump to any version in my version's array or can just pop versions off or pop the number I want to off. But to get bindings working, I need to know what keys change between each version. So what I resorted to just for this demo was to just say, before I popped it off, what were all the keys available at the top level of that tree? And after, and I've just put them in a set. So I've got this set of the unique keys that might have changed. Sadly, they probably won't have all changed. And then just notify all of them. So when you do a rollback, all of those observers will fire. And that's as far as I've got so far. So I'm going to keep pursuing this because I think these things are really interesting and potentially very, very useful. And if they can be made to talk Ember's language and give you access to Ember's normal tools in this kind of safe, efficient way, then that would be pretty cool. So that's all I've got. Any questions? It looks like you're cloning the ancient oak objects in your setting up versions. The wrapper, yeah. So I'm having to allocate a new ancient oak object. Ideally, I'd like to be able to, I'm not sure. So that's kind of for a subtree is the thing. It would be really nice not to have to do that. There's loads of compromises in this code. All right, I understand. So you're getting a key and it's a subtree. So what do you do with it? Maybe you could just sort of make the rest of your application aware of how to interact with ancient oak closures. But which is what? Maybe it's just the way the wrapper is. Yeah. It's going to be a little more thought through. Yeah, maybe just a way to make the wrapper allocate as little as humanly possible. Because that wrapper will then get its own versions, all right? It would be nicer if it was sort of aware that it was a subject of some parent tree object, like, as one root node. So Jamie, I know you fought in love quickly. And you were in love last time when you saw this. Are you still in love? Do you think it's a great idea? And do you also think it's a highly practical idea you expect to use? I'm still searching for the really good practical demo for it. I think the API for Schumann's library is really, really delightful. It's lovely. But I think I can't think of an app I'm working on right now where I'd need a persistent data structure in it somewhere. But I really want to find one. I think the idea is so cool that I'm willing to make trouble just to find a new excuse, Joe. I'm wondering if perhaps there is not a specific application in terms of app. But if we can rip out the entire Ember computed property logic and replace it with immutable objects, do you think that's possible? I'm not sure. I had a bit of a deep dive into Ember Messel to see how these things are implemented. And actually, there are hints of assistant data structures in there. They do. There are frozen objects get made in several different places, and I can't really explain it very well, just like I can't explain persistent data structures very well in terms of implementation. But I think, yeah, you could potentially create something which behaves much like bindings is the tricky part. I think maybe because ancient oak is such a closed system, if there were a way to hook into ancient oak a little bit more, then that might open up some possibilities. So something I might discuss with Shimon. I saw one good use case was a cave of chess where you preserved state for every move. That's awesome. Yeah. I was wondering, is there any disadvantages to having all those copies and models in memory near the onion mobile devices? Is that memory? Yeah, I'll just repeat. Then can you persist this type of data to the server neatly? So I'll just repeat the question for the sake of the recording. So the really good example is a game of chess and using a persistent data structure to capture each state of the board, which is a really good example, I wish I'd thought of that. And the question then was, should you be wary of allocating so many objects? And I think the answer is that a persistent data structure should help you with that. Because you're only going to allocate changes to the tree. And whatever you don't change, you're always referring to the same spot in memory. You're not making a copy of the whole tree. Yeah, you never make a complete clone of the tree. You just make a new tree with a new root node. And new branches out to your brand new values, but the old branches point to the old tree. So it shares as much memory as it possibly can in principle. And yeah. As you show, there's a pretty good model, a fact line. There's a data store, very much like the end of the data store with a lot more power than dirty objects and individual changes. And you can just do store it safe. What will you change back in the server? You can merge changes from the server. If you've been offline for a while, go back to your laptop, use your Wi-Fi. You can keep making changes offline. And then merge changes on the server, changes on the client. Because you've now got a record of your versions. You've still got a version of the process of data. I was wondering about your roadmap. You appear to be, every layer of your stack is the entire object. Obviously, with the nice supporters in the back end. But I wonder if, instead, you should make each layer a sparse set of just the ones you've changed. Just the diffs. So for a key, for the first one off, it's not there goes an x and goes an x until you find one. That's the latest version of that property. And I immediately said, well, to roll back, you just lose that layer at the stack. And it might make the patching quicker as well. Yeah. So I'll repeat some of it. There was some really good stuff in there. So what was the name of the library in C-sharp? Bold, originally. Bold. OK. It sounds a little bit like it. It sounds a little bit like Core Data, I guess, in Cocoa on that platform. So keeping a load of diffs in a stack, that sounds like Git, which sounds like a really good idea. So yeah, I totally agree. This was an excuse to use ancient oak one or anything else. And I do like it. And I think there are lots of places that could be applied. And it's lovely and lightweight. But yeah, keeping a stack of diffs is definitely another approach. And I'm sure it could be made to be very performant. The other option would say, do a patch. Could you tell me what you patch? Yes. Exactly. If you have query ancient oak for the date. Because it must know what's with patch. Yeah, patchable hasn't even happened. Yep. And rather than try and keep it as a layer on top of it, you know actually you can extend it, you know? Actually, I'll just put up the ancient oak side again. In fact, I'll tell you what, I'll bring up the repo just to give Shim on some credit. What credit is it to you? It's actually, I think it's best explained by its APIs. OK. I've got a view of all the content of the grid. And for what one of the credit is done, I've got a way of the screenshot. Yeah. Well, I actually need good content here. Does the oak is EPF? Do you have an EPF? Yeah, the Ember Persistence Frame. I wouldn't use that, but that does something similar. I don't know if it's a musical, but it does something similar of praising the versions. Yeah, it does, doesn't it? And then merging it back in. I haven't actually used it. Likewise. It definitely looks interesting. Great audience. I'm not sure if we'll be able to find. You're right. It definitely does work on that basis. I think perhaps storing diffs is the way it works. Again, like it. Any other questions? So the Gent app back was talking about storing data on a server, which assists the data for a greater period of time. Yep. Is there any way that you can export your states from H&O to the system on a server and then bring them back into the application at a later date? Yeah. So H&O has, along with Dump, it's got JSON. So turn your particular version of your tree into JSON and send it over the wire. It's what I'd imagine you'd want to do. But even over? You could persist every state. So perhaps every time you get a new version, you send the whole lot back or send a diff back. Or you just choose your moments and say, right, here's a moment I want to commit this version or this last few versions. But I think having those versions in memory, I don't think you'd ever want a bunch of complete clones in memory and persistent data structures like H&O to protect you from that and having diffs protect you from that. So yeah, and then if you've got them all there, you get to pick and choose as to what you send back. So normally, you press save. That's going to persist whatever event of back up to a server, you'll save that version. There, you're just persisting it on the client. At some point, you're going to have to sync it back up to the server. You use the JSON thing. I guess I've done this before. And then they're dumping it back in the day where you want to keep a history of everything that you've done over time and then allowing people to go back. So I wrote a medical app for a hospital where everything they've done, they want to be able to go back and see history of all note changes and be able to bring one back from the stack and bring it back. So this is the same similar idea that you do locally. You could take what you've got, persist the entire tree back up to the API, and then use agent oak on the server to then reconstitute that and then save all your versions down and then save the tree into your data store. The magic then is working out what the data store looks like. And then the end of your trick is normally, if you've got two clients and you've got to have some sort of locking system who wins on that change, of someone's adding notes, if you've got version, client over here, one, two, three, four, five, client over here, four, five, six, seven, eight, and then they say that your numbers are going to get. How do you answer them? My head hurts thinking about this. But if you've got a, if someone's working on their own data, for example, then on your fairly, you could use data time for the version numbers instead of using half that sort of accumulator number. Yeah, yeah. Yeah, so ancient oak on the server, it's, I mean, it's a fully node compatible library. So definitely. Anything else? Sorry, I missed the introduction to ancient oak in the previous. So I'm just curious, how does it actually enforce the new ability to get some sense of it? Yeah, so I'll, I'll, it's probably explained all pretty well here. So when you, you use I, you feed it your starting data tree and you just get a function back. So it's a closure. So all the data is contained within this function. You can't get at it. And what's more, this function is frozen as well. So you can't even add extra methods to it. And then you get, by calling the function with a key, you set by calling set on it. I think that's an example of that. Oh yeah, so if you, this is the example of if you're, if you're kind of burrowing down the tree, you can just throw keys at it like that, set pretty self-explanatory around your version. Yeah, you don't, you don't change the original version. You get a new tree, but that shares memory with the other version. And then, yeah, all these other nice methods that you've put in it. And I think under the hood, this is a, the implementation is a, is a binary tree type of a thing. I've put my slides away, but yeah, it's a, this is a clip of his slide. And it's kind of what it looks like under the hood. It's, it's very optimized. It is better examples. Shimon. Using, using ABCD doesn't help. The chess game, I think would, or a CMS, but the chess games are nicely, it's got rules. It's contained, like, yeah. OK, awesome. Thank you, Jim.