Stream: ideas

Topic: Roc GUI architecture idea


view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 15:04):

I just wanted to get it out of my system: https://gist.github.com/qrzychu/300ba12c775e4354d1f61d0e4420a711

Basically I think Roc will be great for building native GUI apps, and I cannot stop trying to figure out how it could look like. I definetely don't have time to work on it, but I wanted to share my idea.

TLDR: it's Elm, but multiple Elm-loops in one app (they are just actors) + Rx for subsciptions to events, state changes etc

I think it's pretty cool :)

view this post on Zulip Notification Bot (Feb 05 2025 at 15:17):

Karl has marked this topic as resolved.

view this post on Zulip Karl (Feb 05 2025 at 15:17):

sorry about the misclick

view this post on Zulip Notification Bot (Feb 05 2025 at 15:17):

Karl has marked this topic as unresolved.

view this post on Zulip Karl (Feb 05 2025 at 15:41):

I don't disagree about the Elm Architecture+Actor thing but it's not clear to me how Rx would need to fit in. I played around with cyclejs back in the day and never felt like the Rx primitives were a real win outside tightly coordinated async workflows. Those do exist and Rx is really great for it but they're not the norm.

I have thought about doing GUI and I'm specifically interested in UI for my Supernote A6X2 since I want an app for training handwriting and shorthand but the processor is pretty heavily underpowered so the normal Android stack has unacceptable lag (hundreds of ms). Since I'm not in any particular hurry on this it's been pretty yak shaving but I do (finally) have the egui Rust app running on android under NDK.

I'm less specifically concerned about architecture since I assumed the Roc part would be vdom construction and event handlers with the platform handling the event loop. I'm more concerned about not boiling the ocean with trying to avoid the digression of writing a layout and widget system from scratch. The Rust ecoysystem has layout covered (Taffy) but widget options are sparse. My widget needs are light so it seems like egui could be it.

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 15:52):

Rx is for fine-grained reactivty - in C# and Avalonia I use it all the time.

It opens a whole plane of possibillities. For example, you want to display a message after user fails to log in 3 times?

LoginCommand.Where(x => !x.Success)
    .Skip(2).Take(1) // third item
    .Do(_ => ShowForgotPasswordPrompt())
    .Retry() // resubsribe when done
    .Subscribe()
    .DisposeWith(navigatedAway); // cancel on success login, navigating away

It can also beat computed properties in performance by recalculating only things that actually changed. With reactivity model like this you don't really need a vritual DOM - it's closer to Vue.js/ Svelte Runes

view this post on Zulip Karl (Feb 05 2025 at 16:00):

My issue with signal systems in a functional language is that signals are inherently mutation based. You can conceptually model it as a whole chain of actors sending messages but then you need some way to coordinate a bunch of actors. The vdom model is inherently functional and performance of the approach should be more than adequate even on the slow processors I'm targeting.

view this post on Zulip Karl (Feb 05 2025 at 16:02):

In most languages I do prefer dataflow/signals approaches. It's just pure functional that I prefer vdom.

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:06):

I actually think that signals are really functional if the only thing they can do is to publish a message to the actor

In the example above instead of Do(.... it would be .Send(actorAddress, ShowForgotPasswordPrompt)

The actor would get the message, update it's state, publish StateChanged event, and then only the bits of the UI that have subscription to that_actor.state_changed.filter(.forgot_password_prompt_visible) (or whatever the current Roc syntax is) would get redrawn

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:08):

even with Akka.NET you can get thousands of actors to run on a signle CPU core, and it's fine

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:13):

even for handwriting you can do something like:

PenDown.Select(_ =>
      PenMoved
         .TakeUntil(PenUp) // I know this is a simplification :)
         .Where( penPositions => IsLetterA(penPositions))
        .Do(_ => Show("Congrats, you drew a letter A!")
   )// handle all the subscriptions

You can make the above async easily (at least in C# :)) - once it clicks, it's really powerfull. The above example could be reworked to the pen positions be aggregated until a letter is recognized, or a certain time passes after PenUp - whatever, still would be just couple lines of code

view this post on Zulip Karl (Feb 05 2025 at 16:14):

I would argue that starting with state and ends with ends with firing effects is pretty deeply non-functional. Sure, derived signals are pure unless you hate yourself but there's non-pure stuff on both ends.

view this post on Zulip Karl (Feb 05 2025 at 16:16):

I've written plenty of Rx code. I've used both approaches professionally. Signals and vdom are both architecturally valid choices and there's plenty of evidence in js land that both approaches work and can deliver similar performance when optimized. I simply prefer vdom in a functional language where the non-functional part happens in the parts between the functional slices.

view this post on Zulip Karl (Feb 05 2025 at 16:20):

I'll chip in that my preferred js framework is Solid. I'm not particularly dogmatic about either approach. I've done both approaches in clojurescript and I prefer vdom for functional languages.

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:25):

I see signals as messages in this case. It's just one more way to trigger the update function in Elm :) Elm even has subscriptions, it's just for "external" things.

The idea is that other actors (like a sub-page or a global store) are those external things. That's it - no mutation at all.

For UI rendering it allows for push to update over pull to update - the whole JS land is switching to signals for a reason :)

and Solid is a solid choice :D

view this post on Zulip Karl (Feb 05 2025 at 16:48):

I think our disagreement is that you consider actors functional and I consider them non-functional. They exist in functional languages because the world isn't pure but the mailbox (or whatever you want to call the storage an actor is built around) is clearly state and I consider effects to be stateful in practice because order matters for real uses. I think that functional programming is about the avoidance of state so actors are fine but at the edges of the system and not in the internals.

If you're arguing that the main elm loop is an actor and that's the granularity of the actors we're talking about then we're in violent agreement. The elm loop has one big pool of state at the top and a vdom architecture elsewhere. That's the approach I'm expecting here and if there's more than one actor at the top then I have no problem with this. My impression from your other stuff is that you're thinking more like the Svelte5/Vue/Solid where components have their own signals and that's the kind of architectural decision that I'm opposed to in a functional language. I'm being insistent because I have actually tried it (Javelin in cljs).

view this post on Zulip Karl (Feb 05 2025 at 16:51):

Javascript frameworks are generally moving to signals because signals are a better fit for JS. I approve of the trend there. I've found that the approach works notably better in teams of mixed skill levels. I spent a lot of my career cleaning up React apps with performance problems because people didn't grok the model.

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:53):

yeah, actor model itself is state-full, but as long as the exposed api is pure functional it doesn't matter - just like Roc does in-place mutation as optimization. It doesn't make the language less "pure"

and yes, the idea is just "multiple elm loops in one app"

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:54):

however, wheter it's a virtual DOM or fine grained subscriptions to state change for the UI, I don't really care at this point

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 16:56):

like I said, it's just an idea for now :)

view this post on Zulip Krzysztof Skowronek (Feb 05 2025 at 17:04):

I will try to write up a sample code repo later, maybe it will show what I mean a bit easier


Last updated: Jun 16 2026 at 16:19 UTC