This week weâre talking with Nathan Sobo about his next big thing. Nathan is known for his work on the Atom editor while at GitHub. But his work wasnât finished when he left, soâŚhe started Zed, a high-performance multiplayer editor thatâs engineered for performance. And today, Nathan talks us through all the details.
Nathan Sobo: Yeah. So GPUI is an application framework, a UI framework that we basically created because at the time - what was it, like 2019⌠I think there were some experimental Rust graphics libraries out there, but none of them that we looked at really solved all the problems we knew we would need to solve, and just from a stylistic perspective if I canât pick up a thing that does the things I need it to do, then Iâd rather build it myself, so I really understand it, and I really have control of it, I can map it to my intuition.
So GPUI covers just the shell of the app, so interacting with the platform APIs to like pull up windows etc. We did that ourselves. And then once we have a window open, itâs just like a giant right now metal canvas that weâre going to render graphics into⌠But thereâs also just like âHow do you structure the views?â So itâs based on data flow, rather than control flow. So what does that mean? Well, Rustâs ownership rules are really strict, so we have this kind of global object that owns all the top-level views and models. And then the views and models can kind of interact with this global object via this standard protocol, where you know, say a user clicks - that models as an event, that calls an action on a particular view, and we call that into the view. And then the view can do whatever it wants. And when we call them into the view, we kind of yield the guts of the application to the view. And so if the view wants to emit an event, it says, âHey, Iâd like to emit an event.â And then Control Flow returns back up to the parent object, and then we move that data to any of the subscribers of that event.
So in a language where ownership is more promiscuous, like JavaScript, you might model an event as like âOh, on click Iâm going to attach this closure here. And inside the closure, Iâm going to implicitly capture this, which creates like a cyclic loop. And so when the click event happens, Iâm just gonna loop through all the event handlers and call them.â But in Rust, ownership is one way. That model, of like attaching a click handler that calls a method on you, and creates these cyclic data dependencies - that just doesnât work.
So thatâs a big part of GPUI, is sort of how do you structure the application logic, the models, the views etc. so that you can have these bi-directional interactions which are really common in UIs⌠Like, I open a modal; then the user clicks the X on the modal? Well, the thing that opened the modal needs to know about that, so it can hide the modal. That creates this bi-directional relationship.
So a big part of GPUI is just like a scheme for modeling bi-directional data relationships between these big views and models in the app. And then thereâs another big piece of it, which is, âOkay, once we have updated the state of a view, how do we represent that view on screen?â So thereâs this concept of a tree of elements, which is kind of inspired by React, but the difference is that in React you have the virtual DOM, and theyâre diffing it with the underlying DOM, and then that produces some mutations to this retained mode representation of the state of the UI, and then a bunch of other stuff etc. Like, thereâs this big chain that occurs⌠Where instead, anytime any view you updates its state, we basically rerender the entire window. So we build this tree of elements, and we do a pass from the top that lays everything down. And this is inspired by Flutter, which we found via the writings of [unintelligible 00:36:04.16] Levine.
[36:07] So yeah, we do this layout pass-down that says the constraints, how big or small anything can be, then everything passes, it sizes up. So thereâs one linear layout pass, and then one linear paint that populates this cross-platform scene representation. Then we go straight into GPU memory and draw it.
And so we bypass all this nonsense that occurs on the web. I mean, this model of the web vastly predates the availability of GPUs, and introduces a lot of complexity thatâs not relevant to the problem we face, of like keystroke to pixels. I get a keystroke, I want pixels on the screen on the next frame. And so yeah, GPUI is the system that we built, that kind of aligned with our intuitions, and everything weâve learned about doing UI⌠And Iâm sure thereâs many ways to do it, but this oneâs ours, and itâs worked pretty well for us.