# Live Reloading GUI From Scratch

**URL:** <https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569>\
**Category:** Links\
**Created:** [May 15, 2024, 2:33pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569 "2024-05-15T14:33:18Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![tristanC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tristanc/32/827_2.png) [@tristanC](https://discourse.haskell.org/u/tristanC)\
**Post date:** [May 15, 2024, 2:33pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/1 "2024-05-15T14:33:18Z")

</div>

Here’s a tutorial on using ghcid to live reload a dear-imgui application. This post also introduces how to use the upcoming cabal 3.12 multi-repl feature to reload the executable while working on the library:

> **[Live Reloading Haskell GUI From Scratch](https://tristancacqueray.github.io/blog/live-reloading-haskell-gui-from-scratch#)**
>
> This post shows how to setup a live reloading workflow to develop graphical user interfaces (GUI) with Haskell on Fedora Linux from scratch. This post demonstrates how to create a developer environment with a blazingly fast and flexible feedback loop...

---

<div class="post-metadata">

**Author:** ![Ambrose](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/ambrose/32/5672_2.png) [@Ambrose](https://discourse.haskell.org/u/Ambrose)\
**Post date:** [May 15, 2024, 2:55pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/2 "2024-05-15T14:55:20Z")

</div>

Very cool!

> I believe the killer feature is the REPL interpreted mode which lets you run the code without linking, which is often the slowest part of a live reload workflow. For example, even with all the tweaks prescribed in the Bevy Rust engine [compile optimizations doc](https://bevyengine.org/learn/quick-start/getting-started/setup/#compile-with-performance-optimizations), including using the new mold linker, I couldn’t make my toy [moonracer](https://github.com/TristanCacqueray/bevy-moonracer) game reload in less than a few seconds.

I 100% agree. `ghci` is a top reason why I continue to use Haskell for gamedev and consider languages such as Rust to be insufficient.

Speaking from gamedev experience, you can probably take the hot reloading even further. For instance:

1. You can re-use the existing window handle by storing it with `foreign-store`.
2. Dunno if imgui could do this, but you can spin up your app in an OS thread and have it listen on an `MVar` for _an entire app loop_. Stuff that `MVar` in a `foreign-store` and then on reload, pass in the newly-loaded app loop. Depending on how your state & loop is managed, you can have new code operate on pre-existing state. No need to bounce `main`! I’ve done this with games and `apecs` and it’s pretty cool.
3. You can also use the `MVar` approach to make `ghci` your development console - have your app loop listen to an `MVar` that has effects in it and execute them. You can even have it pass results back with some `Dynamic` magic - [[example code]](https://gist.github.com/ramirez7/f1309264e58aa31f12be3532d43f3d09). I banged my head against the wall trying to add a “dev console” using a hand-rolled interpreter for a while. And then I tried `hint`. But then it dawned on me that `ghci` was all you need.

[Here’s an example `Main.hs` using these techniques.](https://gitlab.com/macaroni.dev/mayhem-engine/-/blob/31c7be62bbfa3dd9d523ff06779c3fa9f0ebef70/games/ld/55/LD55/Main.hs)

---

<div class="post-metadata">

**Author:** ![tristanC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tristanc/32/827_2.png) [@tristanC](https://discourse.haskell.org/u/tristanC)\
**Post date:** [May 15, 2024, 5:29pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/3 "2024-05-15T17:29:27Z")

</div>

Thank you @Ambrose for such great feedback! I initially meant to write a response to the loglog post about [leaving rust gamedev](https://loglog.games/blog/leaving-rust-gamedev/) by explaining how their arguments do not match the user experience I get with Haskell. Though this quickly got unwieldy and I decided to focus on showing the feedback loop instead. I am glad to hear I’m not the only one using Haskell for that particular capability 🙂

Now am I thinking about writing a few more parts such as using an IDE with HLS (import completion, go to definition, …), hot reload as you suggested with `foreign-store` or [essence-of-live-coding](https://hackage.haskell.org/package/essence-of-live-coding) and perhaps finish with binary distribution.

Though I’m also trying to keep this guide as simple as possible so that new comers can give it a try without much complications.

Thank you for your work on macaroni and the mayhem-engine, I’m looking forward your next release!

---

<div class="post-metadata">

**Author:** ![tonyalaribe](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tonyalaribe/32/2681_2.png) [@tonyalaribe](https://discourse.haskell.org/u/tonyalaribe)\
**Post date:** [May 15, 2024, 8:14pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/4 "2024-05-15T20:14:27Z")

</div>

I wonder if any of these live reload strategies eg foreignstore could work in a Servant web backend?

My dev workflow would greatly benefit from being able to make lucid html changes and instantly refreshing the browser to see the changes.

---

<div class="post-metadata">

**Author:** ![tristanC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tristanc/32/827_2.png) [@tristanC](https://discourse.haskell.org/u/tristanC)\
**Post date:** [May 15, 2024, 8:46pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/5 "2024-05-15T20:46:23Z")

</div>

For WebUI, you can get live reload by opening a websocket and calling `window.location.reload()` in the javascript reconnection handler, that way, when your backend restart, the web client can automatically refresh the page. Here is an example with htmx: [demo-websockets](https://github.com/TristanCacqueray/haskell-xstatic/blob/5c84c9106b0c0fe0e25fcd7d74da05046d84bbad/demo-websockets-ki-htmx/Server.hs#L185-L189), and L140 for the setup.

---

<div class="post-metadata">

**Author:** ![romes](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/romes/32/2912_2.png) [@romes](https://discourse.haskell.org/u/romes)\
**Post date:** [May 17, 2024, 5:56am UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/6 "2024-05-17T05:56:41Z")

</div>

A note from my experiments here:

Some context window creation library like `GLFW` require the program to be run from the main thread, but GHCi can launch your program in a fresh unbounded thread. In any case, the workaround is

```haskell
:set -fno-ghci-sandbox

```

before running Main, to force computations to be run in the main thread rather than in a forked thread.

---

<div class="post-metadata">

**Author:** ![chrisdone](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/chrisdone/32/1408_2.png) [@chrisdone](https://discourse.haskell.org/u/chrisdone)\
**Post date:** [May 17, 2024, 9:05pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/7 "2024-05-17T21:05:31Z")

</div>

I should note that for **10 years** foreign-store has remained the same with no commits, with a terrible segfaulty bug that nobody noticed was there, until a few months ago when Johannes Gerer fixed it: [GHC segfaults (aka "The perils of using a non memory safe language") · Issue #4 · esoeylemez/foreign-store · GitHub](https://github.com/esoeylemez/foreign-store/issues/4)

So if you tried foreign-store in the past and experienced segfaults, it might be fixed now.

---

<div class="post-metadata">

**Author:** ![tristanC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tristanc/32/827_2.png) [@tristanC](https://discourse.haskell.org/u/tristanC)\
**Post date:** [May 17, 2024, 9:19pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/8 "2024-05-17T21:19:24Z")

</div>

I just gave `foreign-store` a try and it worked really well for this use case, thanks you @chrisdone! I asked a question to improve the ergonomics with ghcid: [How to check if a global store is initialized · Issue #6 · esoeylemez/foreign-store · GitHub](https://github.com/esoeylemez/foreign-store/issues/6) .

It looks like a great workflow for persisting the window across reload (and avoid loosing the focus on the IDE), and I’m now tempted to propose simple wrappers for sdl, glfw and gloss to handle the hot reload.

---

<div class="post-metadata">

**Author:** ![tristanC](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tristanc/32/827_2.png) [@tristanC](https://discourse.haskell.org/u/tristanC)\
**Post date:** [May 17, 2024, 9:52pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/9 "2024-05-17T21:52:06Z")

</div>

I should note that I’m also using [pulse-simple](https://hackage.haskell.org/package/pulse-simple) to submit audio buffers near real-time (30 times per second), the library was last uploaded **13 years** ago, and it still works fine with ghc-9.6. Makes me wonder what is the oldest package still working today 🙂 As far as I can tell, Haskell is remarkably stable!

---

<div class="post-metadata">

**Author:** ![danidiaz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/danidiaz/32/92_2.png) [@danidiaz](https://discourse.haskell.org/u/danidiaz)\
**Post date:** [May 18, 2024, 9:26am UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/10 "2024-05-18T09:26:44Z")

</div>

IIUC, when performing a reload in ghci the REPL bindings are lost, but any already started thread will keep chugging along, still running the old code?

I wonder if we could harness that to create an alternative to [foreign-store](https://hackage.haskell.org/package/foreign-store) which, instead of FFI, used helper threads to store values that could later be queried using asynchronous exceptions. I tried that in [this repo](https://github.com/danidiaz/unfazed); it’s very hacky but it kinda seems to work.

Perhaps some form of binding persistence functionality should be integrated in the `:reload` command itself. 🤔 Seems like a useful feature, despite the dangers.

---

<div class="post-metadata">

**Author:** ![chrisdone](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/chrisdone/32/1408_2.png) [@chrisdone](https://discourse.haskell.org/u/chrisdone)\
**Post date:** [May 18, 2024, 2:58pm UTC](https://discourse.haskell.org/t/live-reloading-gui-from-scratch/9569/11 "2024-05-18T14:58:57Z")

</div>

Does this mean all the threads of your program need to be aware of receiving this exception? Oh, nope, you’re using labelThread to identify the participating threads, even if it is O(n). Both listThreads and labelThread are opening up interesting possibilities!

Another use case that springs to mind would be a chaos monkey style thread killer, which would highlight how robust your thread supervisors are.
