Console #167 -- Interview with Héctor of Iced - A cross-platform GUI library for Rust
Featuring DocuSeal, OneUptime, and Iced
🤝 Sponsor
This space is reserved for sponsors that support us to keep the newsletter going! Want to support Console? Send us a note at osh@codesee.io
🏗️ Projects
Browse through open source projects on OpenSourceHub.io, add your project to get more exposure and connect with other maintainers and contributors!
DocuSeal
DocuSeal is an open source platform that provides secure and efficient digital document signing and processing. Create PDF forms to have them filled and signed online on any device with an easy-to-use, mobile-optimized web tool.
language: Ruby stars: 1712 last commit: today
repo: github.com/docusealco/docuseal
site: docuseal.co
OneUptime
OneUptime is a self-hosted, open-source complete observability platform. It monitors your website, dashboards, API's, and more and alerts your team when downtime happens.
language: TypeScript stars: 1115 last commit: today
repo: github.com/oneuptime/oneuptime
site: oneuptime.com
Iced
Iced is a cross-platform GUI library for Rust focused on simplicity and type-safety. Inspired by Elm.
language: Rust stars: 19990 last commit: 2 days
repo: github.com/iced-rs/iced
site: iced.rs
Join thousands of other open-source enthusiasts and developers in the Open Source Hub Discord server to continue the discussion on the projects in this week's email!
🎙️ Interview With Héctor of Iced - A cross-platform GUI library for Rust
Hey Héctor! Thanks for joining us! Let us start with your background.
I was born and raised near Barcelona, Spain.
My dad introduced me to computers when I was three years old and I have been fascinated by them since then. When I was ten, I learned PHP because I wanted to have my own website to talk about video games.
I focused on web development until I started studying computer science in university. There, I was exposed to other popular languages. I was eager to learn and share my projects, so I started open-sourcing stuff: a Zelda clone in C++, a Ruby/Python-inspired scripting language in Java, a command-line tool to benchmark programs in Python, an EventStoreDB driver for Ruby Object Mapper, and more!
After university I kept working on web development for the most part. I founded a couple of start-ups with some classmates and learned a whole lot. It was around this time that I discovered Elm, which ended up being a huge influence.
The start-ups I was involved with eventually failed and I ended up quite burned out of web development. I needed something different and decided to make my own video game. This idea eventually led me to learning Rust, developing my own game library, and releasing Iced, a cross-platform GUI toolkit inspired by Elm.
Who or what are your biggest influences as a developer?
Functional programming and, more specifically, the Elm programming language and its ecosystem focused on simplicity.
When I was in university, I got a glimpse of niche programming paradigms. I learned a bit of Haskell and Prolog, but it wasn’t until a couple of years later that everything clicked and I had what I call my “turning point” as a developer.
My team and I were in the middle of a huge refactor of a Javascript codebase using Angular. An extremely painful one. You know how it goes. Change one thing over here, break something over there; and no easy way to tell! Out of frustration, I googled something along the lines of “Javascript without runtime exceptions” and… There it was! Elm.
Fast-forward one week and I had rewritten the whole codebase in Elm. Up until this point I mainly coded in object-oriented languages, so the functional paradigm was quite a challenge. It was tough, but so much fun! We were already applying some functional ideas in our backend like immutability and event-sourcing, but having a great type system and a compiler enforcing and tying everything up together felt cathartic.
Elm forced me to unlearn a bunch of harmful habits and mistakes I acquired while I was still a beginner: thinking in terms of objects and encapsulating state, relying on design patterns and silver bullets, and over-abstracting code. It all eventually clicked in my head one day. Quite literally! I clearly remember the moment I felt it just click in there!
After that, I used Elm heavily for a couple of years and open-sourced a couple of cool packages in the process: an HTML5 parser and a library to build type-safe, composable forms.
What's an opinion you have that most people don't agree with?
I have too many of these! But if I had to pick one, I’d say I have a higher-than-usual tolerance for code duplication and boilerplate.
In my experience, over-abstraction is one of the most painful mistakes you can make when writing code. Code duplication can be incidental and abstracting boilerplate, especially, is often a recipe for disaster.Abstractions are very important. I like to think of them as words that make up the vocabulary in a codebase. When they are accurate and describe the problem you are solving closely, they help you immensely to reason about the problem and to design solutions for further use cases. When they are inaccurate, however, they can completely steer you in the wrong direction. If you are not careful, the wrong idea starts snowballing and everything becomes confusing.
For this reason, abstractions should arise naturally. And for that to happen, the pattern needs to be extremely clear. This can only occur if you let your code grow organically; and that often entails redundancy.
I have a saying that goes, “boring code is not boilerplate”. I believe a healthy codebase is always supposed to have a bunch of “plumbing code”. This is code that consists mostly of function calling, data passing, and result handling at different abstraction levels. It’s quite repetitive and boring, but it’s extremely important!
Explicit plumbing code keeps your whole codebase flexible and easy to change. Trying to abstract plumbing code is like trying to replace the whole plumbing system in a building with a complex, magical mechanism that somehow moves a single pipe inside the walls just because using multiple pipes seems redundant. Bonkers!
And yet, there are many frameworks and design patterns that exist for the sole purpose of abstracting plumbing code.
Why was Iced started?
After being focused on web development for most of my life, I ended up feeling burned out. I needed a change of pace and decided to make my own PC game.
But after trying Elm, I simply couldn’t go back to any of the usual contenders for the job, like C++ or C. I was so spoiled by a great type-system that going back to these tools felt like returning to the stone age.
This is where Rust came to mind. I heard something about it back when it reached 1.0 and it seemed interesting. Awesome type system, controlled mutability, no objects, great compiler, and performant… It was the perfect fit!
However, the gamedev ecosystem in Rust was quite in its infancy. I wasn’t fully happy with the libraries available and I got extremely side-tracked! Two months into my Rust journey I open-sourced my own 2D game library and, shortly after, I introduced graphical user interface support for it. A bunch of people in the Rust community asked me to release this feature as a standalone library and that's how Iced was born!
How does Iced work?
Iced is a cross-platform GUI library with batteries included. This means you can go from nothing to a graphical application with only Iced as a dependency.
In the end, an application can be seen as a window (or many) that displays some kind of interactive content. The graphical, interactive bits of an application are called widgets.
The widgets of an application produce some graphical primitives that eventually need to be drawn on screen. Renderers take care of this task, potentially leveraging GPU acceleration. Currently, Iced has two renderers:
iced_wgpu – powered by wgpu and supporting Vulkan, DirectX 12, Metal, and WebGPU.
iced_tiny_skia – powered by tiny-skia, which should work everywhere since it is a fully software renderer implementation.
The widgets of a graphical user interface are interactive. Shells gather and process user interactions in an event loop. Normally, a shell will be responsible for creating a window and managing the lifecycle of an application.
Currently, Iced has a single shell built on top of winit, which supports Windows, Linux, macOS, the Web, and more.
Besides renderers and shells, Iced comes with a bunch of built-in widgets. These vary a lot in complexity; from a simple button to a rearrangeable grid of panes. Users of the library can also build their own, thanks to a public widget API.
On top of all of this, Iced exposes a simple interface to manage both the state and presentation of an application leveraging The Elm Architecture.
The documentation mentions that Iced is inspired by Elm. How does Iced incorporate the principles of Elm Architecture into its design and development?
Iced forces users to split their applications into the same essential parts as the parts found in The Elm Architecture.
Basically, users have control over
their application state,
the logic to display this state as widgets (interactive content),
the events that these widgets produce when a user interacts with them,
and the logic used to react to these events and update the application state.
If you look at these parts closely, you can see that there is a feedback loop. The state is displayed as widgets, these produce events when interacted with, then the state is updated as a result, which in turn means it needs to be redisplayed… and so on! This is the essence of The Elm Architecture.
Iced also tries to incorporate other ideas from Elm, like managed side effects. As you may know, Elm is a purely functional language and, as a result, functions cannot have side effects. For instance, it’s impossible to directly perform an HTTP request in Elm.
In order to perform side effects, you need to create a command representing the action you wish to perform and then hand it to the Elm runtime, which will carry it for you and produce an event as a result. This works very well because these commands can run in the background without blocking the user interface of the application.
Even though Rust isn’t a purely functional language, it has a very similar concept to managed side effects: the Future API, and Iced builds the idea of a command on top of it.
Where did the name for Iced come from?
It comes from iced coffee! My favorite drink while I code in the summer. I called my first Rust crate Coffee because I had some right next to me at the time. The name Iced followed from that.
Who, or what, was the biggest inspiration for Iced?
Definitely Elm and its community!
I look up to Evan Czaplicki, the author of Elm. He is very passionate about simplicity and has a mindset of long-term success with a strong vision. He is not afraid of taking hard decisions even if that means short-term turmoil and harsh criticism. I feel this approach is quite refreshing and necessary, especially in the current Web ecosystem.
There are some genuinely amazing Elm talks that still inspire me to this day. To name a few:
The Hard Parts of Open Source by Evan Czaplicki
The Life of a File by Evan Czaplicki
Making Impossible States Impossible by Richard Feldman
Building a Toolkit for Design by Matthew Griffith
Are there any overarching goals of Iced that drive design or implementation? If so, what trade-offs have been made as a consequence of these goals?
Iced is mainly focused on desktop platforms. That means we only officially support Windows, macOS, and Linux.
This helps us keep a narrow scope, reduces the burden of maintenance, and allows us to focus on building APIs that leverage the full potential of desktop computers.
The main trade-off here is the lack of mobile support, which is a very requested feature. But we cannot satisfy every use case out there!
What are the key features of Iced that differentiate it from other GUI libraries in Rust? What were the existing ones lacking that made you consider building something new?
The main difference is definitely the Elm inspiration. If you enjoy working with Elm, you will feel right at home with Iced.
Iced also tries to stay away from any kind of “magic”. There are no complex macros or convoluted DSLs. Code should be beautifully boring and straightforward!
Iced applications are very easy to understand as a result. If you are familiar with Rust, that’s all you need.
Could you explain how Iced achieves cross-platform compatibility?
Our dependencies are cross-platform and export unified APIs. Both the windowing shell and renderers support all the major desktop platforms. Iced stands on the shoulders of giants!
Could you share any success stories or real-world use cases where Iced has been implemented effectively?
Proudly! We have a project showcase both on the repository and the Discord server.
Some notable mentions:
Cryptowatch Desktop, a blazingly-fast crypto trading terminal.
Ajour, a World of Warcraft addon manager.
Halloy, an open-source IRC client.
Sniffnet, an application to comfortably monitor your Internet traffic.
Airshipper, the official Veloren launcher.
How do you balance your work on open-source with your day job and other responsibilities?
I am fortunate enough to not need to strike a balance. Open-source is my day job! I work on Iced full-time thanks to a sponsorship by the Cryptowatch team at Kraken.
If you plan to continue developing Iced, where do you see the project heading next?
We have a roadmap, so ideally in that direction!
We recently got rid of a bunch of limitations related to text handling and rendering. We should now be ready to tackle more complex text use cases like multi-line text edition, right-to-left support, and rich text widgets.
Overall, we are mainly headed towards maturity. Other short-term goals include accessibility support, multi-window applications, and widgets that can leverage their own graphical primitives with custom shader code.
Do you have any suggestions for someone trying to make their first contribution to an open-source project?
Use the project first. Get inspired. Find something you can help with. Then, get in touch with the people involved in the project. Communicate and build trust! Explain your background, what you want to do and, most importantly… Listen! Listen very carefully. The authors know much more about the project than you do. Be humble! They will tell you how you can help.
Most of the time, the advice you will receive won’t be what you expected. Sometimes your idea may be dismissed, or turn into a different thing completely, or it may just not be the right time for it. Lots of iteration may be necessary.
Code should happen as the last step of the contribution process, once there is already an agreement and both parties are on the same page. Code is the end result. The tip of the iceberg. Focus on everything else first!
Want to join the conversation about one of the projects featured this week? Drop a comment, or see what others are saying!
Interested in sponsoring the newsletter or know of any cool projects or interesting developers you want us to interview? Reach out at osh@codesee.io or mention us @ConsoleWeekly!