
Moxie: Incremental Declarative UI in Rust - anp
https://blog.anp.lol/rust/moxie-intro/
======
pgt
Any discussion about incremental UI should include Yaron Minsky's talk about
Jane Street's OCaml framework, incr_dom from 2016:
[https://www.youtube.com/watch?v=R3xX37RGJKE](https://www.youtube.com/watch?v=R3xX37RGJKE)

Incremental is essentially an implementation of Adapton from 2014:
[https://www.cs.umd.edu/~hammer/adapton/](https://www.cs.umd.edu/~hammer/adapton/)

There is a big upset coming in the UX world as we converge toward a
generalized implementation of the "diff & patch" pattern which underlies Git,
React, compiler optimization, scene rendering, and query optimization.

Two sleeper startups in this space that are going to make _a lot_ of money are
Frank McSherry's Materialize Inc. and Nathan Marz's Red Planet Labs.

incr_dom source:
[https://github.com/janestreet/incr_dom](https://github.com/janestreet/incr_dom)

Differential Dataflow: [https://github.com/TimelyDataflow/differential-
dataflow](https://github.com/TimelyDataflow/differential-dataflow)

Declarative Dataflow Client:
[https://github.com/sixthnormal/clj-3df](https://github.com/sixthnormal/clj-3df)

Crux adapter for Declarative Dataflow:
[https://github.com/sixthnormal/clj-3df](https://github.com/sixthnormal/clj-3df)

~~~
amelius
> Two sleeper startups in this space that are going to make a lot of money ...

How are they going to make money if open source enthusiasts copy the ideas and
spread them for free? See e.g. React -> Vue.

Selling developer tools these days is just a losing game.

~~~
pgt
You are right about developer tools, but these companies are not selling
developer tools. Plus, the technical implementations are non-trivial.

~~~
amelius
> but these companies are not selling developer tools

Welll ... from their website:

> Red Planet Labs is pioneering a radically new kind of software tool.

Also, the Materialize "reactive SQL" solution sounds a lot like Firebase.

~~~
pgt
Firebase is a hosted database. Where does a dev tool begin and end? Is Slack a
dev tool? Is HN? Where do you draw the line?

------
erikpukinskis
A lot of innovative frameworks take the approach of forcing everything through
a single paradigm, so that you can avoid solving a whole class of problems.

It seems like a good trade off—yes, everything must be done just so, and
perhaps some parts of your app are a little awkward, or a little
boilerplate-y, but there’s a whole giant class of problems you can just
totally ignore.

Until... you can’t.

There’s another approach to library authorship, where the goal is not to
delete a class of problems, but to make a class of problems easily
controllable. Not to make a large domain disappear, but to make it
programmable.

I have found, with that as your goal, you will be pushed away from declarative
models. Because declarative models are about making a surface which is not
programmable but configurable.

You can’t program arbitrary relationships across a React component boundary.
You must flatten your intent into the very tight declarative interface which
exists there.

Procedural models allow you to use the full set of capabilities that a
function call and type system gives you. Ideally you don’t use much of that
capability at any one time. But the beauty is you can use exactly the right
control structure for the specific concern you are trying to... not abstract
away, but make controllable.

The set of “concerns” is the infinite set. And no possible declarative model
can capture it. Functions can.

~~~
paulddraper
You just need to know where your escape hatch is.

    
    
       SQL -> SQL procedures
    
       Angular templates -> DOM manipulation
    
       Puppet -> custom scripts
    

And you may even find it depends on the context.

For example, HTML/SVG/CSS DOM scripting can be considered "procedural", but
the in other sense the DOM is a rather declarative version of rendering, whose
procedural escape hatch is Canvas/WebGL.

You may even find case where they are combined tightly:

A makefile has declarative dependencies and procedural recipes.

~~~
erikpukinskis
Sure.

But once you are out the escape hatch you will need to model both the new
space you are working in, AND model the world you escaped from in order to
interoperate, which is a special hell.

~~~
rstuart4133
This hell has a name you will recognise: the leaky abstraction.

The idea is always to put a layer on top that simplifies things, so it's
easier to use and faster to learn. But the end result is usually you have to
learn both the abstraction and thing it was trying to hide.

------
bluejekyll
> the goal is to write the code "generically with respect to time," describing
> the state of the UI right now for any value of now. I think this is clearer
> in the above code samples, where the code always executes a complete
> declaration of the desired UI rather than explicitly mutating prior state.

I almost wish the post led with this, anp. It’s such a great and concise
description of the aim for the project, and really helps clarify all
underlying decisions.

Thanks for writing this post. It’s great!

~~~
anp
Great idea on the intro. Moved some things around, should be online soon.

Thanks for the kind words <3

------
kibwen
For more in the Rust UI space, see also Iced, which has an Elm-inspired
reactive model: [https://github.com/hecrj/iced](https://github.com/hecrj/iced)

~~~
epage
Also Relm which is Rust+Elm-inspired+Gtk

[https://github.com/antoyo/relm](https://github.com/antoyo/relm)

~~~
mdtusz
Also yew. It's more web focussed, but it works great running in a WebView for
a local application with RPC to a background server running locally.

[https://github.com/yewstack/yew](https://github.com/yewstack/yew)

------
danr_
> moxie assumes that the program will enter from the "top" of the tree each
> time. [...] My suspicion is that Rust may be fast enough along with the
> right memoization strategies to never worry about the time spent getting
> from the root of the tree to nodes with changes.

I think there is reason to worry: consider a node with a lot of children, for
example a list of many todos. Say you want to change the state of one single
todo, for example marking it as done. With a top-down approach such as diffing
you have to go through each child to see if it has changed. This is O(n). If
you instead have components that know their position in the tree and can react
to external changes, like react's Components or using hooks and useState, this
can be updated in O(1).

------
anp
Author here. I'm trying out an optional email Q&A format on the post, but will
also be keeping an eye out here.

~~~
sansnomme
Website on mobile needs a bit of fixing. Also, what do you think of Svelte?

~~~
anp
screenshot? how does reader mode look on your phone?

~~~
tiborsaas
Code blocks are too wide. Make them 100% wide and add overflow-x: scroll

I can't find reader mode on mobile chrome.

~~~
anp
Thanks for the tip! Should show up shortly.

------
derision
Not sure if it's because of rust (not super familiar with the language) but
the syntax seems really awful

~~~
anp
Yeah, I'm not the biggest fan of the syntax still either. That said, the
phrasing of your comment is unkind and its contents don't provide any useful
feedback.

~~~
jessaustin
_...unkind..._

Please don't misinterpret in this way. This is a candid reaction. As you
indicate, it confirms your previous observations. This is not an opinion of
you or any other Rust developer. It is an opinion of the syntax, period.

~~~
anp
It's unkind to call someone else's work "awful," even if its meant in a very
minor way (even if I agree with it!). It's a low value comment when it doesn't
provide any concrete feedback on top of that. Our industry has abysmal
standards for discourse and I'm not sure why you think that's important to
apologize for and normalize.

------
pier25
Anyone else plays "Surviving Mars"?

[https://survivingmars.gamepedia.com/MOXIE](https://survivingmars.gamepedia.com/MOXIE)

~~~
TeMPOraL
No, but I thought about it. Is the game any good?

~~~
DataGata
The game is good once you get the hang of it, but there are bursts of
micromanaging followed by long droughts of waiting for shit to happen. At max
speed, the game will do 1 day/3 minutes. Most of the Steam achievements take
about 60-100 days to do, which means 3-5 hours per game with lots of time
spent not interacting much. Of course, to get to a "full fledged" colony it
can take as many as 10 hours of gameplay, which again is mostly waiting for
your commands to happen.

Also, because its a Paradox game, the interface is ass.

If you like the genre of games, this is one to lose a couple of dozen hours
to. If you just think "oh, Mars is cool" its probably good to skip or download
a mod that lets you zoom time faster.

~~~
TeMPOraL
> _Also, because its a Paradox game, the interface is ass._

Huh, it's a Paradox game? Thar alone makes me interested; I'm a big fan of
Stellaris.

> _bursts of micromanaging followed by long droughts of waiting for shit to
> happen_

Yeah, that sounds like Stellaris.

Thanks for the review; I'll check the game out.

~~~
pier25
> _Huh, it 's a Paradox game?_

It's published by Paradox not developed by them.

------
guelo
One of the issues with React-style "declarative" UI frameworks is that they
have a hard time modeling transitions and animations. I'm not a Rustacean but
that would be one of the things I'd look for here.

~~~
hellofunk
If you take the animation out of the DOM-level code and put it in the CSS,
doesn't that fix the issue? React then does not need to know about or control
the animation and the browser just does what it does natively as things get
added or removed from the DOM.

~~~
WAHa_06x36
That leaves you with very simple and bland animations, and very little
flexibility.

~~~
hellofunk
Hm, have you seen some of the incredible and fine-tuned animations possible
with all the CSS features for that? I think it's pretty amazing and relatively
easy.

------
r-w
> Each time the button is clicked, the closure in boot runs in entirety but if
> you open your browser's devtools on the iframe, you should see that only the
> necessary DOM nodes are seeing updates:

Isn't that still radically inefficient?

~~~
Devagamster
Not really. The assumption is that modifying the dom directly is the expensive
part.

~~~
erikpukinskis
Doesn’t seem like a good bet for the long term. There’s no practical reason
why modifying the DOM couldn’t be practically free. Especially if we can hint
to the layout engine that we’re working in a well behaved subset. (Or the
layout engine can detect such)

~~~
Manishearth
Hi, I work on a browser, layout and styling are expensive.

Browsers already to _tons_ of work to avoid recomputing too much of this stuff
whenever the DOM changes, and it's _still_ inadvisable to poke the DOM too
much. I don't see this changing anytime soon. There are various new features
that allow for some level of hinting, but it's not going to obviate this.
Browsers need to have incremental layout/styling prepare for any kind of
potential change, whereas if you have a reactive UI framework you know what
kinds of changes can happen, and can optimize diffing based on that.

There's a reason why a lot of JS UI frameworks use a virtual DOM. It sounds
expensive to maintain, but directly operating on the DOM is more expensive.

~~~
fulafel
At some point the JS->C++ FFI was just slow in most browsers, but I guess this
has seen improvements lately?

~~~
Manishearth
I don't think that's too slow. It can be, but it's not the main bottleneck in
my experience.

That said there are various tricks that browsers use to avoid introducing
these boundaries.

------
3fe9a03ccd14ca5
Can this be easily built as a static binary? I mean, really static, as in pop
it onto your mother's windows laptop and let her double-click it and run the
program?

~~~
anp
Don't see why not, although to do so you'd need to use moxie-native which is
still very new.

------
giancarlostoro
This looks great, was kinda disappointed they didnt have a DOM demo for the
calculator, woulda really sold it even more honestly. It looks great
otherwise. I wish Go had more efforts like these, Fyne is as nicely a UI as I
could find for Go thus far. I think every modern language should really
produce a UI library as part of the STD lib even if it's rather basic.

~~~
anp
Good idea to make a DOM example for the calculator! I'm very behind on
examples.

Someone recently got very close to having the moxie-native calculator working
in a browser's wasm/webgl, which will be mindblowing if they get it to work.

~~~
giancarlostoro
I think even for documentation it would sell it amazingly well if you can see
sample GUI code and run it in the browser and try out the result, even if it's
not interactive editing wise.

------
dakom
So... semi-serious question, what does html/css give us that imgui doesn't?
e.g. taking this idea in another direction - why not just replace the dom
hierarchy with a single webgl node and compile imgui to wasm in order to drive
it that way?

~~~
for_the_many
Text rendering is extremely difficult. Even today, Chrome/Firefox are not
fully hardware accelerated on this front.

[https://gankra.github.io/blah/text-hates-
you/](https://gankra.github.io/blah/text-hates-you/)

~~~
dakom
Good point and thanks for the link! However, doesn't it imply that text
rendering is a bottleneck anywhere - games, digital signage, etc.?

No doubt there's good reasons for the slow browser performance (like text as
you mentioned, layout, event management, etc.) ... but it's still kinda crazy
that with the power of computers today, tearing down and building up a tree
that results in calculations for no more than a few thousand sprites or so is
a performance killer.

Would be nice if I could just re-render the entire DOM every tick. I've been
playing with doing exactly that via lit-html and it seems to be working
fine... but still, the idea is "the dom is sensitive - don't change what you
don't need to" :\

~~~
Manishearth
> Good point and thanks for the link! However, doesn't it imply that text
> rendering is a bottleneck anywhere - games, digital signage, etc.?

Yes, and this is why non-Latin text in many games is at best a texture, and at
worst, horribly, incorrectly rendered.

The state of the art for Arabic in Unity is I believe a plugin that basically
does manual shaping by replacing code points. There may be a Harfbuzz plugin,
idk.

~~~
dakom
Interesting. So does all text in the browser go through the same problem
space? Canvas, SVG, and HTML?

(also a question to the siblings here! I'm not totally clear on HN etiquette
when one wants a "reply all"...)

~~~
Manishearth
SVG and HTML use the browser's text rendering stack, which is pretty good.
(Native UI elements also benefit from native rendering stacks).

Canvas has the same problem, though there are tricks like compiling Harfbuzz
to wasm to get around that. There are proposals for a Web Shaping API to
expose the underlying shaping engine used by the browser.

~~~
dakom
Thanks!

------
ducaale
brisk-reconciler[0] is in the same vein but implemented in ocaml/reasonml. Its
currently used by brisk[1] and revery[2].

[0] [https://github.com/briskml/brisk-
reconciler](https://github.com/briskml/brisk-reconciler)

[1] [https://github.com/briskml/brisk](https://github.com/briskml/brisk)

[2] [https://github.com/revery-ui/revery](https://github.com/revery-ui/revery)

------
mywittyname
I'm not clear on something: is this translated into javascript or does this
provide an HTML render with native Rust hooks?

~~~
anp
moxie-dom is compiled to WebAssembly, and mutates the DOM using APIs from
javascript. The Rust isn’t translated into JS, but it does run alongside it.
moxie-native doesn’t have anything to do with JS or HTML, aside from reusing
some concepts from CSS.

------
mkettn
Whats the advantage over just writing vanilla html5?

Regarding your mental model: This looks quite similar to IEC 61499

~~~
anp
Ah, that's a good reference for a more modern "control loop" idea. I agree
that there are many similarities with that specification and I need to read in
more depth. Thanks!

Honestly, there's limited advantage over vanilla HTML5 if HTML is actually
what you were going to write. The website at moxie.rs is plain HTML/CSS/etc.
The reason to reach for tools like this on the web is if you want interactive
state, complex data transformations, etc.

I think it will be hard for moxie-dom to compete directly on ergonomics with
purely web-focused tools (especially JS frameworks), because the underlying
tools will always need to maintain some distance from platform semantics.

------
akavi
Is it safe to call this "React.js for Rust?", or is there a nuance I'm
missing?

(Don't intend that to be dismissive; I'm a huge react fan)

~~~
anp
From far down in the post:

> I have described moxie a few times as "what if a React in Rust but built out
> of context and hooks?"

------
toastal
If you have a chance to start fresh on building a UI DSL, why would you choose
XML?

~~~
anp
Familiarity. In short order it’ll be easy enough to write moxie functions
without the xml macro, at which point it becomes a matter of preference.

------
ryuukk_
the syntax, it is HORRIBLE

they'll go nowhere with that

~~~
anp
I'm not happy with the state of the syntax, but I'm pretty sure it'll take me
farther than this attitude.

------
for_the_many
It's nice to see that the traditional desktop GUI programmers finally realize
that the way the Web people do GUIs is right (React/Vue/...) and the way they
did it until now (QT/GTK/WPF/...) is wrong.

Many think that the only reason people use Electron is that it's cross-
platform, when that is actually a minor benefit. The big one is just how much
more better and efficient React/Vue/... are at creating GUIs. I say that as
someone who programmed GUIs in pretty much everything, starting with MFC.

~~~
delfinom
>It's nice to see that the traditional desktop GUI programmers finally realize
that the way the Web people do GUIs is right (React/Vue/...) and the way they
did it until now (QT/GTK/WPF/...) is wrong.

What? How is WPF any different than a web based ui framework. It does
differential rendering, it uses hierarchical components in XML. WPF can update
the UI with state changes on the backing C# without update commands, etc.

~~~
for_the_many
When I used it, WPF only had two way binding. The recommended way to use
React/Vue is with one way unidirectional binding (Redux/Vuex). It's a huge
difference, and simplifies things a lot.

Maybe WPF can do this today, I don't know, haven't touched it in 10 years.

Another aspect, while WPF might check the feature list of React/Vue, using it
in practice is kind of clunky.

~~~
nwallin
.NET Framework 3.0 was initially released November 21st, 2006. React.js was
initially released May 29th, 2013.

There were 2381 days between differentiating between various binding types in
WPF (which include one way, both OneWay and OneWayToSource) and React's
release. There were 2378 days between React's release and today.

So it took React longer to copy one way bindings from WPF than it took this
project to "copy" React.

Too bad you didn't make this comment on Thursday.

~~~
anp
If moxie brings anything new to the table, it’s _only_ because I copied
liberally and shamelessly from React and other successful and interesting
projects, learning and improving on them in the process. If it doesn’t bring
anything new, then it’s because I copied liberally and shamelessly from
successful and interesting projects :P.

I’m flattered to be compared to long standing paradigms I’ve had in mind (and
others I am learning of now) while working on this.

~~~
nwallin
I'm really only commenting on the idea that wpf doesn't have one way binding.
People saying dumb stuff on the internet makes me mad. Personal failing. Like
that was added in 2006. That feature was coreleased with Windows Vista and
IE7. Google had just bought YouTube for $1.65bn and people were incredulous
about such a stupid decision on Google's part. One way binding in wpf was
released to the public three months after jQuery. It's a year older than
silverlight, which is significant because silverlight just took everything
that wpf was and said, "what if we could make web pages this way?" Arguably
without silverlight the react folks never ask, "what if silverlight wasn't
completely shitty?"

I'm not really qualified to compare wpf to react or moxie.

Second, liberally copying the best parts of other things and leaving the
crappy parts behind _is_ bringing something new to the table. Don't sell
yourself short.

~~~
raphlinus
Can you point me to a good introduction (document, blog post, video) to the
way WPF does this? I'm actually quite interested in the older systems,
especially because a lot of them come from a place where massive complexity is
not seen as a good thing.

