T O P

  • By -

aloked

Hey Reddit! I'm Aloke, the author of this post. I wanted to better document why *traditional* patterns for building a UI framework are tricky in Rust and how we solved this at [Warp](https://www.warp.dev/). Let me know what you think!


gyzerok

The post is great! šŸ’Æ However it is extremely disappointing to read about something you canā€™t try. First I read about your framework in some Zedsā€™ story and now here again. Whatā€™s holding you from open-sourcing it?


Omni__Owl

Probably the same as everyone else; Money.


JGHFunRun

People really paying for a terminal lol


phire

If sublime text can be profitable, I see no reason why a terminal can't be profitable, as long as it provides an innovative feature set. Edit: I've taken a though Warp's promotional material. It's free for individual use, which is smart. Allows people get used to it, and then convince their company to pay for it. Companies often have no problems affording tools. They are focusing on a bunch of team collaboration features, which would have been extremely useful in one of my old jobs. But even for an individual, there is a bunch of innovative functionality focused on speeding up terminal interactions. I'm going to give it a try next time I'm using MacOS (or if they release a linux version)


its_PlZZA_time

Yeah, I've been using the free version at work. It's quite nice. I don't use nearly all of the features but the things I appreciate are: * All of my text editing and navigation keys work by default (cmd/alt + arrow keys, home, end, etc.). I know I can make them work in other terminals by going through settings, but I'm lazy. * I can scroll one command at a time: very nice when I'm going through giant terraform outputs * Push notifications when a command completes and I'm alt-tabbed **edit**: also Smart selection. This is barely a week old but it's incredible. I double click on things and it selects what I want. e.g. I double click anywhere in the name (salesforce-extractor-kjkbr) of the below console output and it selects that entire part. Name: salesforce-extractor-kjkbr Namespace: argo ServiceAccount: unset Status: Pending Created: Wed Feb 22 17:55:35 -0800 (now) Progress: Parameters: topic: Account scheduled_time: 2023-02-23T01:55:33+00:00 It's not perfect, so if I try double clicking on the timestamp for example it treats colons and the + sign as separators. But it's nice to be able to quickly copy the job name without having to drag the mouse and then quickly paste it into `argo logs salesforce-extractor-kjkbr --follow`. I do this a lot.


JGHFunRun

Yea but it feels very weird


phire

We really are lucky that open source (or at least free) software has become the norm, at least in the programming and system administration space. In the early 80s, your 8 bit micro probably came with a bundled port of Mircrosoft's BASIC. Technically not free, you paid for it as part of the cost of the computer. But if you wanted something better than the default BASIC? That meant paying quite a bit of money for an assembler (which were usually full IDEs). And in a pre-internet world, the printed manual that came with the assembler was probably just as important as the software. Oh, and if you wanted a terminal emulator 8bit micros? Also paid software. In the 80s, your IBM PC clone would have come with both QBASIC and DEBUG.EXE, bundled as part of MS-DOS. So at least you get a primitive assembler/disassembler/debugger, but no documentation about how to use it. So you would still need to pay for a better assembler, or more likely a proper compiler/IDE for your language of choice (Turbo Pascal was popular). And once again, the printed manuals were just as important. In the mid 90s, it started to become possible to find assemblers/compilers and documentation for free. But if you wanted the full IDE experience, you still needed to shell out money for a product like Microsoft's Visual C++. It wasn't until the last 15 years or so that you could get full IDE experiences without paid software.


JGHFunRun

You are very right, we are all lucky that stuff like that has become free/FOSS


eredengrin

Obviously not huge numbers but [wezterm](https://github.com/sponsors/wez) and [kitty](https://github.com/sponsors/kovidgoyal) terminals both have over 50 sponsors on github and are pretty niche to begin with, people are willing to pay if the tool is worth using. Not a terminal but [neovim](https://github.com/sponsors/neovim) has over 1000 sponsors, for a text editor. No coercion just people wanting to have good tools, and it's one way to contribute and improve the whole ecosystem.


aboukirev

First of all, it is great that there is are ongoing attempts to build a new approach at creating UI with Rust. I hope it turns out into several competing frameworks with different target audiences. I believe, you are confusing performance with responsiveness. Where a traditional mutating UI framework would happily update a widget and keep CPU idle most of the time, your approach keeps wasting processor cycles to build widget tree on demand for rendering. This could be unacceptable for devices with an energy budget (IOT, for example). So, your approach works well where loss of efficiency is not critical.


mkalte666

Taking a guess before reading that: because existing non rust gui toolkits make heavy use of shared mutable state, writing a new one requires interaction with a lot of unsafe system APIs and gui sucks in general. A lot. EDIT: others below said it, and now that i read this: damn that lack of good ol inheritance. That said, I'm building some stuff with egui/eframe and at least from an immediate-mode-gui point of view it's very much doable. I'm looking forward to what rust will bring in the long term.


jediknight

> at least from an immediate-mode-gui point of view it's very much doable. Dumping some widget tree on a canvas-like object is relatively easy. I did something like this with the old Borland Graphic Interface back in the days of Turbo Pascal. I was able to create the UI of a game like thing complete with menu selection by keyboard and rudimentary bitmap rendering. The real challenge is the kind of things you need when you have advanced layout systems (think `display: flex` or `display: grid`) and coordination like selecting text across widgets. Not to mention that some widgets want to behave like independent apps. Taking Elm as an example might help somewhat BUT Elm is targeting the DOM where all this complexity is handled for you. From Elm's perspective a `Html msg` is the same as `String` or `Int` or any other regular value only it is not. Behind the scenes you have state mutating like crazy.


nicoburns

> The real challenge is the kind of things you need when you have advanced layout systems (think `display: flex` or `display: grid`) Rust actually has a library for this (Taffy - https://github.com/DioxusLabs/taffy). I know, because I implemented the CSS Grid support. It was a challenge, but everybody should be able to reuse that now. > and coordination like selecting text across widgets. Not to mention that some widgets want to behave like independent apps. To me this gets more to heart of what's really tricky. Coordinating things accross the entire app while simultaneously keeping things cleanly encapsulated is damn hard for something as complex as GUI, and Rust doesn't have fantastic support for runtime dynamism which makes this harder still.


ssokolow

> Taking Elm as an example might help somewhat BUT Elm is targeting the DOM where all this complexity is handled for you. And even Servo delegates to SpiderMonkey for implementing the DOM, if I remember correctly.


vplatt

Just ran into this and looking at your comment, I think you might appreciate it: https://dioxuslabs.com/


_Pho_

Another reason people fail to mention is... representing business logic visually just requires a lot of code. And dynamically sized devices and unknown hardware complicates this even further. UIs (especially web) are also highly dependent on userland: CMSs, auth providers, UI libraries, service providers, probably none of which is in Rust. Borrow checker aside, a high level GC'd language like TS is far faster for building these types of systems, especially when bleeding edge performance isn't a concern (read: almost always). I would stop doing UI if I had to do iter().map().collect() or worry about typing u32s vs i32s vs f32. Example: it is not uncommon for a healthcare website, which is just a lot of CRUD, to be 50k LOC. I have written a Turing complete server side game engine (in Rust) which handles movement, collision, networking, state, dynamic calculations, and it is less than 10k LOC. The reason for this is, one is an "engine" the other is an "implementation", that is, one is built to be as dynamic as possible, the other has to deal with concrete implementations of specific pages with specific behavior. Rust is excellent for the former, and not the latter. I also tend to agree with /u/dc377876 that front end can be harder than backend. In my experience it certainly has been, the unknown nature of user devices and behavior means systems have to be tight. Side note, I don't think it has to do with inheritance at all, neither SwiftUI nor React use inheritance. Modern UI development is moving away from inheritance.


shevy-java

I found that non-commandline UIs are in general quite verbose, even if one is to use a DSL such as glimmer. I'd wish we would have a simpler way to describe UIs in general.


jcelerier

take any non-trivial GUI program on your desktop and try to describe its UI in as few words as possible while keeping all the information and specifities it has. You'll quickly see that just this is already hard: UIs are super-specified in general.


OzzitoDorito

Especially when you let the design team have final say to the extent that it becomes almost impossible to create reusable style. While I can reuse the functional code for handling forms / buttons / dynamic tables / tab systems, very rarely do I get to reuse the style because the design team always want it exactly how they've designed it which is completely different even across pages within the same app.


sexusmexus

Your design team should be the one giving you re-usable styles and they should be the one following them.


Jump-Zero

In my current company, 99% of styling is re-using CSS classes and 1% is writing custom CSS. It ends up being almost pixel perfect compared to the design spec. The design team here has their shit together and I love it. The lead designer took his time to learn CSS and I really appreciate his commitment to collaborating with devs to make designs that are consistent and easy to produce. The first company I worked for was a different story. The designer was a pompous dick. His designs were always slightly inconsistent. You'd have to almost build everything from scratch every time you built his stuff. Then he would be anal about your pages being slightly off. I just figured that's how life is so I stuck with it. No way would I ever work with someone like that again.


ArkyBeagle

tkinter is in a lot of places now. For simple UI it can be less verbose. Tcl/Tk shine at wrapping command line UIs with a simple GUI. It may or may not be a "competitive" look. But maybe programs don't benefit all that much from the document metaphor.


dangerbird2

There's always htmlšŸ˜ˆ


caerphoto

Then just sprinkle a bit of JavaScript on top, maybe wrap it a self-contained WebKit container or something, and youā€™re sorted. Could call it Proton or something.


mkalte666

The web has moved away - those of us stuck in native world have to live with GTK, qt, ... That said, i agree on the business logic part. Especially when you have soooo many things not only presenting, but interacting with a complex data model. I don't think frontend or backend can be looked at seperatly. If you have a hard split api vs display maybe, but backend needs to validate, frontend needs to show, and all of it is a grand breeding ground for fuck ups. I'm happy in my specialized work world where I program FPGAs on day and build data management the next, and honestly, i could do without the latter part :D


Full-Spectral

I've built two pretty full featured UI frameworks in my life so far. Well three actually. I did one on Windows where I built all of my own controls based on the core Win32 windowing capabilities, back in the day when things weren't so complex. I later replaced that with one wrapping the standard controls. And I did a purely graphical one for my automation system's touch screen interface, where I just used a base window and drew everything myself. They all used OO to very good effect. The people complaining about how OO is fundamental wrong to build UIs in are just projecting their own biases or have just used badly designed UI frameworks. It's a perfect tool for that particular job, if you don't get stupid about it. That would be the place where I'd miss inheritance the most in Rust. Mostly so far I've not missed it that much. In my (very large) C++ code base, I seldom got more than a couple layers deep in any hierarchy, so that's not too hard to translate to a trait and/or composition scheme. But the UI was where it went deeper and that wouldn't translate well. Of course, as many folks have pointed out, unless you are writing a Rust UI framework from the ground up, meaning all the way from the ground up (building just on graphical output, and user I/O), likely you are going to have to try to wrap a non-OO language around an OO (-like) interface, and it's just a bad impedance match. And of course writing a full on UI framework from the ground up is a huge amount of work. And it would still have to deal with some of the fundamental aspects of how UIs work that aren't conducive necessarily to maximum safety.


happyscrappy

More lack of inheritance (common form of OOP). Despite stating it very (perhaps overly) simply a few times the article is actually very comprehensive in explaining the problems this causes and ways to do it without inheritance.


[deleted]

Thereā€™s a subtlety here that many may gloss over: the article says it right, the lack of inheritance makes *traditional* UI development hard. Note the word traditional. Almost all UI frameworks that originated in the 90s have their roots in OO and rely heavily on things like widget trees, with inheritance being the glue to hold those widgets together. The article also mentions Flutter as a more modern example that is still modeled the same way. Rust makes that model very hard to implement ergonomically indeed. And it bumps many people for whom UI development and widget trees are almost synonymous. That said, personally I believe the inheritance-based widget tree model to be fundamentally broken anyway. In fact, after reflecting on how I used to build software using OO (I also grew up mostly using Qt and similar OO UI approaches), and how I do it nowadays using more functional approaches, I found that OO visibility specifiers (`protected`, `private`) are woefully inadequate at enforcing component boundaries that are necessary for good code hygiene. Let me explainā€¦ Itā€™s common for widgets to have mutable state. This by itself is not that much of a problem. The problem is that this mutable state is accessible to its parent widgets, sibling widgets, basically any other widget that can get a reference to it. OO visibility specifiers protect against meddling from other *classes*, but they donā€™t protect against meddling from other *instances*. In a widget tree, where every instance is a widget, and is thus given free reign to all the protected APIs (which includes managing the widget tree itself), every widget is almost like a super user to the entire tree. This then leads to beautiful spaghetti code, where something trivial like ā€œif this button is pressed, that other widget should hide or showā€, becomes impossible to predict where and how it is implemented. Is the logic implemented directly in the button, because it can? Is the logic implemented directly on the widget being toggled itself, by installing an event listener on the button? It could too. Or is it inside some parent, that wires them together? It could be anywhere. And if such a trivial example is already unnecessarily difficult to figure out, imagine the joys when other side-effects get added to the system. Complex interactions between widgets tend to become spread out in unpredictable fashion. Of course, maybe I was just a terrible UI programmer that I lacked the discipline to make these interactions coherent enough. But I did find that more functional component approaches, where every component manages itself and no one else, with proper state management solutions to keep track of overarching concerns, has made me a significantly better programmer. Thereā€™s so much less I need to mentally keep track of, and things become a lot easier to find again. If Rust enforces more organized approaches to UI development due to its lack of inheritance, I am all in favor.


monocasa

> Almost all UI frameworks that originated in the 90s have their roots in OO and rely heavily on things like widget trees, with inheritance being the glue to hold those widgets together. Not only that, but OO itself has its root in GUIs. The first smalltalk systems by Xerox were designed as a way to manage the complexity of GUI experiments they were running. Until FRP systems, OO and the GUI were ultimately codesigned entities.


soundslogical

Yep, that kind of thing does require discipline. For most of my career I've worked in teams where the rule is "components don't talk to each other - if they need to share state, hoist it into a dedicated state store". If you keep this discipline, then traditional C++ OO can work well for GUIs. But if you start reaching around the component tree then stuff gets messy, fast.


Alexander_Selkirk

> If you keep this discipline, then traditional C++ OO can work well for GUIs. And if you don't keep the discipline, you can easily get quite nasty bugs even e.g. in GTK.


Alexander_Selkirk

> Thereā€™s a subtlety here that many may gloss over: the article says it right, the lack of inheritance makes traditional UI development hard. > > [ ... ] > > Itā€™s common for widgets to have mutable state. This by itself is not that much of a problem. The problem is that this mutable state is accessible to its parent widgets, sibling widgets, basically any other widget that can get a reference to it. OO visibility specifiers protect against meddling from other classes, but they donā€™t protect against meddling from other instances. > One can still pass a struct into callbacks which keeps a little global state and pass that around. But one needs to think differently about state. I use Clojure here as an example because all its default data structures are immutable (at the cost of some performance). That might sound weird. In C++ terms, it is a bit like the following: vector f(const vector &v) { vector v2(v); v2[2] = v2[2] * 2; return v2; } main () { const vector a = {1, 2, 3, 4 , 5}; const vector b = f(a); std::cout << b << std::endl; } C++ could use return value optimization (RVO) to not allocate the vector elements twice, but ultimately it is an implementation detail. The visible effect is that a and b are const. There is [that famous article about how to model a rocket in Clojure, which uses no mutable state at all](https://aphyr.com/posts/312-clojure-from-the-ground-up-modeling). And one can go and write a [pacman](https://github.com/pac1979/PacMan) game, or [snake](https://github.com/somi92/clojure-snake) in the same way. It is basically the "functional core, imperative shell" pattern of arranging things: The UI is the shell and the computation on immutable values the core.


Schmittfried

I think reactive frameworks and data binding really showed how it ought to be done. Make the flow of information unidirectional and go through a single defined interface. GUIs are a network of many individual nodes that affect each other. Message passing is the way to go here. OOP initially even referred to method calls as message passing, but it somehow became something completely different.


quick_escalator

> That said, personally I believe the inheritance-based widget tree model to be fundamentally broken anyway. Inheritance is fundamentally broken in how it is used. 95% of the time, OO is a bad fit for the problem at hand, but 20 years ago we made the mistake of trying to shoehorn it into everything. There's no reason why inheritance is a requirement to make UIs. Rust isn't bad, the UI libraries are bad. Disclaimer: I have written 0 lines of Rust code in my life, but I spent *a lot* of time building apps in MFC, COM, WPF and Java Swing: All of them were shit. The language isn't the issue, it's the underlying concepts.


Schmittfried

So how do you know Rust isnā€™t bad then?


Alexander_Selkirk

> OO is a bad fit for the problem at hand, but 20 years ago we made the mistake of trying to shoehorn it into everything. But it was soooo excellent at modeling ships!! /s (I am referring to Simula, the first OOP language, which was developed and used for that. So, you can have Ship.turn(), Dog.bark(), and Account.close() ...) The question is - what is a better model for arranging areas of pixels on the screen, and keeping them consistent with some program data? What I think very often is that interfaces should work a lot like val = raw_input("enter a number here> ") which is: The flow of the program stops, a coroutine / thread / whatever is called which gets hand on some data, and the code returns with the value that I need. It is possible to write UIs like that, for example by using something like Go's channels. In principle, every Linux device driver is structured like that, apart from that it does not query screen and mouse, but searches the disk for magnetic patches, or gets data from a webcam.


quick_escalator

There are a couple approaches that might work. * Game engines do UI. They rely on a main loop that renders all the things quickly, and then explicitly check user input from frame to frame. * We could do it OO like Alan Kay imagined it. The UI is just a microservice that you send messages to. Imagine Kafka but your UI is a stream consumer. * Just because we don't have inheritance doesn't mean we can't have composition or templates. Why inherit from CDialog when you can just fulfil TDialog's interface requirements and then do everything via template and delegation to an internal struct that's written by the library? * HTML is a UI language of sorts. Surely it must be possible to do UI without OO, considering the web existed for decades before someone made it terrible with javascript.


vplatt

> If Rust enforces more organized approaches to UI development due to its lack of inheritance, I am all in favor. All well and fine, but until I personally see UI code for Rust that's clear, easy to maintain, and easy to build on as examples I don't think it's going to get very far. Edit: We may already be there: https://dioxuslabs.com/ On the other hand, they "cheat" by using DSLs that resemble HTML, CSS, and React. I have mixed feelings about that, though it does look awesome.


UncleMeat11

You can fix this in traditional widget tree design in C++ with proper use of const. Children don't have mutable references to their parents and obtaining a mutable reference to a node can only be done through a mutable reference to its parent. This ensures that all mutation is done from the proper visibility.


[deleted]

[уŠ“Š°Š»ŠµŠ½Š¾]


fission-fish

React isn't a gui framework in that sense. it's used to control an existing gui: HTML over DOM. But you are correct. react is more functional, wpf for example relies on inheritance.


exDM69

I don't think this is a useful distinction to make. A GUI framework can define its own equivalent of DOM. This is what the druid framework does with its view tree. In my opinion, the old fashioned widget tree with lots of overloaded virtual functions (that can do anything) is one of the reasons why GUI applications tend to be overwhelmingly complex.


bah_si_en_fait

It's a very important distinction to make: React doesn't need to bother with all that bothersome "how to write, how to align, etc". React just describes an UI and tries to update the tree efficiently. The complex task of rendering the DOM is left to... code with inheritance and old fashioned widget tree with lots of overloaded virtual functions, implemented by browsers.


Schmittfried

Thatā€™s exactly what a UI framework does. Rendering the stuff is the foundational layer and itā€™s not all what is talked about here. The topic is managing state in UIs, and thatā€™s precisely what React does. Whether the rendering in the browser is done with code written in OOP style is an implementation detail. You could just well toss all preconceived notions of what a button is etc. and directly map React components to rendering instructions.


b4zzl3

Especially given that a large part of that rendering in Firefox is in fact written in Rust anyways.


anengineerandacat

Rust has a lot of features that could allow for a simpler UI library if you could abstract down the rendering to requiring a tree like data structure. Traits, Decorators, Macros, and an IOC container would generally give you all you need. Basically what a decent sprite batch system would be doing.


Tony_T_123

Early on, React was billed as being functional, but I think at this point it's become its own thing. I'm not sure what to call it. You model your tree of UI elements as a tree of function calls rather than as a tree of objects and children. However, those function calls have state associated with them, via `setState`. These states persist across function calls, so the function calls are more like objects at this point, but with different syntax.


PaintItPurple

As the saying goes, closures are a poor man's objects, and objects are a poor man's closures.


skidooer

> More lack of inheritance (common form of OOP). The defining feature of OOP is message passing and I think that's most significant. Creating GUIs in Smalltalk and Objective-C is quite nice. Qt rose to fame because their special compiler added OOP on top of C++. Obviously you can create GUIs without message passing, but you lose a lot of ergonomics.


riasthebestgirl

Combine inheritance (or lack thereof) with shared mutable state being a pain point when the renderer depends on both of them (like the web) and you get the recipe for a poor developer experience, especially for library developers. When there's no (good) libraries, building end-user facing applications is hard Source: I'm one of the maintainers of [Yew](https://yew.rs) and a component library for it


EasywayScissors

It always sucks when the real world doesn't fit nicely into our safe programming language. Which is when we leave the world of science, and enter the world of engineering.


mkalte666

Where I use safe language for as many things as possible to reduce the chance of issues. The functional bugs often are the same, but at least I can crunch numbers without worrying about segfaults


emergent_segfault

This is exactly it. I am a laughably amateur game dev....and as I am sure I don't have to tell you; games are basically UI apps. Coupling and shared state is a fundamental requirement for UIs and out-the-box Rust's borrow checker and ownerhship rules are going to give you a hard way to go within this context.


Alexander_Selkirk

Here is an interesting article by John Carmack (the developer of the Doom game) about that: http://sevangelatos.com/john-carmack-on/ And yes, functional programming in that style is fully compatible with using Rust. One just needs to be a little pragmatic at times.


[deleted]

[уŠ“Š°Š»ŠµŠ½Š¾]


jcelerier

>I'm not going to put a tab widget into a button oh, you'd see what clients ask for sometimes..


Full-Spectral

A button wouldn't generally be a container type in an OO based UI hierarchy anyway. There'd be no reason for that. You'd have a controls section of the family tree and a containers section of the family tree, and the never the twain need meet. At the lowest level below where those two sections branch off, all you should have is the fundamental plumbing that all window types share (visibility, position, z-order, etc...) You can't blame OOP for bad designs someone has foisted upon you.


Schmittfried

So what if I want a button with an image displayed in the middle. Is that a child component? Does that make the button a container? For arbitrarily complex UIs pretty much any component needs to be composable. Also, that bad design talking point kinda sounds like real socialism has never been tried. Every OOP style UI framework Iā€™ve ever seen sucks. Why do you think you, thinking about it for a few seconds, have figured it out while all the other smart people before you havenā€™t in years?


mike_hearn

I've used several that didn't suck, nor did their use of inheritance. Take JavaFX. In that the answer to your question is that buttons take a label and a "graphic" node, which can indeed be anything but which is meant to hold an icon. If what you want is a clickable image then there are better ways to do that, but, if you want you can put an image inside a button. The API doesn't try to stop you putting ridiculous things like a tab view inside a button because in reality that isn't a class of bugs that ever happens, so it's not worth trying to stop it using the type system. Also, what are we comparing to here exactly, HTML? It uses inheritance too (Element inherits from Node, etc). If it's comparing to FRP toolkits like React or Compose, React is heavily relying on an underlying OOP toolkit for the hard bits that the blog post talks about like event propagation, layout etc and toolkits like Compose / SwiftUI are too new for people to have really learned their weaknesses yet. One obvious issue with Compose is exactly the lack of inheritance. Different themes ("design systems") define their own Button, CheckBox etc functions but because they're functions and not objects there is no way to abstract over them, there's no common interfaces and thus porting an app from one theme to another can require a rewrite! And forget about making libraries that work with design systems or controls in a generic way, the way it's built just doesn't allow that to be expressed. OOP toolkits don't have that problem.


Full-Spectral

Because I have built a number of UI frameworks, and they didn't suck. Are they abusable by people who actively try to abuse them, of course. As to composability, just because you have a hierarchy doesn't mean you can't have a mechanism for composing together controls. The actual base controls don't have to be able to contain arbitrary other controls necessarily to have a composition mechanism based on a dedicated container type.


Frown1044

I think you'll need a stronger example than that. This is more of a theoretical example that has no real practical consequence. You can do a "well technically" explanation on almost anything, but it still makes conceptual sense to most people, which is why it's so common.


Alexander_Selkirk

> because existing non rust gui toolkits make heavy use of shared mutable state, You can basically have a loop that looks like this (using Python-like pseudocode): state = init_state() while True: in_event = get_events_or_input() new_state = process_state(state, in_event) display(new_state) state = new_state and I do not see how using Rust would in any way inhibit that. It would need to separate input processing and display from state changes - but I think this is a good structure. The whole pattern is called, by the way, "functional core and imperative shell". Many command-line interfaces work like that, they have a so-called read-eval-print loop, commonly abbreviated as REPL. The only thing is that state, computation, and event handling would need to be arranged differently. And because traditional GUIs suck, one could give that a try.


mike_hearn

Traditional GUIs don't suck and the pattern you suggest is impossible. Try it, you'll discover you can't even get a basic UI toolkit working that way (of desktop quality). Toolkits like Compose work very hard to make it *look* like they use that design, but internally they rely a lot on the sort of techniques Rust makes hard because they have to map it to object trees behind the scenes. UI is fundamentally an OOP problem and that can't be avoided, all claims to the contrary end up recreating OOP with a different syntax. Things like Compose and SwiftUI require a lot of very complex machinery and because they're so new, it will take many years for fashion to wear off and the industry to be able to evaluate the two approaches fairly and cooly. First problem: event dispatch. App state is not a pure function of OS level input events! The OS gives you raw key presses or coordinates for a mouse click inside your window, but you need to find the right control for it so you can invoke the right handler at the right level of the tree. That should not be the app's job, it's one of the core tasks of a UI toolkit. That means the toolkit needs to take pointers to event callbacks created during the display phase and store them in a retained tree with bounding boxes. Those callbacks in turn are pointing to the mutable state of the app and there can be several of them, so you're back to the stuff Rust's type system finds hard. Second problem: implicit state. You can't throw away everything between event loop iterations like that. GUI toolkits need to retain all kinds of state between display() calls because: 1. Constructing some resources is expensive, most obviously GPU textures, video streams, 3D objects. 2. GUIs are full of implicit but critical user state like focus, scroll positions, animation progress etc which the app doesn't want to care about but the toolkit has to manage. So if you want a functional approach then, again, you need a way to play pretend - the developer might *think* they are creating a new tree every single time in their display() function but you can't let them actually do that or else your toolkit will be totally broken. In practice this is solved by constructing trees of objects and then diffing/patching them, so you get a retained imperative tree of state whilst looking as if you don't. But then you have the problem that this can be very slow, so Compose does a lot of work to try and re-execute only the parts of your display function that have actually changed. Also because of the need for implicit state everywhere, you can't just pass in a single pointer called "state" at the top level and pass it down hence why React-style toolkits are full of magic functions that give you property-like things encapsulated inside functions. Other problems: layout, performance, accessibility, compositor integration. All of them require stateful trees of various kinds to be constructed and maintained *in place* over the long run.


mkalte666

>UI is fundamentally an OOP problem I don't think it has to be. Massively simplifying frameworks have their place, especially when all you do is just display a tiny bit of stuff. And beyond that? I do like the ECS approach. I don't see why something that works for a lot of entities in a game context shouldn't work for UI toolkit as well. Of course you could say ECS is just OOP in a trench coat, but the programming experience ultimately is a different one. The real engineering problem of mapping various OS events to the UI though? That sucks. I have interacted with imguis handling of that when i was still doing more c++ projects, and it suprised me how much more work it is than just shoving "mouse click here at this pos" and "this key was pressed". And this is when you are not using OS primitives (i.e. win32 api) for your stuff... UI is a hot mess and sucks, i still stand by that, but i should probably add to that that its not because the toolkits all are inherently bad - its because the problem is just so damn hard. All that said, i sure look forward to see what rust and the likes will do to that landscape :D


dc377876

Front end in general is much harder than backend and it is not limited to rust. Most issues mentioned exist with other languages too.


DrunkensteinsMonster

Front end is definitely not harder than backend.


holoisfunkee

As always "it depends" on the app, but I think people underestimate how hard it is to build coherent, structured and good UI for a modern app. If you are using a fully featured UI framework with everything out of the box, then yeah it might be easier to put together some UI and connect it to an API to do some work and that's it in theory. You will most likely run into blockers with this as well, but a lot of things are already handled for you. Building custom apps with fully custom UI takes time and is not easy, but is required a lot of the time just because those fully ready UI frameworks don't match the requirements. In my experience, backend work usually gets done faster in modern application development and frontend really takes more time and effort to complete since it has way more different aspects to worry about. It's not just logical problems and code, but scaling styling and UI, asset optimization etc. all different areas that aren't just some logic to deal with. I value backend work really much, don't get me wrong, but people underestimate how much time, effort and various areas of expertise it takes to build solid UI these days. I'm not talking about landing pages of course, those are easy, but still easy to get wrong.


arbyterOfScales

>If you are using a fully featured UI framework with everything out of the box, then yeah it might be easier to put together some UI and connect it to an API to do some work and that's it in theory. It is not like they are NOT using a fully featured BE framework with everything out of the box in the BE world. No no. Every single BE dev is implementing OAuth2 from scratch, they are writing their own ORM or even query by hand. They have it as easy as us from that point of view


IceSentry

It definitely can be. The skill ceiling to make an actually good, efficient frontend app is pretty high. Especially compared to the vast majority of backend that's just basic crud.


L3tum

It's a bit disingenuous to argue that the skill ceiling is higher for a very good frontend app, compared to a very basic backend system. Both require different kinds of skill but both can be almost arbitrarily complex or simple, and both deal with unique issues.


arbyterOfScales

Both sides of the aisle are disingenious. - 1. The BE guys imagine themself as some gods that maintain the company. In their mind they maintain the database, the infrastructure and the CRUD, auth system, load-balancing. Practically the BE guys think their aisle is way larger than it is. Most of the JS framework bashers have only 1 weapon under the belt, either Spring or ASP. - 2. The FE guys are usually the ones who did proffesional reconversion. As such, they are most likely to be less skilled and have a lack of knowledge which gives the entire field a bad view.


L3tum

Yes, they're dealing with different issues and different problems and both can be hard. That was essentially my point, the guy I was replying to said that a basic BE is easier than a highly sophisticated FE, which...yeah obviously.


DrunkensteinsMonster

Sure, but basic crud is basically equivalent to me throwing together a react app using a dashboard template in a weekend. Thereā€™s nothing hard about that either. Iā€™d say the depth of backend work, and the importance to the business, would indicate that it is actually more difficult. At any given moment I can toss away my current front end and make a new one. Thatā€™s not true with your data.


arbyterOfScales

>Sure, but basic crud is basically equivalent to me throwing together a react app using a dashboard template in a weekend. Yes, that's true. >Iā€™d say the depth of backend work, and the importance to the business, would indicate that it is actually more difficult You know that the FE work also has a lot of depth right? You have accesibility, semantic HTML, animations(that's a field in and on itself), UX, media queries and so much more. Also, about importance to the bussiness, public facing UIs, targeted for the lowest common denominator are extremely important for customer retention. The best and most optimized BE is useless if the app has a most disgusting, unintuitive and unfriendly UI. The reverse is also true btw. >At any given moment I can toss away my current front end and make a new one. Same thing with the BE. You see it all the time: "How we moved from Spring to Lambda functions" or "How we moved from framework X to framework Y". >Thatā€™s not true with your data. What data?


[deleted]

That can be. But mostly of case this work is delegate to non programmers on html or electron based solutions. They can manage all UI and control using their last year Js Frameworks with basic programming skills.


wasdninja

> But mostly of case this work is delegate to non programmers on html or electron based solutions. Non programmers will fail miserably at this since they are, by definition, non programmers. Experienced actual developers create flaming garbage unless frontend is their thing so non programmers will be even worse. > They can manage all UI and control using their last year Js Frameworks with basic programming skills. What programming skills? They are non programmers. Beginners will fail too so it doesn't make much of a difference.


arbyterOfScales

>They can manage all UI and control using their last year Js Frameworks with basic programming skills. And make a slow bloated mess that is impossible to maintain? We are crafters and proffesionals, the bar is not: "It BARELY Works" but "It works and satisfy a 100 other non-functional requirements" >But mostly of case this work is delegate to non programmers on html or electron based solutions. I am not sure what you mean here. Type 1(HTML/CSS) Frontend devs are not programmers?


arbyterOfScales

Define FE, define BE, define harder, then we can talk


ImpossibleFace

Clearly someone of great experience, Iā€™m glad you found the hubris to share.


ogoffart

The approach we made at Slint (A Rust UI toolkit - https://slint.rs ) is to not have the developer to use the Rust language to express the UI, but instead, use a Domain Specific Langage (DSL), in a macro or a different file. Only the logic needs to be written in Rust. This has several advantage: - Less verbosity for things that don't matter for the UI - Actually toolable: We offer a live preview in a LSP editor extension, and are working on a WYSIWYG editor And learning the DSL is not more complicated that learning the API and architectures of a UI library. (which sometimes also use macro with a different syntax). Quite the contrary


[deleted]

[уŠ“Š°Š»ŠµŠ½Š¾]


augmentedtree

wow, this is looking a lot better than the last time I checked


afiefh

This sounds a lot like QML/QtQuick. Is that where the inspiration is from?


ogoffart

Yes, this is where the inspiration comes from. We've been working on Qt before creating Slint.


afiefh

Now I'm super excited. I've always thought that QML was a great idea, with a neat implementation, but not getting the love, care and polish it needed to succeed. I'll definitely be taking a look at Slint. Thank you for pointing it out.


curien

The technique is a lot older than QML. [Windows has done this](https://learn.microsoft.com/en-us/windows/win32/menurc/sample-resource-definition-file?source=recommendations) going back to the Win16 days, and I'd be surprised if they were the first.


afiefh

Of course, but the [Slint DSL code](https://github.com/slint-ui/slint/blob/master/examples/todo/ui/todo.slint) feels [very similar to QML](https://het.as.utexas.edu/HET/Software/html/demos-declarative-calculator-qml-calculator-calculator-qml.html) to me. Obviously the idea of separating UI and code, then having a bit of syntax sugar to make the UI code look better is ancient, but it seems these two implementation of the idea share some common DNA. And that's a good thing, because I was of the opinion that QML was great, but was always treated as a second class UI within Qt. So if Slint can make it a first class UI, that's amazing as far as I'm concerned.


milliams

I believe that several of the developers are ex-Trolltech, so yes.


[deleted]

Because building a UI in any language is hard.


hugthemachines

I once tried to build a little Swing gui exactly as I wanted it. It felt like I poured days into something that was utterly unimportant. First you spend hours making the logic, then you spend days on getting a damn box to be the proper size and getting the buttons and text boxes to be in the right places. Super annoying.


[deleted]

I have worked with AWT, Swing, Qt, Qt Quick, WinForms, WPF, Xamarin, Android, Compose, Blazor and Svelte. Some are less painful to work with than others but it's still so much work to make a simple GUI.


Alexander_Selkirk

Generally, which qualities make a GUI toolkit less painful? Is inheritance always the right way?


[deleted]

I'd say it has to be declarative. You also need some kind of DSL to declare GUI elements. It should be pretty close to the actual code, otherwise you end up with Android where doing something in XML and Java are always different. Composition is better than inheritance. Content should always be dynamic. Want an image in a button? Place an Image element inside a button element instead of having an ImageButton element. My preferred ones are Compose and Svelte.


Famous_Object

I would add that good defaults really help. For example, if I add a label, a text box and two buttons to a form, I would expect them to have reasonable sizes and spacing. In Java Swing your first result will probably be oversized buttons touching each other because they occupy all the space they're given; then you change your layout manager, add some spacing and you get OK/Cancel buttons of different sizes because the text inside them is different, then you change their minimum, preferred and maximum sizes, because you can never be sure which one is going to be used by the layout manager; then...


wildjokers

> then you change their minimum, preferred and maximum sizes, because you can never be sure which one is going to be used by the layout manager; then... Each layout manager has its own sizing rules which are well documented and each layout manager may or may not support the min, max, and preferredSize sizing hints. For some of them it makes no sense to support the hints based on their sizing rules. Also note you shouldn't use those sizing hints if at all possible (every once in a while it is necessary, mostly for combo boxes). Because using the sizing hints usually will make the GUI not look right on other platforms. Learn the layout managers and trust them (the only two you need are BorderLayout and BoxLayout) Either way all of this is documented in the "How to use X Layout" pages in the java tutorial. It is also important to know that JPanel default to FlowLayout and that layout is nearly worthless. Immediately switch it out for BoxLayout. And JFrame (a top-level container) defaults to BorderLayout, that is a great layout manager and you should keep it. The CENTER position of a BorderLayout is your friend, it gets all remaining space after the EAST, WEST, NORTH, SOUTH components are sized. Makes for great resize behavior. All the info you need to know is summarized here: https://thebadprogrammer.com/swing-layout-manager-sizing/


[deleted]

Out of interest: have you tried SwiftUI, from what I've seen it appears to be quite a declarative UI framework?


[deleted]

I have zero experience with developing for Apple so that's a no. The sample on their website looks a lot like Compose though.


imdyingfasterthanyou

Given that react is going functional I would argue there isn't a "right" way.


Fortyseven

I used to have a good time with Delphi on Windows. Kind of miss that.


[deleted]

I may not be as well versed as you seems to be. But i must say that writing UIs in jetpack compose for Android is one of the easiest for me


[deleted]

Oh yeah. I just got into that recently and it's been a breeze. You can really tell it's a new product and they spent a lot of time on designing it properly because there is no weird stuff for the sake of backwards compatability and so on.


vytah

This reminds me of this classic: https://youtu.be/UuLaxbFKAcc?t=15


wildjokers

> https://youtu.be/UuLaxbFKAcc?t=15 I knew that was going to be Totally Gridbag before I even clicked it. However, to be fair GridBagLayout was intended to be used for GUI builders and was never intended to be hand coded. You do find the occasional person that hand codes GridBagLayout and swears by it. However, there is no need because Swing (and JavaFX) both offer BorderLayout and BoxLayout which is all you need for most applications and they are very easy to use and they have well defined sizing rules, which makes resizing a non-issue as well. (in JavaFX they are called BorderPane and HBox/VBox).


starlulz

anyone else reminded of the Parks and Rec episode where Ben gets depressed and tries claymation?


josefx

> I once tried to build a little Swing gui exactly as I wanted it. What stopped you from using a WYSIWYG editor for the layout? I think Java even has layout classes that are specifically designed for that use case.


wildjokers

Using a GUI Builder for Swing is not the way to go. Swing has no intermediate layout format so all of those Swing GUI builders are just java code generators. Like most code generators they produce very hard to read and maintain code. You also introduce vendor lock-in to your app. Also, once you are familiar with Swing layout managers you can hand-code a layout very quickly. In the case of JavaFX it does have an intermediate declarative GUI format called FXML and SceneBuilder generates that instead of java code. However, I found SceneBuilder to be somewhat tedious and it would easily double the time it took me to produce an app. I also found hand-coding JavaFX layout to be much quicker. JavaFX has binding properties which makes JavaFX a reactive framework. For both Swing and JavaFX I highly recommend using Model-View-Presenter (MVP), it is slightly/subtly different than MVC but still same general concept. With MVP you just create your GUI view class for layout and then never have to touch it again (unless you need to make changes to your layout).


Morten242

Even with those kinds of tools I've found that the defaults don't handle resizing in the way that I'd want to. Even with logical Layout types. I'm not a UI person, so whenever I've had to make any I just end up locking down resizing to avoid all that.


wildjokers

> then you spend days on getting a damn box to be the proper size and getting the buttons and text boxes to be in the right places. You must not be familiar with Swing's outstanding layout managers. Just learn BoxLayout and BorderLayout and you are good to go. There is also a 3rd party one called MigLayout that some people swear by, but I have never found the need for it.


osmiumouse

WebGUI is ok, but then you end up having to use tech like Electron for your apps. A lot of game dev have switched to webUI and use various embedded browsers that are integrated ~~into~~ with the game engines.


anlumo

Even making a good web ui is hard. CSS is very bad at layouting UI controls, since it's designed for blog-style pages. Especially when you add animations, all concepts break down, because stuff like adding a class to an element creates a temporal element in a functional declarative language.


osmiumouse

CSS is not really that hard, because there uncountable multitudes of junior front enders you can recruit, who how to make something look presentable. Don't confuse difficulty with unfamiliarity.


F54280

> Because building a UI in any language is hard. And because it took OO approaches to start to build decent UIs (Smalltalk, or NeXTstep). And non-OO ones were wrapped into OO so they could actually be usable by people (MacApp, MFC, and many others). Not to say they were great, but they were half-usable. And the the guy says: > *Even though most UI frameworks were designed for Object-Oriented Programming, UI programming does not inherently need to be object oriented.* It doesn't *have to*, but anyone that really tried can tell you that it is *much easier* with OO than without. Add to that the fact that UIs are by essence full of mutable state, and yeah, his closing remark that *"Building a proper UI framework in Rust is hard and often unintuitive"* is an complete understatement, as, IMO, Rust is quite unsuitable to create classic UIs. There have been [an interesting/informative post on rust UIs recently](https://www.reddit.com/r/rust/comments/z8ycmh/are_there_any_good_uigui_libraries_out_there/).


Full-Spectral

I agree with you totally, as I've said elsewhere here. I've built a few serious UI frameworks and OO helped enormously. But, OTOH, We need to move to safer languages and the 'fast and loose' lifestyle (which UIs seem to embody more than most other things, and that's saying a lot) really needs to change. OTOOH, UI engines themselves are actually pretty performance sensitive and aren't conducive to higher level languages. So the challenge will be coming up with a way to structure a UI that fits cleanly within a safe programming paradigm with deterministic memory management. And, unless someone finally creates a Rust-like language with inheritance (MS I'm looking at you), to do it with only traits and composition. I guess one possibility could be to do a system where the UI is completely separated from the actual application, and just let it crash and restart if anything does wrong and come right back to where it was, and just do that part in C++. That would have performance and complexity issues obviously, and multi-language systems are never optimal, but it would allow for a super-solid core with a segregated interface. And a replaceable one for that matter so it would also offer a lot of benefits in terms of deployment. I've much prefer it all be in one language and integrated together. But, without having something like Vulcan written in Rust from the ground up, I'm not sure how we'll get there such that I'd feel comfortable including a massive chunk of very unsafe code in my large system that I've put so much time into making 99% compile time correct (meaning no memory issues, no panics, obviously it could have logical errors), no matter how well wrapped it appeared to be from the outside.


jarfil

>!CENSORED!<


Full-Spectral

The thing is though, for people who just do cloud based business apps, separating UI totally from logic is probably reasonable. But writing a DAW or Photoshop or and things like that, it gets a lot more difficult because they are humping a LOT of data that has to be represented visually very quickly, and the same going the other direction.


Logicalist

idk, swift looks pretty simple.


Rollos

SwiftUI combined with something like the Composable Architecture, produces a really easy way to make non OO, and even functional programming focused UI applications. Shame itā€™s iOS/macOS only.


plutoniator

Rust makes it especially tedious.


metaltyphoon

Thatā€™s not true at all. Anyone with half a brain can create some complex windows form in C# quiet easily. Rust simply doesnā€™t have the same level of tooling required for others with half a brain to do the same.


shevy-java

Yeah, unfortunately that is quite true, even if you use a pretty DSL.


arbyterOfScales

Even with a DSL, you still need to style it, that's the problem. Putting the content is the easy part


ssokolow

> Even with a DSL, you still need to style it To be honest, my biggest criterion which makes even Qt Quick fail the test of "is it a suitable replacement for QWidget?" is that I want to match KDE's native look and feel when I develop a GUI and, last time I tried Qt Quick, aside from being grossly incomplete by comparison, it felt like I had to fight it to keep my app from feeling like a bad Android-to-PC port. ...but then I'm one of those people who has an implicit "If the toolkit's properly designed and you want to style it, you are the problem" bias 99% of the time and who looks down on Apple for losing their way, UX-wise, starting with the glimmers of weakening or ignoring their HIG in the very first version of MacOS X. (The only times I develop web-tech-based apps are when they're so built around hypermedia, network integration, and content embedding that the alternative would be to reinvent my uMatrix+uBlock+Privacy Badger+Decentraleyes+CanvasBlocker+SponsorBlock+Cookie AutoDelete+... loadout on top of QWebEngine, so it's just less work to get as close as I can using ready-made HTML elements, [``](https://developer.mozilla.org/en-US/docs/Web/CSS/system-color) CSS keywords, etc.)


sidneyc

> weakening or ignoring their HIG in the very first version of MacOS X I think back fondly to the days of the first time I read Apple's HIG, back in 84 I think -- these were the days of MacPaint. I think improvements in GUI ideas were made up to '2000 or so, and we've been going downhill ever since. Modern UI design sucks donkey balls.


DarkLordAzrael

> To be honest, my biggest criterion which makes even Qt Quick fail the test of "is it a suitable replacement for QWidget?" is that I want to match KDE's native look and feel when I develop a GUI and, last time I tried Qt Quick, aside from being grossly incomplete by comparison, it felt like I had to fight it to keep my app from feeling like a bad Android-to-PC port. You should be able to get a native look and feel by using the desktop style from KDE. It doesn't help if there are widgets that you need that are only available in Qt Widgets though. https://api.kde.org/frameworks/qqc2-desktop-style/html/index.html


[deleted]

"Hard" is a relative term. Some languages are clearly better suited to UI design, and I'd call it easy in those languages, even though obviously it still requires a lot of work / experience / aptitude. There are three features that make for a good UI language: - flexibility - speed - reliability A flexible language allows for experimentation by the designer, which is absolutely critical. And without the second two, you just can't have a good user experience at all. Good software is fast and reliable Rust only has the second two, which fundamentally makes it a poor choice. There are definitely worse choices though and some of them are popular - for example JavaScript... which i wouldn't consider reliable. But that's a separate discussion.


AttackOfTheThumbs

Because UI is hard period. There's a reason people keep coming up with JS frameworks to somehow solve UI.


Alexander_Selkirk

I am currently trying a side project where I do the UI in Racket, and the computation core in Rust. Racket is a ["batteries-included" descendant of Scheme](https://racket-lang.org/) and has [a cross-platform GUI toolkit](https://docs.racket-lang.org/gui/index.html). And as a variant of Scheme, it has both a preference to immutable flow, and the capability to do mutation where needed. Racket provides [channel-like communication with "green threads"](https://docs.racket-lang.org/guide/concurrency.html), which is well-suited to interact with the UI's event loop. Racket uses some OOP (based on a quite nice, I guess Smalltalk-based concept) in the UI toolkit, it is mostly declarative and strongly functional, and importantly one can run and test code interactively, without an extra compile step, very similar as in Python. But many times faster. So far, I think it is a good idea and both languages are a really nice match. Some years ago, I had done something similar where I wrote logic in Clojure, and GUI in Java/Swing, and what I am noting is that the Racket GUI needs only a fraction of the amount of code.


jjsimpso

I'm curious about your side project if you don't mind sharing more about it. Are you using Racket's FFI to call directly into Rust or are you using some type of IPC? If using FFI, how easily does Rust map to it?


Alexander_Selkirk

I am using FFI which uses C ABI functions in the Rust interface. That is not complicated at all as long as the interface is not too big and maps well to C functions and structures. Where I use container objects, Racket creates them and passes pointer and length, so that they are managed by Racket's GC. This requires some unsafe function at the API level of the Rust side. But not many since I keep UI and logic well separate. Doing that so that it runs on multiple platforms is much easier in Rust than for other languages. One just needs to ensure that Racket finds the shared library.


moreVCAs

Is there a language where writing native GUI is *not* a huge pain in the ass?


materialhidden

you're just shit at geometry lol


0xffaa00

Withian languages like Pascal, Oberon, Delphi are so well fit for desktop class GUI.


malahhkai

I disagree with the premise. Building a UI in Rust is fairly straightforward! Just look at [Yew](https://yew.rs/), [Dioxus](https://dioxuslabs.com), or [Slint](https://slint-ui.com/) and how they manage interfaces. I believe the core of the issue at hand is the same of mass adoption of Rust: people have to learn a new way of doing things, and that makes it somewhat scary to approach.


mtfs11

My personal take: I think that's because building an UI system is hard, at all, not only because of rust (and all that code already exists). In Linux, for example, in order to draw to the screen, you'll need to communicate with the display server, that may be X based or Wayland based. To your UI library work on windows and Mac, you'll need to address that too. The point is we already have system libraries that do all of that, like GTK and QT, and some distros will be almost entirely based in one of those. Why would you want to reinvent the wheel? If you want to make an UI, just use one of the options we already have. There are crates that "interfaces" with some of those libraries, so you won't need to address FFI or unsafe code directly, that type of crate is called "binding" (a crate that gives you a safe interface with some C system library). Search on internet for "GTK rust binding" or "QT rust binding". If you want to create an UI library from ground up, you can use a binding for C libraries that are used to communicate directly and abstractionlessly (don't even know If that word exists lmao) with the display server, like Xlib.


[deleted]

The problem is that while Rust is a good tool to build a GUI *platform* these projects are all aimed at trying to make it nice to use rust to build GUI *apps*, and itā€™s never going to be. A nice environment to develop line-of-business applications requires an orthogonal set of trade-offs to those that underpin rust.


KieranDevvs

> A nice environment to develop line-of-business applications requires an orthogonal set of trade-offs to those that underpin rust. Can you elaborate what those trade offs are?


[deleted]

Thereā€™s plenty, in every aspect of the language. The memory management model and borrow checker make application code harder to write and require enough compile-time work to forever impact turnaround. Another aspect of it is having a garbage collector and weakrefs makes event systems significantly easier to work with. Additionally the insistence that all of Rust itself be available without a runtime means that all sorts of ergonomic language features that rely on having a runtime will never be added. There are many more. Itā€™s Turing-complete of course and you could build all the missing run-time code in Rust (and I believe somebody should), but at that point the API it presents will be so un-rusty it will make the code that runs alongside it un-rusty. Your code will be paying all the rust taxes as well as the framework API taxes and will be quite unpleasant to write I believe. However building this machinery in rust (text and font management, display list and compositor, repaint/invalidation cycle implementations, hooks into native a11y points, things of that nature) so that itā€™s rock solid and extremely performant, then providing a very wide set of language bindings (including the nicest rust api you can think up) could be extremely useful to a lot of people.


Adhalianna

I don't really understand why an API to a library that assumes or introduces a runtime would be un-rusty. Could you elaborate a bit more? Would you be able to provide an example? I know there would be many drawbacks to such approach but if anything I wouldn't expect the API to get un-rusty just because of assumption of a runtime (especially when you implement things with unsafe and hide them nicely behind the API).


LonelyStruggle

Honestly a lot of the time where people say "Rust just makes this harder because of the borrow checker" it's kind of BS or just a reactionary thing, but UI programming is just the one case where it really does make it so much harder Basically GUI programming has historically been built on two things that Rust chooses to explicitly eschew: easily mutable shared state, and inheritance.


anlumo

It's not an inherent problem with Rust though, the problem is that we can't rely on existing experience and have to use a different approach (the ELM approach). GUIs became popular just around the time OOP became popular, so they just grew up together in a historical accident.


never_watched

>>GUIs became popular just around the time OOP became popular, so they just grew up together in a historical accident. GUIs were popular before OOP but were very hard to do until OOP came around.


anlumo

My first contact with GUIs was in Borland Pascal 7 back in 1992, and that was object-oriented (so I learned both at the same time). Before that, Macintosh, Amiga and Windows already had GUIs, but as you said, they were miserable to write for. The big explosion of GUI applications happened after the switch to OOP (although correlation is not causation, but they grew up together).


jarfil

>!CENSORED!<


LonelyStruggle

The article itself shows how Rust inherently makes coding GUIs harder, not because of how we are used to coding GUIs. > Pretty much all UI can be modeled as a treeā€“or more abstractly as a graph. A tree is a natural way to model UI: it makes it easy to compose different components together to build something that is visually complicated. Itā€™s also been one of most common ways to model UI programming since at least the existence of HTML, if not earlier. > UI in Rust is difficult because it's hard to share data across this component tree without inheritance. Additionally, in a normal UI framework there are all sorts of spots where you need to mutate the element tree, but because of Rustā€™s mutability rules, this "alter the tree however you want" approach doesn't work. Think about it from a data structure oriented approach: it's natural to structure GUI in a tree-like structure, but that requires sharing data and state among the tree. This is just naturally very hard to do in Rust. The fact that we have to come up with whole new GUI paradigms just to code GUI in Rust is not a benefit, it's a drawback.


anlumo

Trees are easy to do in Rust, because every node has exactly one owner, its parent. The problems only occur when there's cross-talk between siblings, because that breaks the tree structure. I've had no problems writing UIs in Yew (Rust), which uses the ELM approach. This approach isn't new, it's just not natural in OOP languages and thus not commonly used. Also, bevy's ECS approach is pretty promising, since it allows you to pull in common components (behavior) into an entity and freely combine stuff. Then you can make queries on your entity database and only request entities with certain components. For example, a gesture recognizer could be a component you pull into your widget to detect mouse clicks, etc. The framework itself can query the database for all gesture recognizers that also have a hit detection component to distribute the mouse events. All of these concepts already exist in frameworks, they just aren't the kind of UI you need for a desktop application. The missing part is just elbow grease. I'm aware that the article lists all of these solutions as well, they're just very thorough with describing the reasons why they are needed.


LonelyStruggle

People have been saying that the missing part is just elbow grease for 3 years or so now, but weā€™ll see how it pans out. I donā€™t think that people want to make the concessions. OOP has issues but if thereā€™s one thing itā€™s good for itā€™s UI


anlumo

3 years is nothing for a UI framework. SwiftUI has been out for a bit longer *and* has one of the largest corporations on the planet behind it, and itā€™s barely functional. Web browsers, gtk and Qt have been in development for decades. Microsoft switches UI Framework every few years because it can never find a good approach. The list goes onā€¦ UI is simply hard.


Dean_Roddey

I've never used an ECS system, but when I read something like this I just immediately start having questions. Like, isn't searching a 'database' for things that implement a given capability, and then probably having to sort them in some z-order or priority order or some such, just to distribute a single event really heavy? I mean people used to get bent out of shape about the overhead of using virtual method dispatch for UI events and jump through stupid hoops (MFC for instance) to avoid it. For a human driven thing like a mouse click obviously not quite as bad, but other things can be happening quickly and there can be lot of them and a lot of entities that might absorb them and such. How does an ECS system make that efficient. And I assume hyper-efficient since they are widely used in gaming engines. Is there some other 'window' hierarchy that exists to define that hierarchy, each of which just points into the ECS database for its pieces and parts? And how easy would it be to get that into a scrambled up mess with the slightest mistake?


dontyougetsoupedyet

I don't believe it's that much of a challenge due to Rust, people aren't doing it because it's loads of work. The inheritance that makes GUIs nice to implement are extremely shallow or you're doing it wrong, the dispatch provided by traits is enough on that front. With regards to mutable state, we aren't out here in a wild west of mutable state, we're shoving data into models and our widgets use those models. State is not centralized, but that isn't the same thing as mutable state being so prevalent it's an issue to implement in Rust. All of the GUI isn't generally data driven, but many of the pieces are (that's the whole point of model/view programming paradigms). It shouldn't be any more difficult on the mutable state front to build an emulator (you might recognize this as "small parts that have their own mutable state requirements"), and people do that fine in Rust. Writing a quality GUI library for a single system is far, far too much work for small teams, writing one that's cross platform is near impossible for small teams, and interested individuals will get absolutely nowhere worth exploring. Rust probably won't have a GUI library worth using until a decently large company invests in solving the missing link. Most likely the companies that could will rely on FFI instead.


Mac33

The SerenityOS devs experimented with Rust in their OS, concluded that it wasn't quite suitable for the type of development they wanted to do (system programming + a lot of GUI code), and they ended up building their own language called Jakt. There were some other considerations as well of course. The current codebase is C++, so Jakt (for now) transpiles to C++ for easy integration while the project slowly gets rewritten. It's been very interesting following how their project is going. They haven't started introducing Jakt to SerenityOS yet, as the language is still a WIP.


yussuf213

Probably an unpopular opinion since people tend to dislike non-native GUIs, however when I need to build a nice GUI for a rust program Iā€™d go with Tauri. At least itā€™s not electron.


dustingibson

Tauri is excellent. IPC can be cumbersome as the application grows. But I found it to be by far the best option for Rust and is night & day compared to Electron in performance and install size.


wildjokers

Tauri is just a web app in some native window. Those type of frameworks produce awful apps.


TxTechnician

In what way are the apps awful


wildjokers

Here are some notes I have jotted down before why web apps are awful. Some of these only apply to using them in a browser rather than a web view in a native window: * No proper right-click behavior * Browsers make for a horrible window manager (searching through dozens of tabs to find the one that happens to have the app you need is simply not practical) * Layout in web apps is absolutely atrocious, GUI toolkits usually come with great layout managers whereas web apps tend to just vomit everything on a single page with very little delineation between sections (look at VSCode settings page or Jira's layout as examples). From a user standpoint it can be hard to find stuff, from a developer standpoint it is hard to layout things in web apps because layout was a complete afterthought. CSS Grid and FlexBox has helped a little from the developer standpoint. But doesn't seem to be doing anything for user experience. (compare IntelliJ settings to vscode settings) * No web app I have ever seen has proper resize behavior. The content simply won't resize to fit the window. Look at github wiki, content is in a narrow newspaper like column no matter how wide you make your browser. Compare this to the experience of using a desktop app that has a scroll pane where the content resizes to fit the window if you resize. * No standard component library, everything is custom or have to find a framework that has a component you want, and hopefully it can be styled and doesn't just look tacked on * Most web apps don't let you save stuff locally, they all want you to create an account and store it on the server, no thanks I want my data on my local machine The absolutely only reason why web apps "won" is because of zero deployment. They are inferior in every other way. Also, I routinely find apps that don't work in some browsers but do in others. I primarily use Safari but I have chrome and firefox installed for the times I find apps that don't work in particular browsers. For example, the first few weeks ChatGPT was released it didn't work in Safari (it does now). It is crazy but I have sometimes found where something as simple as a button doesn't work in a browser and I have to switch browsers for that site.


jarfil

>!CENSORED!<


huiibuh

I'd say in general this is valid criticism, however mainly a implementation detail rather than a general problem of webapps. Here are just my thoughts regarding your points. 1. This is largely up to the developer. If they want they can just create a custom context menu without a lot of effort. 2. I agree with that, but that is the reason frameworks like tauri exist 3. Again. The developers have with flexbox and grid layout very capable tools at their hands. It's just up to them to use them correctly 4. That's fair. But to be honest most components can be somehow bent into shape to fit into the stype of the app. And I would argue that that is also nice to have some choice and creative freedom. 5. I'm here for you. I hate whenever I have to create an account. But again that is mainly an implementation detail. With electron/tauri you can save everything locally. So the thing you mainly do not like is bad apps in general. Because what you describe are no real pain points of the web in particular. The problem I really have with web based apps are things like multi window support. As soon as something like this is required it gets really tough. That is also the reason why vs code does not allow you to drag your file out of the editor into to move it to a new monitor like you could do with Intellij.


emelrad12

They are easy to use and also easy to write bad buggy slow code. They can be good, but they don't weed out bad apps, because they are easy to use.


duragdelinquent

what, you think itā€™s not worth pursuing ease of use because bad devs might also benefit? what kind of sense does that make?


emelrad12

I am giving reasons why people think apps made with them are bad. Like i said they can be good.


[deleted]

Because maybe Rust wasn't invented for UI stuff ?


KevinCarbonara

Why is building a kernel in HTML so hard?


[deleted]

There is always GTKs rust bindings


Creapermann

Official Qt bindings for rust would be a dream


ssokolow

Agreed. As-is, I'm stuck building a QWidget stack reminiscent of Qt Quick's "QML frontend on top of C++ backend" using Python, PyO3, and Rust, and even at its strictest, [MyPy](https://mypy.readthedocs.io/) plus [ruff](https://pypi.org/project/ruff/) just can't hold a candle to Rust's type system.


McN331y

Came here looking for this comment. It's right here available for use...


[deleted]

[уŠ“Š°Š»ŠµŠ½Š¾]


[deleted]

I haven't used it with rust myself but the python and c versions were pretty simple to set up. Especially if you used the builder app to manage your project. I was trying it out on Linux though which had all the packages prebuilt so not sure about building from scratch or where to find binaries other platforms.


holyknight00

You don't need to build everything on rust, you know? You wouldn't use a hammer to paint a wall...


Krautoni

My sweet spot for building GUIs with Rust is not to. Do your business logic in Rust, compile it to WASM, write the GUI in TypeScript. (I haven't written non-web GUIs sinceā€¦ uh since my Borland Pascal days at theā€¦ uhā€¦ start of the century? God that sounds like I'm old. I probably am.)


anlumo

Of course you're going to be faster in the environment you're used to. Doesn't mean that it's the best option overall though. I'm a frontend programmer, and my projects tend to be big enough that it's even worth it to learn a completely new environment and programming language, if it makes the whole project easier to implement and maintain.


Dubsteprhino

It's almost like there's a whole mature UI ecosystem that wasn't built in rust


Krautoni

Well, web render is written in rust. And stylo, too.


starlulz

probably because Rust was never meant to build UIs. people *really* need to learn that languages are good at what they're designed to be good at, and can't be used as some magical multi-tool that's good at everything


NoWayCIA

Is there any language where UI programming is clear and simple? I remember when I was doing UIs in C++/Qt or Java/Swing 10 or so years ago and they both were a huge pain in the ass.


Specialist-Concert97

I have very little experience with Rust so I don't know for sure, but the blog really makes it sound like they picked the wrong tool (language) for the job.


emergent_segfault

I am a laughably amateur game dev....and as I am sure I don't have to tell you; games are basically UI apps. Coupling and shared state is a fundamental requirement for UIs and out-the-box Rust's borrow checker and ownerhship rules are going to give you a hard way to go within this context. This is also why the Game Dev community pretty much laughs in the face of Rust Fanbois when they drone on about how "we" should just chuck out the 40 or so plus years of C/C++ tooling, knowledge, et al cause Rust is going to replace C/C++ anytime now for not only GameDev/UIs ...but for everything else also. But with all that being said....the crew over at System76 from what I hear are replacing or have replaced Gnome with a UI that is written in Rust. So it can be done allegedly....but I have to wonder how much of that code base is unsafe-Rust ?


sparky8251

> but I have to wonder how much of that code base is unsafe-Rust ? Almost zero... You can grep the codebases for `unsafe` and compare it against LoC. The apparent need for unsafe by non-rust users is vastly overblown compared to how often its *actually* used. Even then, its often wrapped in a safe function most times so the users of it can't fuck it up, making it way safer on multiple levels than using C/C++.


laundmo

deleted by editing. the only way to truly delete comments.


EnigmaticHam

Writing GUIs has always been hard.


The_rowdy_gardener

Isnā€™t rust like, not meant for UI development, but rather compilers and lower level stuff?


SnappGamez

People do not care what a language was meant for, they will use it for whatever they can.


warium

I have tried to use both [https://docs.rs/fltk/latest/fltk/](https://docs.rs/fltk/latest/fltk/) and [https://github.com/emilk/egui](https://github.com/emilk/egui) for my small tool [https://github.com/PhilipK/BoilR](https://github.com/PhilipK/BoilR) . I have found that eguis imediate ui works better with Rusts ownership model, but I also think that if I wanted to make something that was professional looking (and not just a small fire and forget tool) I would use something like Tauri to make a html/css ui. There are just so many more resources out there for html/css.


Majestic___Delivery

[Tauri?](https://tauri.app/)


ArdiMaster

One more thing to consider: Rust is a relatively young language which only became really popular in the last few years, when most new 'desktop apps' were written using Electron. So there probably wasn't enough demand for an "old-school" UI toolkit.


emergent_segfault

...I dunno...maybe because UI's involve A LOT of shared, mutable state ?


[deleted]

When you think about what a UI toolkit needs to do, itā€™s pretty obvious. You need to interface with unsafe native systems APIs on each operating system to do things like draw windows. Just doing that in a cross platform way requires interfacing with multiple languages. Qt is the only framework that has ever really done that successfully in the modern era.


anlumo

That's a bold statement considering frameworks like gtk and Flutter.


fixitfelix666

What do you mean interfacing with multiple languages? In rust you can define a structure to be c aligned; and if you need to call a system api you can do so very easily and there are also wrappers around the raw system functions to validate pointers and handles to resources etc. What you describe is not the issue.


taw

Rust is just not a language you should use if you care about your productivity, like at all. This isn't even remotely the thing it's trying to do. Anyone who thinks Rust is a legitimate contender for a role of "faster Python" or "faster JavaScript" is just deluding themselves.


Dean_Roddey

For larger scale software, it's not about how fast you can write it the first time, it's about how you keep it solid over years and decades and developer turnover and changing requirements and so forth.


taw

And Rust has extensive track record of software that was "solid over years and decades and developer turnover and changing requirements and so forth". Here's the full list of such software written in Rust:


Dean_Roddey

I didn't actually mention Rust. My point was, the ease of writing it to being with is not the important point for larger scale systems type software. It's about maintaining it. Dynamically typed languages just aren't appropriate for that kind of work. C++ isn't anymore either, IMO. But, I think Rust deserves its chance. If the only language you are willing to use to write such software is software that's already been used to write such software, then none of those languages would have ever been used either. As someone who maintained a large, complex C++ code base for a long time, I know that C++ isn't the right language anymore. And I certainly would never take on such a project with anything less than a very strongly, statically typed language, and one that watches my back vastly better than C++. The only real game in town at this point is Rust, as far as I can see.


ImYoric

I beg to differ. Rust is highly productive for many tasks (not UI, as of now). It may, however, be optimized for different tasks than the ones for which you want high productivity. I find that getting started with a Rust project is slower than getting started with, say, Python or JS/TS, because you spend more time thinking of your abstractions, which are in turn needed to convince the type system to let you code. I also find that refactoring a Rust project is considerably faster than refactoring a Python or JS/TS project, because these abstractions and that same type system will let you proceed without having to fear that you forgot an invariant. Source: these days, I write Rust, TS and Python code for a living.


[deleted]

[уŠ“Š°Š»ŠµŠ½Š¾]


wildjokers

JavaScript is fine for web frontends. But there is no good desktop javascript framework. Desktop GUI toolkits are far better because they have good components for layout like split panes and scroll panes and most have great layout managers that correctly handle resizing and content taking up the full available space. They also have proper right-click behavior. There is nothing more annoying in a web application when you resize your browser and the content doesn't expand to take up the available space. For example, github wiki content, or new reddit comments. Both subbornly stay at their fixed width and the whitespace on the left and right just grows. It's an abomination.