[HN Gopher] Iced: A cross-platform GUI library for Rust, inspire...
       ___________________________________________________________________
        
       Iced: A cross-platform GUI library for Rust, inspired by Elm
        
       Author : ducktective
       Score  : 377 points
       Date   : 2021-08-27 10:33 UTC (12 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | no_wizard wrote:
       | Any idea if mobile support is coming? That's starting to feel
       | table stakes as time goes on I think, even more important than
       | desktop which can always fall back to web
        
       | ComputerGuru wrote:
       | The most recent time I evaluated Iced (Aug 2020), it didn't
       | support any of my Linux machines due to broken/non-existent
       | OpenGL support. With the progress the wgpu renderer has made, I'm
       | pleased to report the situation has improved, although on Linux
       | my initial attempt landed me here:
       | https://github.com/hecrj/iced/issues/1013
       | 
       | I've had no issues with Iced on any other platforms, fwiw.
        
       | ZenPsycho wrote:
       | until this supports accessibility, please don't use this
        
       | mftb wrote:
       | I think the example in the readme is presented and worded in a
       | confusing way, "Finally, we need to be able to react to any
       | produced messages and change our state accordingly in our update
       | logic:". Since your referencing the Elm architecture, it's 1.
       | send msg, 2. update 3. view. This is presented, 1. 3. 2. The code
       | looks right, but the example seems out of order and consequently
       | confusing.
        
       | skohan wrote:
       | How does it work? Does it render itself, or delegate to native UI
       | components?
        
         | fosefx wrote:
         | The project is kept modular. There are renderers for web [1]
         | and native [2]. The project's ECOSYSTEM.md [3] is addressing
         | this in more detail.
         | 
         | [1] https://github.com/hecrj/iced/tree/master/web [2]
         | https://github.com/hecrj/iced/tree/master/wgpu [3]
         | https://github.com/hecrj/iced/blob/master/ECOSYSTEM.md
        
       | qwertygnu wrote:
       | I'm dislike the not-so-recent trend of
       | companies/projects/libraries that co-opt common words as their
       | name. "Rust" and "elm" and "iced" wouldn't normally have anything
       | to do with computing, but it still feels like a small intrusion
       | on our language.
        
         | alpaca128 wrote:
         | You mean like Apple, BASIC, Lisp, Explorer, Safari, Chrome,
         | Android, ...? This practice has existed from the start and I
         | don't see it as an intrusion into the language. We humans are
         | able to consider context (which is necessary for language
         | either way), and that mostly takes care of it. When someone
         | says "I've got rust on my PC's power supply" or "my python
         | escaped" it's still very obvious it's not the programming
         | language.
         | 
         | And an outsider might have trouble following the conversation,
         | but that would happen no matter what words are used. Whether we
         | say "Elm" or "C++", the target audience knows what's meant and
         | others wouldn't be able to follow either way.
        
           | jhgb wrote:
           | LISP and BASIC were initially acronyms.
        
         | ryanianian wrote:
         | > it still feels like a small intrusion on our language.
         | 
         | All languages evolve over time, despite official bodies trying
         | to reject foreign influence. (IIRC the French government has a
         | department that tries to limit loan words from other languages,
         | but good luck with that given the internet.)
         | 
         | So what's the actual problem with it? Only downside I see is
         | google-ability and occasional conflicts when two projects use
         | the same name. Both of those exist with any naming Scheme (ha!)
         | and imho haven't really ended badly for projects or their
         | users.
        
       | andrekandre wrote:
       | struct Counter {         // The counter value         value: i32,
       | // The local state of the two buttons         increment_button:
       | button::State,         decrement_button: button::State,       }
       | impl Counter {              pub fn view(&mut self) ->
       | Column<Message> {            ...         }       }
       | 
       | this looks like it holds state in the ui layer... wouldn't it be
       | better to keep state in some separate state/model object (struct)
       | and bind the ui to that instead?
       | 
       | not doing it this way couples a lot of logic/state to the ui
       | framework which means its much harder to switch ui frameworks
       | later, not to mention testing the logic independently of the ui
       | choice...
        
         | andrekandre wrote:
         | to whoever downvoted, instead of downvoting, maybe its better
         | to make a counter argument?
         | 
         | im asking because i hope to get some insight not a silent
         | downvote
        
           | ensiferum wrote:
           | I agree with your point. In fact it's the approach I'm doing
           | myself in my current UI lib (which has a very specific use
           | case but the point still applies).
           | 
           | https://github.com/ensisoft/gamestudio/blob/master/uikit/win.
           | ..
        
       | dhbradshaw wrote:
       | I've been playing with the iced examples, particularly the
       | styling example. The code is beautiful and the result is clean
       | and responsive and fast. Love this.
        
       | danieltanfh95 wrote:
       | App developers discover game programming patterns, colorized 2021
        
         | arsome wrote:
         | Slowly they'll meet with the Electron people and eventually
         | we'll reinvent Delphi and Visual Basic.
        
       | cultofmetatron wrote:
       | congrats on plugging one of the biggest holes in the rust
       | ecosystem. Looks like an api I'd love working with. Id love to
       | imagine an alt universe where someone builds an entire desktop
       | off this the way gnome was formed from gtk.
        
       | amelius wrote:
       | Just looking at the example, I notice that you have to use Enums
       | to pass messages around. E.g. "IncrementPressed" in the example.
       | Wouldn't it be much easier to use closures for that? Managing
       | Enums sounds like an unnecessary administrative burden.
        
         | Dowwie wrote:
         | Enums are a natural fit for event handling. If you write an api
         | that can manage 50 different kinds of events, a single enum
         | consisting of 50 variants would be able to facilitate that. A
         | closure isn't identifiable to the request handler. It's just a
         | thing that does stuff, when you're ready to call it. How do you
         | know what stuff to do with it?
        
           | amelius wrote:
           | What I mean is: binding an enum to an action, which then
           | sends a message containing the enum, deciphering it and
           | executing code based on its value, and not forgetting to
           | define the enum somewhere, when ... you could simply bind the
           | closure to the action.
           | 
           | So instead of:                   Button::new(&mut
           | self.increment_button, Text::new("+"))
           | .on_press(Message::IncrementPressed)
           | 
           | you would write:                   Button::new(&mut
           | self.increment_button, Text::new("+"))
           | .on_press(|| MY_CODE_HERE)
           | 
           | For comparison, in JavaScript you can write:
           | button.onclick = function(){ ++counter; }
           | 
           | That's quite a direct way of formulating what you want to
           | happen. All in a single line and no Enums involved.
        
             | WJW wrote:
             | The enum of all possible events is still there, it's just
             | spread over dozens of different callback properties
             | belonging to several different objects. Splitting out via
             | an enum to a big `handle` type function makes it possible
             | to detect whether you have handled all possible events at
             | compile time instead of having to raise an exception at
             | runtime.
        
               | jbverschoor wrote:
               | Just require a callback to be non-null.
        
               | verdagon wrote:
               | If we had a closure, we wouldn't ever need to "handle all
               | possible events", we would just do a virtual call. It's
               | guaranteed to be handled.
        
               | varajelle wrote:
               | I see little value in seeing that enum of all possible
               | event on one place. On the other hand, I want to see what
               | is the action performed by that button and there is value
               | in having small event handler close to the thing they
               | handle.
        
             | nybble41 wrote:
             | The iced package requires the messages to implement the
             | Debug, Clone, and Send traits, none of which are available
             | for closures. I was able to implement something similar to
             | your example[0] but it only supports plain function
             | pointers for the callbacks. The compiler wasn't able to
             | derive a sufficiently general Debug trait for the function
             | pointer due to an issue with the lifetime of the argument,
             | so I had to implement that myself as well.
             | 
             |  _[Edit: Ignore this next paragraph; as steveklabnik
             | pointed out, this change has already been implemented and
             | "Message(|c| c.value += 1)" is accepted by the latest
             | stable version.]_ Incidentally, as long as there are
             | situations where only function pointers can be used and not
             | closures it would be _really_ nice to have some support for
             | anonymous function pointers in Rust (with the fn type and
             | not just the Fn trait) so that one could write e.g.
             | "Message(fn |c| c.value += 1)" instead of "Message({ fn
             | f(c: &mut Counter) { c.value += 1 } f })". Or just infer
             | the fn type for "closures" which don't actually close over
             | any variables without the need for an extra keyword.
             | 
             | [0] https://github.com/nybble41/iced-
             | counter2/blob/master/src/ma...
        
               | steveklabnik wrote:
               | I'm not at my computer but I thought non-capturing
               | closures already will coerce into a fn.
        
               | nybble41 wrote:
               | It seems you're right. That didn't work the last time I
               | tried it--which I admit was some time ago--but it does
               | work in the latest stable version of rustc.
        
               | steveklabnik wrote:
               | Looks like support was added about four years ago, but it
               | is true this wasn't the case a whole back. Glad it's
               | working now though!
        
               | jayd16 wrote:
               | Pretty funny to read the arguments about how enums are
               | the one true way and here we see function pointers are
               | already supported.
        
               | Jweb_Guru wrote:
               | Bare function pointers are, but not state-capturing ones
               | (see my other comment for why that is). Without state
               | capture, closures really aren't more ergonomic to use
               | than enums in most cases, and are often less so.
        
         | Jweb_Guru wrote:
         | No one has addressed the actual issue here, unfortunately.
         | There's a good reason why you'll often find message passing
         | done with enums in Rust where other languages use closures, and
         | it's not ideological.
         | 
         | In Rust, if you want to access shared state, you need to hold
         | onto a reference to it. If a reference captured by a closure is
         | unique, the compiler conservatively prevents you from not only
         | accessing that variable, but _anything that could transitively
         | lead to it_ , and if it's shared, the compiler prevents you
         | from _mutating_ anything that could lead to it. Additionally,
         | you can 't move or destroy the object until there's no chance
         | _any_ value transitively referenced through it is still
         | borrowed--which across threads, often means pretty much _no_
         | borrow length will suffice. In a UI framework sending stuff
         | across threads, that 's a totally unacceptable state of
         | affairs. By contrast, enums that declaratively specify what you
         | want to modify have no such issues, because the state only
         | needs to be accessed when you actually want to run the event.
         | 
         | There are three ways to work around the lifetime part, but
         | they're not ideal. The most common is to use something like Rc
         | or Arc, which allow reference counting (a primitive form of
         | garbage collection). Reference counting _always_ makes your
         | objects shared, so it guarantees you 'll have to tackle the
         | mutation problem somehow, which can be unsatisfying; it also
         | has a runtime cost (which can be quite significant) and can
         | cause memory leaks if you have cycles in your data (though this
         | is rarely an issue in UI frameworks). Secondly, you can
         | architect your application around things like arenas, which
         | give you "scoped" access to lifetimes--these can be really
         | efficient with the right use case, especially pointer-spaghetti
         | graphs, but can restrict a lot of the patterns you'd write in
         | Rust, since the arenas have to outlive _everything_ you want to
         | do with the objects. Finally, you can separate your shared data
         | from the closure--which works great but now you are restricted
         | to  "bare" functions or functions that only capture unrelated
         | state. The closure can't specify the state it wants to update,
         | it has to be directed to the object--which is much less ideal
         | (since now the closures aren't universal in any way, as they
         | need to be passed in the state they want to modify).
         | 
         | You can work around the mutation part in two ways, but neither
         | is that great. One is, again, to ban closures from capturing
         | any environment state, so the data is still stored separately
         | and has to be passed in, which has the limitations mentioned
         | previously.
         | 
         | The other is to use "interior mutability" which uses some
         | combination of runtime checks and other restrictions to
         | guarantee that you're only accessing the element one at a time.
         | Almost invariably, these mechanisms are slower at runtime,
         | restrict your types somehow (e.g. making them non thread safe),
         | can cause your program to panic if you misuse them, or are just
         | plain annoying to use (or some combination of all of these). So
         | when you can avoid this option, you do!
         | 
         | So basically: enums make a ton of sense in Rust because they
         | totally avoid these borrow checker issues. Your intuitions
         | about using closures for this stuff in functional or garbage
         | collected languages don't apply here--patterns that make a lot
         | of sense in them don't work at all in Rust. That's one big
         | reason there are so many Rust UI frameworks rather than just
         | wrapping the C ones or using the same patterns you see in
         | functional languages--the usual patterns simply don't work
         | well.
         | 
         | That's not say there aren't some upsides to the approach from a
         | reasoning standpoint. A big one is that it enforces "single
         | writer" control flow--just one place is responsible for all the
         | state updates, so you don't have to worry about synchronization
         | weirdness due to lots of places updating the state on their
         | own. IME, this helps a lot with reasoning. But not everyone
         | agrees that that outweighs the convenience of being able to use
         | a callback, which I totally get--it's just that the "convenient
         | way" isn't really convenient in Rust at all. And it's this that
         | causes all these libraries to be designed this way (at least
         | that's been my experience), not theoretical concerns about
         | serialization and stuff which I agree is basically a nonissue
         | in practice.
        
           | verdagon wrote:
           | Thank you for this thorough and balanced explanation! This is
           | probably why all the GUI frameworks in Rust (that I've seen)
           | require message passing like this. You have a really good
           | handle on the borrow checker's benefits and limitations.
           | 
           | I'm trying to make a language (https://vale.dev/) that
           | addresses the borrow checker's limitations (by making it
           | automatic and opt-in) to handle cases like these, if you want
           | to drop by our discord (https://discord.gg/SNB8yGH), I'd love
           | to get your thoughts!
        
         | jerf wrote:
         | Consider the Enums simply as defunctionalized closures.
         | 
         | https://blog.sigplan.org/2019/12/30/defunctionalization-ever...
         | 
         | There are significant advantages to this sort of
         | defunctionalization in a system like this. It is a bit more
         | administratively at the point of enum definition, but the
         | flexibility and simplification of the _other_ parts of the
         | program will be a win for almost any non-trivial UI
         | application, not to mention the future-proofing it gives you.
        
           | amelius wrote:
           | Could you give a concrete example of the benefits? I prefer
           | to avoid abstract discussion since it might not apply to 99%
           | of my code.
           | 
           | And by the way, defunctionalization sounds a lot like
           | transforming my code into a bytecode interpreter which
           | interprets my code. This is something I don't need and which
           | would make my code slower and more difficult to read.
        
             | b3morales wrote:
             | One key difference is that the defunctionalized
             | representation is _serializable_. An example feature that
             | enables is that you can now have a GUI for your interface
             | construction, letting you preview the layout while you
             | build it. The controls are hooked up to the message names,
             | which can be be deserialized at runtime and used for
             | dispatch. Attaching live functions, especially closures, to
             | them is not really feasible.
        
               | amelius wrote:
               | Do you think that at one point Rust could automatically
               | transform my code into defunctionalized form, and thus
               | make it serializable?
               | 
               | What you describe sounds like QT Creator, by the way.
        
               | b3morales wrote:
               | > Do you think that at one point Rust could automatically
               | transform my code into defunctionalized form, and thus
               | make it serializable?
               | 
               | For a pure function some kind of bytecode representation
               | is certainly conceivable, but as soon as you add captures
               | it gets much more complex.
               | 
               | > QT Creator
               | 
               | Precisely, yup; or Android's Layout Editor/Apple's
               | Interface Builder.
        
               | verdagon wrote:
               | You might be serializing your enums, but unless you
               | serialize a lot more (button IDs, view IDs, etc), the IDs
               | in your enums will be meaningless. I don't think you're
               | suggesting we serialize the entire GUI?
               | 
               | This also seems like the wrong layer to serialize.
               | Normally we would want to serialize the model, not the
               | view. Admittedly, the line is a bit blurry here (and for
               | most small programs) so take my words with a grain of
               | salt.
        
               | b3morales wrote:
               | > I don't think you're suggesting we serialize the entire
               | GUI?
               | 
               | I am, exactly -- to enable WYSWIG construction/editing of
               | the GUI. Just added another comment saying this below,
               | but consider Android Layout Editor/Apple Interface
               | Builder (or someone else mentioned QT Creator, which I'm
               | not familiar with but has the same idea).
        
               | amelius wrote:
               | You might be right, but I feel that by filling out Enum
               | structures I am helping the tools, whereas the tools
               | should be helping me.
               | 
               | And as a terminal-aficionado I don't want to use
               | Design/Creator tools.
               | 
               | So ... what I really want is a simple API with closures.
               | And there should be no problem with that, as the
               | Design/Creator tools can simply emit more complicated
               | code if they want (e.g. closures that use enums).
        
               | verdagon wrote:
               | I'm not sure this is how WYSWYG really works.
               | 
               | There's only one MyFancyTextEditor widget definition, a
               | blueprint so to speak. It's IDs refer to other things
               | inside that blueprint.
               | 
               | But at runtime, we might instantiate two different
               | MyFancyTextEditors, one for view A and one for view B.
               | They probably shouldn't share IDs, lest we run into
               | confusion.
               | 
               | I think WYSWIG is more like defining a class, whereas at
               | runtime we'd be serializing instances.
               | 
               | Feel free to correct me if I'm wrong, I admit I've never
               | been down this line of thought!
        
               | b3morales wrote:
               | Here's an example snippet from a xib file for an actual
               | iOS project of mine:                   <button
               | opaque="NO" contentMode="scaleToFill"
               | contentHorizontalAlignment="center"
               | contentVerticalAlignment="center"
               | buttonType="roundedRect" lineBreakMode="middleTruncation"
               | translatesAutoresizingMaskIntoConstraints="NO"
               | id="ykl-6F-b5r">           <rect key="frame" x="0.0"
               | y="0.0" width="375" height="0.0"/>           <state
               | key="normal" title="Done"/>           <connections>
               | <action selector="doneEditingTitle"
               | destination="POI-12-VR5" eventType="touchUpInside"
               | id="14R-fR-990"/>           </connections>
               | </button>
               | 
               | A xib is an XML description of a GUI layout. Note the
               | `<connections><action ...>` element inside the `<button>`
               | -- this is defining what happens when the button is
               | tapped. The connection becomes active at runtime when the
               | file is rehydrated into live objects. The `selector`
               | string identifies the name of the method to be called.
               | (This exact mechanism relies on ObjC, but the principle
               | can be applied to other systems.)
        
               | verdagon wrote:
               | My point was that when we hydrate, we don't use the same
               | IDs as what was in the serialized data. Otherwise, we'd
               | have conflicts when we hydrate the same definition
               | multiple times.
        
               | b3morales wrote:
               | I'm sorry, I'm not following your point -- what are the
               | IDs used for, in your example?
               | 
               | (For the XIB system, they have no purpose at runtime;
               | they're solely for the archive. Objects get their own
               | identity as usual when they're instantiated.)
        
               | verdagon wrote:
               | My bad, I didn't really explain that part.
               | 
               | In practice, when we receive a GUI event, we then modify
               | something in our surrounding environment, usually some
               | model, controller, or other view. To interact with any of
               | those in Rust, we need to refer to it by some sort of ID.
               | 
               | This is the same ID you're referring to, which objects
               | get when they're instantiated, at least for views (models
               | and controllers likely do something similar).
               | 
               | My central question is: why would we want to serialize
               | those IDs?
               | 
               | Also, WYSWYG might not be the best example, as it's a GUI
               | that produces another GUI, hence some confusion. If you
               | think about this in terms of a simple app that maintains
               | a Customer database, you'll see what I mean; we wouldn't
               | ever want to serialize a button click event there,
               | especially since the hydrated IDs aren't stable and we
               | don't know what they refer to unless we serialize the
               | entire app UI state.
        
               | b3morales wrote:
               | Maybe I'm missing something particular about Rust? When
               | the archive is loaded at runtime, we don't need explicit
               | IDs: we have a normal object graph, with references
               | between things. The instantiated widgets have identity as
               | objects in memory. The string `id="ykl-6F-b5r"` isn't
               | relevant -- or used at all.
               | 
               | You can create as many instances of `Button` as you want,
               | and they are different, and their targets (the other
               | widgets they message when tapped) are different because
               | they were either created alongside or, if they were live
               | before the archive was deserialized, a reference was made
               | to them as part of the deserialization process.
        
               | verdagon wrote:
               | I think what you might be missing is that, in (safe +
               | idiomatic) Rust, we actually can't have references
               | between things (unless we want to make our entire GUI
               | immutable, which would be a tad silly).
               | 
               | Since we can't use references, we need to "refer" to
               | other objects via IDs.
        
               | b3morales wrote:
               | Thanks, I'll have to look into how GUIs in Rust work
               | then; that sounds utterly bizarre to me :)
               | 
               | I thought you could take references to things in Rust.
               | Also, in particular, I don't understand why you'd want to
               | use closures -- inherently reference-y -- when everything
               | else is (I guess?) a non-reference plain value.
        
               | kortex wrote:
               | > I don't think you're suggesting we serialize the entire
               | GUI?
               | 
               | Yup that's exactly what people do in some GUIs. Tons of
               | GUI frameworks and systems rely on varying degrees of
               | defunctionalization and serialization. Microsoft COM and
               | XServer for example. I don't know exactly how granular
               | they get but I believe it's quite granular in what you
               | can do over RPC.
        
               | verdagon wrote:
               | I thought COM was a way to talk between
               | applications/libraries, not between GUI elements?
               | 
               | Message passing at that level is fine IMO, but between
               | GUI views/controllers sounds like a bad tradeoff though.
        
             | jerf wrote:
             | The problem with closures is that they are opaque. The only
             | way to interact with them is to call them. Making them the
             | foundation of your system eliminates a lot of useful
             | architectural patterns, such as putting filters on the
             | event stream, being able to prioritize some of them based
             | on certain criteria, being able to ship them between
             | different servers if necessary, creating a generic logger
             | that can operate on the enumeration values without having
             | to have each closure log things, implementing various
             | security checks (you really don't want a security system to
             | be stuck only being able to run a bit of code to see if
             | it's safe), just a whole lot of things that can't be done
             | if all you have are closures.
             | 
             | If you don't care about your values leaving your local OS
             | process, which is a pretty common use case, there's a
             | hybrid approach you can take too, which is to put closures
             | inside your data structures that describe the value,
             | instead of passing raw closures around. You get the
             | benefits of being able to examine the values without
             | executing the handler and being able to filter, decorate,
             | etc. but while retaining all the advantages of being able
             | to implement handlers inline. Depending on your local
             | language, various slick implementations may allow this to
             | be one degree or another of transparent, such as
             | implementing some sort of interface/trait for all these
             | values, or implementing __call__ in Python, etc.
             | 
             | "And by the way, defunctionalization sounds a lot like
             | transforming my code into a bytecode interpreter which
             | interprets my code. This is something I don't need and
             | which would make my code slower and more difficult to
             | read."
             | 
             | It depends on the language you're in. Most OO languages
             | have some way of doing this that doesn't add any speed
             | issues to speak of, it's just a slight rearrangement of
             | code.
             | 
             | I'd also say this is an issue of scale. I don't bother with
             | this in small programs and may just glue everything
             | together with closures, but as program size increases the
             | odds that you'll want to do something that you can't do
             | with closures directly increase. But the languages I tend
             | to work in don't make this much of a hassle usually,
             | either. I think you may be overestimating the expense.
        
               | verdagon wrote:
               | By opaque, do you mean encapsulated? Encapsulation is
               | pretty important to software architecture, in that it
               | enforces decoupling between components. Rust has private
               | visibility for this very reason.
               | 
               | The filtering you're talking about sounds interesting,
               | but the GUI layer is (imo) _definitely_ the wrong place
               | to do it. When 's the last time you wanted to filter,
               | prioritize, secure, or distribute UI events?
               | 
               | Imagine if we transformed every method call in our app
               | into enums, it would be an unwieldy and unreadable mess.
               | I'm not saying you're suggesting that, just highlighting
               | that there are definitely some drawbacks here.
               | 
               | So, I don't see why we're being forced to use enums in
               | this case.
               | 
               | I wonder if this a conscious decision by the Iced folks,
               | and if they first tried with closures and ran into some
               | trouble.
               | 
               | Your hybrid idea is interesting! Is that doable with Rust
               | in practice? I'd imagine the borrow checker might enforce
               | it can't read from outside its scope.
        
         | Skinney wrote:
         | There are several benefits to using enums as opposed to
         | closures:
         | 
         | 1. All your actions are in one place. Figuring out what can
         | happen as a result of a series of user interactions can be done
         | without navigating through a component hierarchy.
         | 
         | 2. The history of a user interaction is simple to serialize. In
         | case of error, you can dump the user interaction history for
         | this session (just a list of enum values, right?) to disk. This
         | can then be submitted in bug reports for easy re-production of
         | an issue.
         | 
         | 3. It's simple(r) to create a time-travelling debugger that can
         | move backwards and forwards in time, since it can simply re-
         | play the series of messages to a specific point.
         | 
         | 4. Since you've seperated state changes from the UI, writing
         | unit tests that ensures that a series of user interactions
         | results in a specific state is pretty easy. You just send in
         | the enum values representing a specific use interaction then
         | check what state you've ended up with.
        
           | verdagon wrote:
           | > 1. All your actions are in one place. Figuring out what can
           | happen as a result of a series of user interactions can be
           | done without navigating through a component hierarchy.
           | 
           | I'd imagine it would be easier to just call a method on
           | whatever we want to update, instead of lowering all our
           | methods into enums. Why wouldn't we do that instead?
           | 
           | Also, serializing usually isn't enough to get the benefits
           | you describe. You need true determinism for that, and that's
           | very difficult to achieve. If you ever e.g. query the current
           | date without recording it you've just introduced
           | nondeterminism.
           | 
           | If we could really achieve deterministic replayability
           | easily, then I might be okay with the drawback of turning
           | methods into enums.
        
             | Skinney wrote:
             | > I'd imagine it would be easier to just call a method on
             | whatever we want to update, instead of lowering all our
             | methods into enums. Why wouldn't we do that instead?
             | 
             | Easier how? The difference in lines of code is minimal.
             | It's not going to make any meaningful difference in how
             | much time you spend on crafting a solution.
             | 
             | > Also, serializing usually isn't enough to get the
             | benefits you describe. You need true determinism for that,
             | and that's very difficult to achieve. If you ever e.g.
             | query the current date without recording it you've just
             | introduced nondeterminism.
             | 
             | It requires some thought, but it isn't terribly difficult.
             | Most user interactions with a gui doesn't require a side
             | effect, and those that do can usually be written in a way
             | that it gets represented in the enum. Even when
             | nondeterminism creeps in, it rarely cancels out all of the
             | benefits of having a history of user interaction. Perfect
             | nedn't be the enemy of good.
        
               | verdagon wrote:
               | I'm afraid that when dealing with nondeterminism, you
               | *do* need to be perfect. If even one call is
               | nondeterministic, you've corrupted your entire replay.
               | 
               | This is a common challenge with e.g. RTS games, and it
               | means we have to very carefully discover and avoid
               | nondeterministic functions.
               | 
               | For example, did you know that C#'s string's hash code
               | calculation is nondeterministic across runs? The same can
               | be said for any floating point calculations, iterating
               | Rust's/Go's default hash maps, etc.
               | 
               | Also, IME most interactions with GUI do have side
               | effects, GUI apps tend to be very stateful.
        
         | scns wrote:
         | Using Enums makes you build a Finite State Machine and
         | therefore all effects/state transitions explicit and
         | concentrated at one place. This enables you to see what this
         | particular piece of code is able to do. Methods could obscure
         | what might happen. Using inline closures would make it hard if
         | not impossible to get an overview what might happen.
        
         | jbverschoor wrote:
         | Message passing is a lower level construct. It's nice in the
         | way that you can have multiple subscribers, but for __most__
         | application you won't need it.
         | 
         | I mean, we're not really doing this anymore, right?
         | while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) {}
        
           | Narishma wrote:
           | What's wrong with that?
        
       | chubs wrote:
       | Worth mentioning: cryptowatch's great desktop app uses this, it's
       | worth trying as an example of how efficient iced is, i like it:
       | https://blog.cryptowat.ch/sponsoring-rust-gui-library-iced/
        
       | O_H_E wrote:
       | Genuine question: Does somebody understand how this compares to
       | Druid https://github.com/linebender/druid
        
         | danachow wrote:
         | Well for one this seems to do it's own rendering. Druid depends
         | on a native widget toolkit.
        
           | adamnemecek wrote:
           | Druid does its own rendering using piet and uses some native
           | controls.
           | 
           | Here's an example of Druid rendering a button. https://github
           | .com/linebender/druid/blob/master/druid/src/wi...
        
         | raphlinus wrote:
         | I wrote a little on this last year, mostly still valid:
         | https://raphlinus.github.io/rust/druid/2020/09/28/rust-2021....
         | 
         | I think there are approximately five viable Rust toolkits:
         | Iced, Makepad, sixtyfps, egui, and Druid (in no particular
         | order). Any of these five could evolve to being a real
         | solution, with enough investment. Of course, it's possible
         | another could arise, or that I've given short shrift to one of
         | the other contenders (areweguiyet has a list, but that resource
         | is not super well maintained).
         | 
         | There are some things easier to do in Iced than Druid
         | (especially integration with 3D, which is something we
         | currently don't do at all). On the other hand, we're pushing
         | pretty hard on infrastructure: proper text handling, input
         | methods, subwindows, etc. Currently, Druid relies on platform
         | capabilities for 2D drawing, but my main work right now is a
         | new GPU renderer. And we hope to work with 'mwcampbell on
         | accessibility in the next year (integrating AccessKit).
         | 
         | We've got a great community, but tend not to toot our horn very
         | loudly, so people might not be as aware of the progress we're
         | making. By contrast, sixtyfps is a commercial product (in
         | addition to a GPL release) and has weekly updates.
        
           | O_H_E wrote:
           | Oh wow, did not expect an answer form Ralph himself. Great
           | fan of your work on Xi.
           | 
           | Thanks for the detailed answer. As an aching Linux user, I
           | appreciate your focus on infrastructure and accessibility.
        
       | woodruffw wrote:
       | An unfortunate name clash with one of the best x86 decoders I've
       | ever used, also written in Rust[1].
       | 
       | [1]: https://github.com/icedland/iced
        
         | benatkin wrote:
         | Looks like the GUI library's crate came out first:
         | 
         | https://crates.io/crates/iced/versions
         | https://crates.io/crates/iced-x86/versions
         | 
         | I'm not sure there's a naming conflict here. There is little
         | overlap between x86 decoding and a GUI library. If _software is
         | eating the world_ , then it's similar to Giant Bicycles and
         | Giant Food Stores.
        
           | woodruffw wrote:
           | I didn't mean to imply priority: a clash is just a clash, not
           | a sign that either project isn't entitled to the name. It's
           | just an unfortunate namespace problem: language package
           | managers (overwhelmingly) flatten things into a single-level
           | namespace, and so we end up with things like this.
           | 
           | > There is little overlap between x86 decoding and a GUI
           | library.
           | 
           | I work on a graphical tool that visualizes x86 binaries! It
           | uses iced (the decoder), and it could very easily end up
           | using iced (the GUI library).
        
             | ucosty wrote:
             | But then you'd be obliged to call it Ice Cubed
        
             | benatkin wrote:
             | The main thing I disagree with you on, is that there is a
             | namespace collision because of the package manager, or that
             | there is a namespace collision because both use Rust. If
             | there is a namespace collision, it should be because
             | they're both tools used by developers. The package manager
             | issue is solved easily by adding something to the package
             | name. As for the language, Rust is shaping up to be more
             | like C++ than Ruby or Python, where the main community is
             | more about the language and the standard library and less
             | about the myriad different uses of it.
             | 
             | I think both can keep their names long-term.
        
         | tomcam wrote:
         | Had no clue this existed. Looks like the Swiss Army knife of
         | reverse engineering. Thank you.
        
         | qw3rty01 wrote:
         | This is the project that the dnSpy author moved to!
        
       | option_greek wrote:
       | Very nice. If it works on mobile too, could end up being a
       | competitor to flutter.
        
       | ecmascript wrote:
       | Looks cool, how does the DOM updates work here? Is it possible to
       | do whatever kind of update you want?
        
         | clarkmoody wrote:
         | There is no DOM, since this is not Web tech.
         | 
         | GUI state mutations are triggered by messages passed around the
         | system. Messages can be generated from user interactions for by
         | asynchronous subscriptions (network socket, etc).
        
           | tmccrary55 wrote:
           | It sure looks like it's using the DOM in the inspector.
           | 
           | Which is cool but a custom rendered UI would be cooler.
        
             | clarkmoody wrote:
             | Iced can compile to WASM and be run in a browser, but
             | that's just a single target. There is no concept of DOM in
             | Iced itself.
        
               | ecmascript wrote:
               | I get that, but how does the updates in the DOM work in
               | the example? Is it possible to extend it somehow?
        
               | tmccrary55 wrote:
               | Ah I see what you mean.
        
       | jatins wrote:
       | That looks exciting! Congrats on the ship.
       | 
       | Have you done any benchmarking on how this compares with Electron
       | on things like binary size, memory usage? Those are usually most
       | common complaints people have with regards to Electron so would
       | be nice to see the improvements this provides.
        
         | clarkmoody wrote:
         | From my experience, compressed binary bundle is < 10 Mb and
         | memory usage is < 100 Mb for a generic app. Of course memory
         | usage will vary wildly between application domains. With Iced,
         | it's fairly constant, since Rust offers pretty solid memory
         | leak protection.
        
           | ducktective wrote:
           | Music to my ears...
        
         | OJFord wrote:
         | This looks great too, but just to point out if you're looking
         | for something like Electron (but rust, or smaller or whatever)
         | then Tauri is a much closer fit, using web stuff (HTML, CSS,
         | JS, wasm, frameworks, whatever you want) for the UI in the same
         | way.
        
           | JohnKacz wrote:
           | Thanks. I had not heard of Tauri.
           | 
           | https://github.com/tauri-apps/tauri
        
           | jatins wrote:
           | Tauri, while an improvement on some aspects, is still a
           | webapp in a shell. But it has the problem that you have to
           | deal with browser specific quirks.
           | 
           | From what I understand, this will avoid that problem by
           | compiling to whatever native platform you are building for?
           | Also it'd not just be a webapp in a shell.
        
             | imbnwa wrote:
             | If by browser specific quirks you mean having to deal with
             | Webkit as Windows is Chromium now.
        
               | OJFord wrote:
               | Well, Tauri (or more specifically the 'ri' part:
               | https://github.com/tauri-apps/wry/) uses different
               | engines on different platforms, so I assume there's the
               | potential for quirks.
        
             | OJFord wrote:
             | Yes, correct I think on all counts. I was just responding
             | to the Electron comparison, saying if _that_ 's what you
             | want, maybe look at Tauri, _because_ it 's also 'a webapp
             | in a shell'.
             | 
             | For some people in some senses, there's a big advantage to
             | the 'webapp in a shell' model, because HTML/CSS is
             | considered good, or WhizzBang.js is the familiar tool for
             | building UIs, or whatever.
             | 
             | I didn't mean to say it's better (or worse) than this -
             | it's just quite a different (more similar to Electron)
             | approach, that'll suit some and not others.
        
         | api wrote:
         | Almost everything is smaller than Electron.
        
           | amelius wrote:
           | Yeah but don't forget that Electron is literally packed with
           | features. For example it can draw SVG, it can play video, it
           | can do 3d stuff, do networking stuff ...
        
           | axelroze wrote:
           | Cries in InteliJ (java) and 1GB+ ram usage.
        
             | api wrote:
             | IntelliJ is a lot more than a GUI. There's a ton of
             | language modeling and parsing and lookup stuff going on in
             | there. It has tons and tons of features too.
             | 
             | Electron is hundreds of megabytes for "hello world."
        
       | thibaut_barrere wrote:
       | It is pretty cool! I would love to use that for audio programming
       | GUI.
        
       | lsllc wrote:
       | Previous discussion (April 2020):
       | 
       | https://news.ycombinator.com/item?id=22766639
        
       | z3ugma wrote:
       | The more I use Elm; and the more I look at other reactive
       | frontends like React+Redux and Vue, the more I love thinking in
       | The Elm Architecture (https://guide.elm-lang.org/architecture/)
       | aka Model-View-Update as a pattern for GUI development.
       | 
       | To wit: Here's a way to implement it with Python and Tkinter for
       | an old school reactive GUI.
       | 
       | https://maldus512.medium.com/how-to-setup-correctly-an-appli...
        
         | goostavos wrote:
         | For Python + WX, there's also re-wx[0] (shameless self-
         | promotion)!
         | 
         | I wanted React with Elm-like architectures in WX enough that I
         | got annoyed and built one ^_^
         | 
         | [0] https://github.com/chriskiehl/re-wx
        
         | patwoz wrote:
         | Can someone explain the difference of redux to elm? I don't see
         | a difference on the first look. I'm a React/Redux Developer.
        
           | sli wrote:
           | Quickly? Redux is a state container that supports Flux
           | actions and Elm is a language with a companion architecture
           | that's recommended. The comparison would be between Elm and
           | Javascript/Typescript+React+Redux, as it provides the ability
           | to implement those featuresets out of the box, including
           | Messages, which is the TEA answer to Redux and Flux actions
           | (more or less).
           | 
           | Personally, I find working with Elm's state management
           | features is like heaven compared to dealing with
           | Redux+Typescript's intensely noisy types.
        
             | scns wrote:
             | TEA was the inspiration for Flux/Redux IIRC.
        
             | seanwilson wrote:
             | > compared to dealing with Redux+Typescript's intensely
             | noisy types.
             | 
             | Anybody have any experience on how this compares to
             | ReasonML + React?
        
           | tmountain wrote:
           | They're really similar. Elm works hard to abstract away the
           | JavaScript universe and create really clearly defined borders
           | regarding being inisde Elm land or outside of Elm land.
           | Specifically, interacting with external libs, etc. involves
           | retrofitting them to work via a port, which lets side effecty
           | stuff come in as a standard message without having to deviate
           | from the basic design. Redux may do something similar (I
           | forget), but the gist of what I'm saying is that Elm works
           | really hard to adhere to its core primitives to limit
           | cognitive overhead for most tasks.
        
           | mejutoco wrote:
           | Redux is to React what the 'update' function is to Elm
           | architecture (first code example in the following link)
           | 
           | https://guide.elm-lang.org/
           | 
           | Answering your question, the difference is Elm has a more
           | expressive type system than javascript, and will catch a lot
           | of errors for you, with excellent error reporting from the
           | compiler.
           | 
           | The layout of the code becomes less important, because the
           | compiler will catch most errors (actually recommended in elm
           | guides not to split in too many files until overwhelmingly
           | necessary)
        
         | Narice wrote:
         | Elm is awesome! I would really like an equivalent for
         | software/game dev
        
           | S04dKHzrKT wrote:
           | The Nu game engine might interest you. There's also FuncUI
           | for app dev which is F# + MVU running on Avalonia.
           | 
           | https://github.com/bryanedds/Nu
           | 
           | https://github.com/fsprojects/Avalonia.FuncUI
        
           | axelroze wrote:
           | The Elm Architecture is not that super novel. Actually it
           | came from game development from the Components way of
           | thinking. Take a look at this book. It's a classic for
           | gamedev: - https://gameprogrammingpatterns.com/
        
           | tempest_ wrote:
           | The language itself seems interesting but from the outside
           | looking in it appears a bit stagnant.
           | 
           | Is the community active at all in 2021 or is it just the
           | result of having basically one person working on the
           | language?
        
             | sdeframond wrote:
             | I would say it is quite active, although still small.
             | 
             | I think there is a slow shift toward community built tools
             | such as lambdera. The language itself is pretty stable (and
             | good, IMHO).
             | 
             | Most of the news are available on the discourse
             | discourse.elm-lang.org
        
             | 1-more wrote:
             | check out the elm slack! Very active, but that's behind a
             | signup wall so that's ahrd to see from the outside.
             | https://elmlang.herokuapp.com
        
             | G4BB3R wrote:
             | Elm seems stagnant because Evan is not so transparent and
             | prefer work in a private branch and to release work in
             | batches instead of having a release every 6 months, this
             | makes people think it is dead. Elm is still being used in
             | production by dozens of companies with huge codebases
             | (100k~400kloc), and the community is very active, there are
             | amazing projects like elm-pages, elm-review, elm-ui (from
             | mdgriffith), elm-spa, elm-charts, lamdera and others.
        
             | z3ugma wrote:
             | Most of the activity happens in the (public) Elm Slack
             | community, so it's not indexed in search engines and hard
             | to find in StackOverflow, but it's a really effective place
             | to get advice and help with a problem in a more personal
             | way
        
         | figbert wrote:
         | I had my first encounter with The Elm Architecture through the
         | Go Bubble Tea library
         | (https://github.com/charmbracelet/bubbletea). What a
         | revelation. Such a drastically different way of thinking about
         | UI.
        
         | ptx wrote:
         | Hmm, I'm not so sure that Tkinter example really solves the
         | problem of performing background work without blocking the UI.
         | Sure, the UI thread doesn't block, but instead the UI state (as
         | the user continues interacting with it) can drift out of sync
         | with the model when the controller thread is busy with other
         | work.
         | 
         | The real issue in that example seems to be that the event loop
         | needs to wait for both UI events and read/write readyness on
         | the serial port. This could probably be handled either with
         | createfilehandler[1] (although it doesn't work on Windows) or
         | by dedicating a thread to handling the serial port and posting
         | messages to the Tkinter event loop as suggested at the end.
         | 
         | [1] https://docs.python.org/3/library/tkinter.html#file-
         | handlers
        
           | z3ugma wrote:
           | I think your last suggestion is dead on - think about the
           | browser event loop where Messages can be triggered all the
           | time from clicks, hovers etc. If you have 4 threads and all
           | those threads are pushing Messages then the update thread
           | only has to push the state change notifications and doesn't
           | have to do much blocking of its own
        
       | conradev wrote:
       | Does this use the text input stack provided by the platforms? Or
       | is it parsing raw keyboard events?
       | 
       | I only ask because if it doesn't use platform text input, that is
       | a non-starter for mobile.
       | 
       | It also would mean having to reimplement platform behavior for
       | text input, like being able to hold Shift on macOS while moving
       | the cursor to change text selection.
        
         | ensiferum wrote:
         | Why would a widget library need to deal with input stack
         | directly? For portability it'd provide an API where the caller
         | will dispatch abstract events such as mouse events and keyboard
         | events and already translated character events.
        
           | cmrdporcupine wrote:
           | If you think it's easy to make an abstraction around keyboard
           | events, stroll through the Chromium and Blink source tree
           | some time and try to understand all the nuances.
           | 
           | Keyboard and key event input is much harder than it first
           | appears. From multiple platforms to multiple languages to
           | multiple keyboard interface devices to multiple layouts, and
           | you cannot assume that the operating system provides a
           | workable abstraction on its own.
        
             | ensiferum wrote:
             | Not sure if that's an apples to apples comparison.
             | Generally speaking a widget library should be able to
             | provide and interface for taking the keyboard input. It
             | doesn't need to interface with the OS for this. The caller
             | does and uses for example an IME or the native OS API to
             | receive the os level input. I have in fact written widget
             | libraries this way. Just wondering if I didn't hit some ude
             | case that would require the widget to rely on some input
             | system directly.
        
         | athrowaway3z wrote:
         | Not a direct answer but a good read/overview.
         | 
         | https://www.cmyr.net/blog/rust-gui-infra.html and the precursor
         | https://www.cmyr.net/blog/gui-framework-ingredients.html
        
         | ericls wrote:
         | This is an important point for me as well. Not sure on other
         | platforms, but on web, it does support composition.
        
           | conradev wrote:
           | Yes! This is because web browsers use the platform text input
           | stack
           | 
           | Browsers are actually a great example of my favorite approach
           | to cross-platform UI, because they sprinkle platform-native
           | widgets throughout the canvas that they render, controlled by
           | a platform-agnostic programming language. Which reminds me
           | that people were trying to use webrender[1] to build native
           | apps in Rust.
           | 
           | [1] https://github.com/servo/webrender
        
         | arghwhat wrote:
         | Not using appropriate text input integration is a no-go in any
         | platform, be it mobile or desktop.
         | 
         | Self-implemented keyboard input pretty much only works for the
         | simplest use case in english-native countries.
        
       | est31 wrote:
       | See also: sixtyfps, which has been started by two KDE
       | contributors. https://github.com/sixtyfpsui/sixtyfps
       | 
       | https://news.ycombinator.com/item?id=26958154
       | 
       | https://news.ycombinator.com/item?id=24919571
       | 
       | It's great to see GUI frameworks being designed in Rust,
       | countering the trend of doing everything in Electron.
        
         | ComputerGuru wrote:
         | sixtyfps is licensed under the GPL, so it's icky for anyone
         | that isn't developing a GPL app and doesn't want to or can't
         | shell out for the commercial license. Iced is licensed under
         | the MIT license.
        
           | infogulch wrote:
           | It looks like there are actually 3 different pricing/license
           | options. https://sixtyfps.io/#offering
           | 
           | - GPLv3 - free
           | 
           | - "Ambassador" - free commercial license (after approval), in
           | exchange for marketing as being built with sixtyfps and
           | authorization to use your logo and feedback
           | 
           | - Normal commercial - paid
           | 
           | I kinda like the addition of the "Ambassador" tier. Seems
           | like a fair exchange for an in-development framework, and
           | would be a good option for people that are building a new
           | product and don't yet have the revenue to justify the cost
           | during the prototyping phase.
        
             | ComputerGuru wrote:
             | I wasn't aware of the "Ambassador" option and that changes
             | the calculus for deciding between the different frameworks
             | on the basis of the license, although the opaque "after
             | approval" could mean anything and tbh gives me pause.
             | Thanks for enlightening me.
             | 
             | For the record, the rust community has mostly settled
             | around dual-licensing under MIT/Apache for what you can
             | call "foundational" crates ("libraries"), which are both
             | far more liberal than the GPL.
        
               | riquito wrote:
               | > For the record, the rust community has mostly settled
               | around dual-licensing under MIT/Apache for what you can
               | call "foundational" crates ("libraries")
               | 
               | That's just your opinion, there's no such thing as a
               | blessed license scheme by the community. GPL is a
               | perfectly valid choice if you feel like it
        
           | ruined wrote:
           | sixtyfps is dual-license. you can contact them and negotiate
           | a license for commercial use. i think this is a better scheme
           | than straight mit which accommodates no demand for financial
           | support to the developers.
        
         | adamnemecek wrote:
         | You should also check out the femtovg project, a 2D rendering
         | API that sixtyfps relies on.
         | 
         | https://github.com/femtovg/femtovg
         | 
         | It's a decent starting point for trying to build your own
         | toolkit.
         | 
         | I have recently added a wgpu backend but for now it lives in my
         | fork https://github.com/adamnemecek/femtovg
         | 
         | run the demo with `cargo run --example wgpu_demo --release`.
         | 
         | Also join the femtovg discord https://discord.gg/V69VdVu
        
       | api wrote:
       | Looks nice, but like almost all promising new UI toolkits
       | accessibility is not even mentioned.
        
         | zellyn wrote:
         | I think everyone is waiting for AccessKit to be ready...
        
           | mwcampbell wrote:
           | Sorry folks, that's not my day job, and I haven't had much
           | energy lately to work on it on the side.
        
             | rauljara wrote:
             | Thanks for the work you did do!
             | 
             | It's out there, so whether you finish it, someone forks it,
             | or it just serves as inspiration for another project,
             | you've contributed.
        
           | paulgb wrote:
           | For those (like me) just hearing about AccessKit, I assume
           | it's this: https://github.com/AccessKit/accesskit
           | 
           | Neat! I really like the Rust ethos of creating modular cross-
           | platform adopters (e.g. winit, getrandom), and from a brief
           | skim this seems to fit that model.
        
           | jamil7 wrote:
           | Very cool, didn't know about AccessKit.
        
         | slingnow wrote:
         | It's almost like they want to make sure it works for the vast
         | majority of people before they spend time and effort making it
         | work for a much smaller segment of their userbase.
        
           | b3morales wrote:
           | Accessibility is not a bolt-on extra feature, it's core to
           | being able to make a product that suits all your users.
           | Everyone needs, or will need, accommodation sometimes.
           | 
           | When you have an accident waterskiing and end up on crutches,
           | you'll be glad for the accessibilty of doors that open with a
           | button press. When you poke your eye hiking and need to wear
           | an eyepatch for a few weeks, a screen reader might not seem
           | such a niche use case.
           | 
           | These are even kind of extreme examples: frankly, even stuff
           | like dark mode that we take for granted at this point is an
           | accommodation to how some people need or want to use their
           | computers. Migraines are a good example of an (astonishingly)
           | common condition that benefits from flexibility around having
           | to stare at a screen.
           | 
           | None of us gets younger as the days go by, either, and that
           | comes with changed needs. I'm still thirty years from
           | retirement and I find that the 10 point font I used to prefer
           | isn't good enough anymore. Bumping up text size is a
           | quotidian action for me and millions of other people.
           | 
           | ADDITION: Ah, finally found the quote I was looking for.
           | Maybe not directly relevant, but thought-provoking:
           | 
           | > SMS texting was invented [to] figure out a way for deaf
           | people to communicate with one another without speaking. ...
           | Now text messages are universal.
           | 
           | https://blog.ai-media.tv/blog/why-designing-for-
           | accessibilit...
        
           | scns wrote:
           | One blind programmer has worked on the Rust compiler.
           | Indirectly he is making a library like this possible. Should
           | we leave him out, because he is a minority?
        
           | ZenPsycho wrote:
           | so they should tackle accessibility (20%) before mac (8%) and
           | linux (2%) support
        
             | nybble41 wrote:
             | The odds are good that the fraction of this project's user
             | base--developers writing GUI applications in Rust--who
             | would be interested in Linux support is much more than 2%.
        
               | ZenPsycho wrote:
               | i thonk you've forgotten what the point of developing
               | software is
        
         | ginko wrote:
         | People keep bringing up accessibility whenever UI toolkits are
         | mentioned, but wouldn't it be simpler to just have a CLI
         | interface for whatever your program is doing?
        
           | yoz-y wrote:
           | Depends, accessibility is a spectrum. Most people don't need
           | a fully voice/gesture based interface but can get by with
           | good contrast controls and font sizing (as in, the fonts need
           | to be able to get huge). Accessibility is also being able to
           | use the interface only with a keyboard, or only with a mouse
           | or specialized controller with 2 buttons.
        
           | pqb wrote:
           | Funny you mention that, it reminds the post I have read few
           | seconds ago: https://news.ycombinator.com/item?id=26224197
           | 
           | I am person, who in last few days tried out to use VoiceOver
           | and move responsibility on it to navigate me and read
           | contents, when I could code while I had closed eyes.
           | Ironically the most annoying interface was CLI, because I had
           | to extend my focus on contents of the terminal. Imagine
           | running docker-compose up and you are going to spammed with
           | reading all logs. Next, usually I had problem to find some
           | relative point that I could mark a "milestone" in my head,
           | which will be further point from I will be reading.
           | 
           | Also, not all commands are read after executing them. Such
           | command is silly pwd. Everytime I write it down I had to move
           | the VO cursor to read the contents. Also many characters I
           | would recognize as a programmer VO reads differently. Nano
           | editor was complete unusable for me. While in vim I had
           | notable problem to recognize indentations characters
           | (sometimes they are read and sometimes they don't) and to
           | know in what mode am I actually. brew update+upgrade was a
           | nightmare for me. All kind of separators like #### are read
           | as "number", "number" spam. The same situation was with
           | "clear" command. It was read a hundreds of "space", "space",
           | "space"... I was starting to think I am going to the Moon or
           | I play Portal 2 [0].
           | 
           | I could continue writing down my disappointment about the CLI
           | interface that was among my favorites in past but now after
           | this week with VoiceOver I think it is terrible to be blind,
           | because most of time I had to use my eyes to help myself to
           | recognize where I am and what I need to click to move to next
           | element. I was very surprised by the rofi-like find of
           | elements that are on the screen (named as Rotor feature,
           | CapsLock+U). With VO I don't any longer needed to use mouse,
           | which for anybody who has problem with wrists is also a nice
           | thing to consider.
           | 
           | [0]: https://www.youtube.com/watch?v=NiaxOkyKbDI
        
           | dagmx wrote:
           | How would that work for something that needs to display an
           | image or other media?
        
         | clarkmoody wrote:
         | That's right. Accessibility is one of the last things to figure
         | out after all of the other tricky things: proper event handling
         | for sane keyboard navigation, efficient layer clipping /
         | redraw, advanced text layout / style, animations, expanded
         | compatibility across platforms, etc, etc.
         | 
         | And then accessibility brings with it the integration with
         | different OSes via disparate APIs, so it will take some effort
         | to offer a cross-platform API to the library user.
         | 
         | You'll notice that Iced is not >= 1.0 yet, so you shouldn't
         | expect it to be fully-baked.
        
           | resoluteteeth wrote:
           | On the one hand that's understandable, but on the other hand
           | it appears to be almost 2 years old already and if people
           | start to actually use it in its current state the lack of
           | accessibility will become problematic.
        
           | marcellus23 wrote:
           | Accessibility seems like the kind of thing that would need to
           | be baked-in from the start right? Bolting on accessibility
           | after everything else has already been built seems like a
           | recipe for a half-assed solution.
        
             | clarkmoody wrote:
             | Luckily large refactors are relatively painless in Rust.
        
       ___________________________________________________________________
       (page generated 2021-08-27 23:00 UTC)