elmish / Elmish.WPF

Static WPF views for elmish programs
Other
428 stars 71 forks source link

Lazy subModelSeq (and subModel)? #143

Closed cmeeren closed 3 years ago

cmeeren commented 5 years ago

Unless I'm mistaken, currently subModelSeq will loop through and update the sub-bindings for every item on every iteration of the update loop. This may have performance implications for large sequences. If the input sequence has not changed, the bindings should ideally be skipped altogether. This calls for a subModelSeqLazy binding.

The same might be said for subModel, though there's only ever one model there, so it's not as critical. But given that the model might have further sub-models (or just a lot of bindings), it should be possible to skip subModel, too, if the input hasn't changed.

Nobody has requested this, and I don't have any immediate plans on implementing it, but I'm leaving this issue here in case anyone else wants to look at it, or just as a future reminder for myself.

TysonMN commented 3 years ago

This feature now exists in the branch composable/Lazy/implementation.

Here is an example of it working using the branch composable/Lazy/example.

In this example, I implemented the map function to delay for a second. Changing the counter value always takes a second, but changing the step size executes instantly because lazy behavior avoids the delay in map.

2020-12-21_08-55-57_437

If I remove the laziness, then updating the step size also ensures the delay.

2020-12-21_08-57-13_439

As stated in the OP, a great place to add this effect is "on top of" a SubModel or SubModelSeq binding.

TysonMN commented 3 years ago

This features now exists in the branch composable/Lazy/implementation.

One change I want to make is to address the comment I left here (with typos fixed and expanded a bit below).

Instead of iterating over the bindings three times to update properties, commands, and validation errors, consider iterating over the bindings once and updating those three things for each binding. Then the LazyUpdate predicate can be executed once for each binding for each call to UpdateModel.

Another advantage of this change (as I plan on making it) is that the resulting code will do a better (but still not perfect) job of separating pure from impure code.

I have to be careful to preserve behavior. There is a a lot of impurity there. I know of three sources (not "directly" in UpdateModel).

  1. Implicit dependence on CurrentModel.
  2. ObservableCollection changes in the OneWaySeq and SubModelSeq bindings.
  3. The calls to setError and removeError in updateValidationError.
cmeeren commented 3 years ago

There was a discussion a mile up this issue about a name for lazy since it's a keyword. I just thought of laz. Works fine with intellisense (unlike lzy), and with a bit of goodwill it can be pronounced like "lazy" (think z = "zee").

No strong opinions, just felt like writing it down before I forgot.

TysonMN commented 3 years ago

with a bit of goodwill it can be pronounced like "lazy" (think z = "zee").

Maybe. The actual pronunciation of laz would be like this.

What about lazyy?

cmeeren commented 3 years ago

Maybe. The actual pronunciation of laz would be like this.

Well, I wasn't thinking it was "proper" pronunciation; just that if you squint a little, laz can be thought of as la-Z, i.e. la-zee (yes, yes, I know half the would would think la-zed).

lazyy is possible, but I'd say little better than lazy'.

TysonMN commented 3 years ago

I will go with lazy' as the "working" name.