UIs have long been known to be a perfect fit for actor systems. Think about it–every part of the UI needs to be independent and responsive to events, while also being able to recover from errors. This is a nearly perfect use-case for actors. Elixir’s Phoenix LiveView system is a great proof of this but even way back when Joe Armstrong made an Erlang wrapper for the X Window System that showed the potential of this model for a perfect fit: https://erlang.org/workshop/2004/ex11.pdf
what @yawaramin said + I find it a lot easier to think in actors
currently minttea is structured with 3 processes that can parallelly do output (rendering), input, and the program update cycle.
but larger applications can be decomposed so that subsections are processes on their own, and then a “compositor” process stitches them together.
using riot its also super easy to spin up other supervision trees of work that have their own failure mode, so they won’t take the UI down if they fail for whatever reason, while still being able to communicate with them via message passing (tho this is in a PR right now).
Mint Tea looks very cool! I’m pretty impressed by what I’ve seen in the examples.
Somewhat relatedly, there was a GUI toolkit for Standard ML called eXene back in 1991 which used Concurrent ML as its basis similarly to how this one uses actors. So building user interfaces as a “distributed system” is definitely not unheard of.
Even though this function does not take any optional arguments now, it will be easier to add them in the future by requiring a positional ‘unit’ argument now. The change will be source-code compatible with existing code.
this. Just making room for myself to add more things without breaking all the examples/apps. Generally speaking i find that using a unit gives me a little room play with the API.
Good feedback I’m not much of an Elmer myself and this is how i was using the pattern in BubbleTea from Go. If this is more natural then we can definitely fix this in the next version. If you’re interested, PRs are welcome!
Some initial models can be expensive to create, so allowing delayed execution is imo a Good Thing
Ah I see. I tend to associate functions requiring a unit to functions generating a side-effect so that’s why I got confused.
Cool I’ll have to play with the lib for real to give better feedback.
In Elm, the init function has the same return type than the update function so that makes the API “symmetric” for lack of a better word. That allows you to reset your state by just recalling your init function within your update for instance. But that may not make sens in the absence of a customizable msg/event type
You got me thinking about this and I updated this API to be just one function:
val init : 'model -> Command.t
So that you can build the app, and when you call Minttea.start you can pass in the initial state:
Minttea.start app ~initial_model
This felt the cleanest since you don’t have to hardcode your initial state, and you can start your app in different states.
Considering I’d like to integrate MintTea into existing apps, this is useful in at least 2 ways:
You can parse CLI args before starting the app, and set the model to something specific based on that. For example, you could use cmdliner to do the initial argument parsing and have it build the initial state of your app before calling Minttea.start.
You can recreate specific test scenarios by just starting at the right state
This has been working alright in the new examples I’ve been building, but I very much welcome your opinions/critiques!
Also a side-note if you’re gonna pin from the repo, you’ll also need to pin down the latest tty and colors. They should both land on opam soon tho.
Oh forgot to say that since a Mint Tea app is just a Riot app, we can send Riot messages to it, and they’ll be sent into the main update loop as custom events:
type Message.t + = Custom_event
let update e m =
match e with
| Event.KeyDown Space ->
send (self ()) Custom_event;
| Event.Custom Custom_event -> (* ... *)
(* ... *)
We haven’t yet integrated this nicely with a command like Command.Message Custom_event, but it’s only a matter of time. I’m not a fan of leaking the Riot primitives like self () or send here.