|
|
|
|
|
by d12frosted
150 days ago
|
|
Good points, thanks for engaging thoughtfully. On vui.el's approach - yes, the blessing is that widget.el is simple enough to build on. It does the "rendering" and some "behaviour", vui.el handles the rest. On ECS vs OO - I'll admit I don't have enough experience to speak about UI paradigms in general. But my critique of widget.el is that inheritance hierarchies don't compose well when you need orthogonal behaviors. Composition feels more natural to me - could be just how my brain works, but it scales better in my experience. On state management being independent - I'd be curious to hear more. Pathom is interesting for data-driven architectures. vui.el's state is intentionally minimal and Emacs-native, but you're right it could potentially be decoupled further. On "why not full reactive" - to clarify what vui.el has: React-style hooks with explicit dependency tracking (vui-use-effect, vui-use-memo, etc.), state changes trigger re-renders, batching for multiple updates. What it doesn't have: automatic dependency inference or fine-grained reactivity where only specific widgets update. The tradeoff was debuggability - explicit deps are easier to trace than magic. But I'm open to being wrong here. What would you want from a reactive layer? |
|
> Pathom is interesting for data-driven architectures. vui.el's state is intentionally minimal and Emacs-native, but you're right it could potentially be decoupled further.
I'll be honest, I haven't yet written a Pathom-backed GUI. But I'm hoping to experiment with this in the coming weeks :)) cljfx is structured in such a way that you can either use the provided subscription system or you can roll your own.
> What it doesn't have: automatic dependency inference or fine-grained reactivity where only specific widgets update
So all the derived states are recalculated? Probably in the 95% case this i fine
In the big picture I enjoyed the cljfx subscription system so much, that I'd like to use a "reactive layer" at the REPL and in general applications. You update some input and only the parts that are relevant get updated. With a subscription-style system the downside is that the code is effectively "instrumented" with subscription calls to the state. You aren't left with easily testable function calls and it's a bit uglier.
Pathom kind of solves this and introduces several awesome additional features. Now your "resolvers" can behave like dumb functions that take a map-of-input and return a map-of-output. They're nicer to play with at the REP and are more idiomatic Clojure. On top of that your code turns in to pipelines that can be injected in to at any point (so the API becomes a lot more flexible). And finally, the resolvers can auto parallelized as the engine can see which parts of the dependency graph (for the derived state you're prompting) can be run in parallel.
The downsides are mostly related to caching of results. You need an "engine" that has to run all the time to find "given my inputs, how do I construct the derived state the user wants". In theory these can be cached, but the cache is easily invalidated. You add a key on the input, and the engine has to rerun everything (maybe this can be bypassed somehow?). You also can concoct complex scenarios where the caching of the derived states is non-trivial. Derived state values are cached by the resolvers themselved, but they have a limited view of how often and where they're needed. If two derived states use one intermediary resolver but with different inputs, you need to find a way to adjust the cache size.. Unclear to me how to do this tbh