Why is it so difficult to create a user interface in Rust?

What makes Rust unique?

Why is the UI in Rust so difficult?

Functional UI to the rescue

If you've read Hacker News lately, it's hard not to think that Rust is the future: it's used in the Linux kernel and Android operating system, by AWS for critical infrastructure, as well as in ChromeOS and Firefox. However, as wonderful as Rust is, it has yet to take off as a general language for UI design. In 2019, "GUI" was the 6th most requested feature that was preventing Rust adoption. This is basically a limitation of Rust: the design of the language itself makes it difficult to model common approaches to building a user interface.

We at Warp have created a custom UI framework1 in Rust that we use for rendering on the GPU. Building this framework was very tricky and a big investment, but it served us well in building a terminal with rich UI elements and as fast as any other terminal on the planet. This level of performance would have been next to impossible had we used a UI library like Electron or Flutter.

In this article, I'll explain why Rust's unique memory management model and lack of inheritance make traditional techniques for creating a UI framework difficult and some of the ways we we worked around that. I believe that one of these approaches, or a combination of them, will eventually lead to a stable cross-platform UI toolkit for high-performance UI rendering that anyone can use.

What makes Rust unique?

Rust handles memory management through a concept called "property" which is applied at compile time. This differs from other languages ​​that offer automatic memory management through the use of a garbage collector to remove unused objects at runtime.

Rust ownership works by applying the following rules:

Values ​​belong to variables Values ​​can be referenced by other variables (with some caveats mentioned below) When owning variables go out of scope, the memory occupied by the value is deallocated

fn main() { let mut original_owner = format!("Hello world"); // the move occurs to the new owner let new_owner = original_owner; // trying to use original_owner will // leads to compile time error println !("{}", original_owner) } error[E0382]: borrowing moved value: `original_owner`

Taking the example above, the Rust compiler enforces that there is only one owner of a given value at any given time. Rust prevents us from assigning new_owner to the value of original_owner, because there would be two owners of the value at the same time.

Rust also protects against compile-time data races with rules about when a value can be mutable and immutable referenced. At the same time, these rules enforce that there are no data races caused by two threads updating the same value at the same time:

At any time, you can have either one mutable reference or any number of immutable references. References should always be valid. The value cannot be mutated as long as there are valid references.

Why is it so difficult to create a user interface in Rust?

What makes Rust unique?

Why is the UI in Rust so difficult?

Functional UI to the rescue

If you've read Hacker News lately, it's hard not to think that Rust is the future: it's used in the Linux kernel and Android operating system, by AWS for critical infrastructure, as well as in ChromeOS and Firefox. However, as wonderful as Rust is, it has yet to take off as a general language for UI design. In 2019, "GUI" was the 6th most requested feature that was preventing Rust adoption. This is basically a limitation of Rust: the design of the language itself makes it difficult to model common approaches to building a user interface.

We at Warp have created a custom UI framework1 in Rust that we use for rendering on the GPU. Building this framework was very tricky and a big investment, but it served us well in building a terminal with rich UI elements and as fast as any other terminal on the planet. This level of performance would have been next to impossible had we used a UI library like Electron or Flutter.

In this article, I'll explain why Rust's unique memory management model and lack of inheritance make traditional techniques for creating a UI framework difficult and some of the ways we we worked around that. I believe that one of these approaches, or a combination of them, will eventually lead to a stable cross-platform UI toolkit for high-performance UI rendering that anyone can use.

What makes Rust unique?

Rust handles memory management through a concept called "property" which is applied at compile time. This differs from other languages ​​that offer automatic memory management through the use of a garbage collector to remove unused objects at runtime.

Rust ownership works by applying the following rules:

Values ​​belong to variables Values ​​can be referenced by other variables (with some caveats mentioned below) When owning variables go out of scope, the memory occupied by the value is deallocated

fn main() { let mut original_owner = format!("Hello world"); // the move occurs to the new owner let new_owner = original_owner; // trying to use original_owner will // leads to compile time error println !("{}", original_owner) } error[E0382]: borrowing moved value: `original_owner`

Taking the example above, the Rust compiler enforces that there is only one owner of a given value at any given time. Rust prevents us from assigning new_owner to the value of original_owner, because there would be two owners of the value at the same time.

Rust also protects against compile-time data races with rules about when a value can be mutable and immutable referenced. At the same time, these rules enforce that there are no data races caused by two threads updating the same value at the same time:

At any time, you can have either one mutable reference or any number of immutable references. References should always be valid. The value cannot be mutated as long as there are valid references.

What's Your Reaction?

like

dislike

love

funny

angry

sad

wow