Would a Declarative Reactive UI be too expensive?
Not 100% sure "reactive" is the right term. But frameworks like Flutter, where they rebuild sections of the UI with light weight objects when there is a state change. Would something like that work well in C#? Thinking of for like UI heavy games?
It feels like it would generate a lot of garbage so not really make sense to do. But I also see there is like MAUI Reactor. Which seems to do it. But seems like it wouldn't scale well. And doesn't seem like they are doing any pooling or anything.
It is one of those things that are a bit hard to setup a realistic MVP to profile myself.
21 Replies
Declarative UI, especially in .NET, is a joke IMO.
Only major upside is you get to use your language's built-in tooling.
In .NET, you are churning objects which is bad for GC.
Even worse if you're churning UI controls. "Lightweight" UI controls don't really exist.
That is kinda what I was assuming the case would be. The big upside that I like is that it makes 'binding' so easy and straight forward, more like immediate mode UIs.
Comet, which was going to be MVU for Maui, broke MVU immutability rules and then the author moved from MS to Meta to some AI frontend place.
I don't see how XAML bindings are difficult.
They aren't difficult, they just feel really clunky to me.
Basically, I just like the MVU pattern better. I guess you could do it with pooling, and 'resetting' the elements/widgets when releasing them. But I guess it would still be rather slower than just doing the normal way of updating elements.
Keep in mind that XAML has some serious space for optimizations that C# can't do.
So if you're using UWP (or presumably WinUI3), then there are a lot of perf improvements you're losing by moving your UI into C#.
See https://discord.com/channels/143867839282020352/169726357331378176/1298419243033034894
Sergio
Think of it this way.
Suppose you have this:
And this:
When you use C#, you do the following:
- Create the managed
Grid
object
- This then creates and activates the native object
- Calls set_Height
and go through the marshalling
- Call set_Width
and go through the marshalling
- Create the managed Button
object
- Create and activate the native button
- Call set_Text
and marshal the string
...
Whereas if you use XAML, it loads from XBF2. This is a highly optimized binary format, that does something like:
- Create this native object with this special id. Do no checks.
- Read these 8 bytes as int
-s, assign to these two properties with this raw index in this table. Do no checks, just trust me.
- Do the same for Button
- Just set this property (Text
) from this known id, assign directly this value from this binary blob. Again just trust me.
...
It's uber fast, does 0 validation, can use a special high-perf activation path for WinRT, does 0 marshalling, creates 0 managed objects entirely. It's just meant to be fast.Quoted by
<@160638834109972480> from #gui (click here)
React with ❌ to remove this embed.
Well fine then Modix, embed the whole thing. :harold:
Haha, it is actually just for doing a custom UI framework (for fun and learning new things)
Of course, other XAML frameworks aren't implemented as native, so you only get part of those benefits.
Interesting to know about how XAML does fancy stuff to be faster. Good to know!
Well, the Avalonia PropertyStore (system which manages bindings, setter priorities, etc) is built around observables. So you can do a lot with reactive programming.
Avalonia has https://github.com/AvaloniaUI/Avalonia.Markup.Declarative
Uno has https://platform.uno/c-markup/
In case you need inspiration. I still personally just don't like it. 🤷♂️
I appreciate it! the links!
Fair enough, to each their own really. If you take declarative UI out of the equation. Any thoughts on MVU pattern and implementing it?
No idea. I saw the pattern and I'm not willing to put real time behind unproven stuff in .NET, especially if it has obvious flaws (object churn).
Uno has its own adaptation called MVUX: https://platform.uno/docs/articles/external/uno.extensions/doc/Overview/Mvux/Overview.html?tabs=viewmodel%2Cmodel
Not entirely related, but Avalonia allows you to bind directly to observables. Though it's still a one-way road.
Fair enough.
I'm still struggling to fully grasp observables, which probably doesn't help some stuff
I assume the pattern can be smarter with pooling (and the limitations that would come from that) and make MVU reasonable with said enforced pattern. But that's a lot of invested time. Time that I prefer the pattern architect to put in, not me.
Yeah, makes sense.
Yeah, observables are awkward. I need to invest time into R3 basics at some point. Largely same thing, but different implementation. https://github.com/Cysharp/R3
The unit tests seem really clean and concise. Which helps understanding how certain features work.
Cool, I'll take a look. That is one thing that has made it hard for me is finding actual examples of observables that didn't have a bunch of other unrelated stuff tacked on that was doing stuff behind the scenes.
Like if you don't understand what
CombineLatest
does, you can always look at https://github.com/Cysharp/R3/blob/main/tests/R3.Tests/OperatorTests/CombineLatestTest.cs
And you'll see it emits a new item (containing the latest value of each input) each time one of the input streams pushes a new item.
Well, once each input stream has pushed at least one item.Oh weird...
(Obserivables, not the implementation)
Most of them are 1:1 with System.Reactive though there are some new operators, too.