You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is just based on curiosity. As it would cause a refactoring in all of quel and result in potential changes in the API, I would recommend conducting it in a separate branch and studying it further, whether the changes are worth or not, can they be minimised, and will this idea in general simplify quel's internals or not.
Currently, all changes are pushed eagerly throughout the dependency graph. Consumers can of course cache by debouncing changes happening in the same tick, but the computations will necessarily happen multiple times.
An alternative would be a push-pull system: when a source changes, all listeners are notified without getting the new value. They get the new value when they pull it. This allows a separation for computed values (which do not exist atm in quel), that can avoid recalculating their values (i.e. rerunning their expressions) until their own value is pulled by some other consumer. Propagation of change notification would be sped up drastically, and end consumers (i.e. observations) can properly schedule their response to change notifications.
This would be the new process:
When a source is changed, it notifies listeners without giving them the value.
A new type of sources, Computed values, are introduced. They will be the default to wrap all expressions instead of Observations.
Computed values will notify their listeners whenever one of their tracked sources notifies them.
Computed values will mark themselves as dirty whenever one of their tracked sources notifies them.
Computed values will rerun their expressions whenever their .get() method is called and they are marked as dirty. This will result in their dirty marking to be removed.
Observations will wrap given expression in a Computed, and eagerly refetch its value upon notification. This behaviour can be configured to more performant solutions.
Potential benefits:
Performance: Unnecessary rerunning of expressions is avoided.
Simplicity: The logic for re-running an expression is potentially simplified, just re-run when fetched and dirty.
Potential complications:
.get() becomes async. Even a sync expression might depend on an async expression. This might be a simplification though: currently the value returned by .get() might not reflect changes in the sources the expression depends on.
Removing dependencies becomes more complicated. Currently when a change in a source triggers a re-run in an expression, but that expression doesn't use the value of said source, then the dependency is removed. When the re-run doesn't happen immediately after change, then a dirty flag needs to be stored for all tracked sources.
Scheduling async runs might be more difficult. Currently, a source is changed, triggering an async re-run (if the expression is async), cancelling any pending re-runs. With this change, a .get() will trigger an async re-run, but multiple other .get()s might occur before said re-run ends. Sometimes these .get()s should subscribe to the same result, other times they should cause a cancellation of that re-run and trigger a new re-run (because new dependent sources have changed in the meanwhile).
The text was updated successfully, but these errors were encountered:
Note
This is just based on curiosity. As it would cause a refactoring in all of quel and result in potential changes in the API, I would recommend conducting it in a separate branch and studying it further, whether the changes are worth or not, can they be minimised, and will this idea in general simplify quel's internals or not.
Currently, all changes are pushed eagerly throughout the dependency graph. Consumers can of course cache by debouncing changes happening in the same tick, but the computations will necessarily happen multiple times.
An alternative would be a push-pull system: when a source changes, all listeners are notified without getting the new value. They get the new value when they pull it. This allows a separation for
computed
values (which do not exist atm in quel), that can avoid recalculating their values (i.e. rerunning their expressions) until their own value is pulled by some other consumer. Propagation of change notification would be sped up drastically, and end consumers (i.e.observations
) can properly schedule their response to change notifications.This would be the new process:
Computed
values, are introduced. They will be the default to wrap all expressions instead ofObservation
s.Computed
values will notify their listeners whenever one of their tracked sources notifies them.Computed
values will mark themselves as dirty whenever one of their tracked sources notifies them.Computed
values will rerun their expressions whenever their.get()
method is called and they are marked as dirty. This will result in their dirty marking to be removed.Observation
s will wrap given expression in aComputed
, and eagerly refetch its value upon notification. This behaviour can be configured to more performant solutions.Potential benefits:
Potential complications:
.get()
becomes async. Even a sync expression might depend on an async expression. This might be a simplification though: currently the value returned by.get()
might not reflect changes in the sources the expression depends on..get()
will trigger an async re-run, but multiple other.get()
s might occur before said re-run ends. Sometimes these.get()
s should subscribe to the same result, other times they should cause a cancellation of that re-run and trigger a new re-run (because new dependent sources have changed in the meanwhile).The text was updated successfully, but these errors were encountered: