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
As of #61, xilem_core is a separate crate that is generic with respect to the type of the element tree. There are also experiments using this core to generate DOM nodes. Potentially, xilem_core is useful as a standalone reactivity layer, comparable in scope to Dioxus or Leptos.
This issue tracks future development of xilem_core, both for potential web applications and as the reactive layer in a native UI stack. Building out the widget tree and other infrastructure is out of scope of this issue. The hope is that the work can happen in parallel.
A hypothesis to test is whether the Xilem reactive layer is a good alternative to React-like (Dioxus) and fine-grained reactivity (Leptos, Sycamore, Silkenweb). This can be evaluated in a web context, and doing so controls for a number of variables, though doing so misses one potential advantage of Xilem: web more or less forces a single-threaded approach.
The main work on xilem_core is in the following categories:
Add more features to xilem_core
Develop xilemsvg and possibly create a xilemweb
Explore scripting integration
Validate the design
Document and explain
We'll expand on each of those in their own sections
Add more features to xilem_core
The current state of the code is very minimal; there are features that have been prototyped in other repos and not adapted to the current architecture, and also features for which there is design work but not yet an implementation.
Three important "architectural" View implementations are adapt, memoize, and use_state. Prototypes exist in the xilem_tokio branch. It should be relatively straightforward to adapt these.
One question on memoize is whether we try to model the concept of "same" (which is captured in the Data trait from Druid), or the sloppier but more ergonomic choice of using PartialEq. It's worth noting that while the signature memoize in the xilem_tokio prototype has a Clone bound, it seems possible to remove.
Of course, one approach is to offer both PartialEq and same variants. For a number of types (strings, etc) there is no significant difference.
Async integration
The xliem_tokio prototype also has async integration. It's not obvious how much of that belongs in xilem_core and how much should be implemented in clients. A good criterion for decision is how much this logic can be made actually generic. Since these views spawn work, there is a dependency on a runtime; on wasm, this can simply be a call to wasm_bindgen_futures::spawn_local.
See draft blog post on Xilem async for more discussion of async. Note nontrivial logic for choreographing the rendering. That feels out of scope for xilem_core (especially as not needed in web use cases), but it is open question. Perhaps the actual scheduling logic is out of scope for xilem_core, but support for common patterns would make sense.
Environment
One feature common to most reactive frameworks is the concept of an environment (also commonly called "context") where a parent view can set some data, and child views can query it. This is a form of dynamic scoping, and can also be seen as a flow of data downward in the tree.
It seems practical to implement in Xilem, and likely desirable. There is an extensive Zulip thread with notes on the design.
impl View for Arc<V: View>
In the Elm tradition, memoization is the primary mechanism for skipping re-rendering when there is no corresponding change to the app state. The memoize View supports that pattern (with an extremely similar signature as Elm), but using a closure to defer rendering has ergonomic downsides; in the general case, users will need to wrap a relevant chunk of app state in an Arc and move a clone of that into the closure. An alternative is for the app to maintain pre-rendered views and paste them into the view tree (also by cloning an Arc).
There is a Zulip thread with fairly detailed notes on implementing this feature, as well as considering its implications. Naming the type of the retained View is challenging, so either type alias impl trait (not yet in stable Rust) or type erasure would be useful.
Diffable sparse data structures
The plan for (potentially) large collections in Xilem is the use of diffable sparse data structures. It's not obvious whether these belong in xilem_core or in separate crates; the underlying data structures almost certainly do, but there may be useful glue specific to Xilem as well. Note that imbl already handles sparse diffing well in its OrdMap type, but not in the corresponding sequence type.
Ideas for sparsely diffable sequences are described in a RustLab 2020 talk, and there is some prototype code implemented in xi-rope, but this hasn't been landed. It may make sense to start with a placeholder (implemented on Vec) with the correct semantics and API but O(n) performance, to be replaced by a rope-like data structure later.
Template diffing
One possible feature I'll list is template diffing, which has successfully been used for significant performance improvements in Dioxus. However, I'm not yet convinced it's worth the complexity; it seems to me to force the use of compile time macros to analyze which parts of the template are static and which dynamic, while the current Xilem design is not dependent on macros. Even so, I think it can be done within the Xilem framework and may be worth exploring, even if only to gather quantitative performance data.
Explore scripting integration
One motivation for Xilem is to enable bindings with scripting languages; this was a limitation of Druid and is nontrivial in general. Among other things, such language bindings generally require type erasure (AnyView), as modeling the View tree in static types won't work.
There was a Python prototype built, on a very old version of Xilem (back when it was still called "idiopath") that demonstrated a simple button and container example.
Given the potential of such languge bindings, it seems worth continuing to explore, and also discovering what works well and what is more of a pain point.
I should note here that the need to support dynamically typed scripting puts some constraints on the View schema. As one example, custom alignments in SwiftUI are implemented by creating custom (generally zero-size) types that conform to the AlignmentID protocol (and implement a defaultValue static method). It might be possible to adapt that to a Python, but it seems challenging.
Develop xilemsvg and possibly xilemweb
There is an experiment of creating SVG dom nodes from Xilem Views. One reason for this particular focus is to explore also implemeting native rendering from the same View tree.
I've also done a small amount of prototyping of using a generic Xilem View to create HTML DOM nodes (not published, and based on a version that predates the current xilem_core). This experiment could be significantly expanded. A good early milestone is re-creating TodoMVC.
Making a real reactive layer is a large task; there's a significant amount of work specific to running in a web browser context.
One potential exploration with xilemweb is to integrate with Blitz.
Validate the design
I obviously feel that xilem_core has the potential to be a great reactive layer for UI in Rust. However, there is currently very little evidence to support such a claim. A great deal of the validation can be done in a Web context. The main criteria are:
Conciseness
Performance
Expressiveness
Flexibility
Overall developer ergonomics
One way to evaluate performance is to participate in the js-framework-benchmark (see Sledgehammer for more details on running this in a Rust WASM context). However, there are some caveats. Because it of its web-centric nature, it cannot capture the ability to exploit parallelism through multithreading.
The "flexibility" line captures the suitability across a range of use cases. One open question is whether xilem_core is usable as-is without an explicit state management layer, or whether it makes sense to add one. One exploration is integration with hornpipe.
Similarly, we'll want to evaluate whether the adapt View actually facilitates factoring a larger application into components. It's always tricky to model interactions between components.
Document and explain
A codebase, even of crystalline perfection, is of little use unless people can actually understand how to use it. There are a few breadcrumbs of documentation, but to be viable, xilem_core needs a good writeup.
As of #61, xilem_core is a separate crate that is generic with respect to the type of the element tree. There are also experiments using this core to generate DOM nodes. Potentially, xilem_core is useful as a standalone reactivity layer, comparable in scope to Dioxus or Leptos.
This issue tracks future development of xilem_core, both for potential web applications and as the reactive layer in a native UI stack. Building out the widget tree and other infrastructure is out of scope of this issue. The hope is that the work can happen in parallel.
A hypothesis to test is whether the Xilem reactive layer is a good alternative to React-like (Dioxus) and fine-grained reactivity (Leptos, Sycamore, Silkenweb). This can be evaluated in a web context, and doing so controls for a number of variables, though doing so misses one potential advantage of Xilem: web more or less forces a single-threaded approach.
The main work on
xilem_core
is in the following categories:xilem_core
We'll expand on each of those in their own sections
Add more features to
xilem_core
The current state of the code is very minimal; there are features that have been prototyped in other repos and not adapted to the current architecture, and also features for which there is design work but not yet an implementation.
Three important "architectural"
View
implementations areadapt
,memoize
, anduse_state
. Prototypes exist in the xilem_tokio branch. It should be relatively straightforward to adapt these.One question on
memoize
is whether we try to model the concept of "same" (which is captured in the Data trait from Druid), or the sloppier but more ergonomic choice of usingPartialEq
. It's worth noting that while the signaturememoize
in the xilem_tokio prototype has aClone
bound, it seems possible to remove.Of course, one approach is to offer both
PartialEq
and same variants. For a number of types (strings, etc) there is no significant difference.Async integration
The xliem_tokio prototype also has async integration. It's not obvious how much of that belongs in xilem_core and how much should be implemented in clients. A good criterion for decision is how much this logic can be made actually generic. Since these views spawn work, there is a dependency on a runtime; on wasm, this can simply be a call to wasm_bindgen_futures::spawn_local.
See draft blog post on Xilem async for more discussion of async. Note nontrivial logic for choreographing the rendering. That feels out of scope for xilem_core (especially as not needed in web use cases), but it is open question. Perhaps the actual scheduling logic is out of scope for xilem_core, but support for common patterns would make sense.
Environment
One feature common to most reactive frameworks is the concept of an environment (also commonly called "context") where a parent view can set some data, and child views can query it. This is a form of dynamic scoping, and can also be seen as a flow of data downward in the tree.
It seems practical to implement in Xilem, and likely desirable. There is an extensive Zulip thread with notes on the design.
impl View for Arc<V: View>
In the Elm tradition, memoization is the primary mechanism for skipping re-rendering when there is no corresponding change to the app state. The
memoize
View supports that pattern (with an extremely similar signature as Elm), but using a closure to defer rendering has ergonomic downsides; in the general case, users will need to wrap a relevant chunk of app state in anArc
and move a clone of that into the closure. An alternative is for the app to maintain pre-rendered views and paste them into the view tree (also by cloning anArc
).There is a Zulip thread with fairly detailed notes on implementing this feature, as well as considering its implications. Naming the type of the retained View is challenging, so either type alias impl trait (not yet in stable Rust) or type erasure would be useful.
Diffable sparse data structures
The plan for (potentially) large collections in Xilem is the use of diffable sparse data structures. It's not obvious whether these belong in xilem_core or in separate crates; the underlying data structures almost certainly do, but there may be useful glue specific to Xilem as well. Note that imbl already handles sparse diffing well in its OrdMap type, but not in the corresponding sequence type.
Ideas for sparsely diffable sequences are described in a RustLab 2020 talk, and there is some prototype code implemented in xi-rope, but this hasn't been landed. It may make sense to start with a placeholder (implemented on
Vec
) with the correct semantics and API but O(n) performance, to be replaced by a rope-like data structure later.Template diffing
One possible feature I'll list is template diffing, which has successfully been used for significant performance improvements in Dioxus. However, I'm not yet convinced it's worth the complexity; it seems to me to force the use of compile time macros to analyze which parts of the template are static and which dynamic, while the current Xilem design is not dependent on macros. Even so, I think it can be done within the Xilem framework and may be worth exploring, even if only to gather quantitative performance data.
Explore scripting integration
One motivation for Xilem is to enable bindings with scripting languages; this was a limitation of Druid and is nontrivial in general. Among other things, such language bindings generally require type erasure (
AnyView
), as modeling the View tree in static types won't work.There was a Python prototype built, on a very old version of Xilem (back when it was still called "idiopath") that demonstrated a simple button and container example.
Given the potential of such languge bindings, it seems worth continuing to explore, and also discovering what works well and what is more of a pain point.
I should note here that the need to support dynamically typed scripting puts some constraints on the View schema. As one example, custom alignments in SwiftUI are implemented by creating custom (generally zero-size) types that conform to the AlignmentID protocol (and implement a
defaultValue
static method). It might be possible to adapt that to a Python, but it seems challenging.Develop xilemsvg and possibly xilemweb
There is an experiment of creating SVG dom nodes from Xilem Views. One reason for this particular focus is to explore also implemeting native rendering from the same View tree.
I've also done a small amount of prototyping of using a generic Xilem View to create HTML DOM nodes (not published, and based on a version that predates the current xilem_core). This experiment could be significantly expanded. A good early milestone is re-creating TodoMVC.
Making a real reactive layer is a large task; there's a significant amount of work specific to running in a web browser context.
One potential exploration with xilemweb is to integrate with Blitz.
Validate the design
I obviously feel that xilem_core has the potential to be a great reactive layer for UI in Rust. However, there is currently very little evidence to support such a claim. A great deal of the validation can be done in a Web context. The main criteria are:
One way to evaluate performance is to participate in the js-framework-benchmark (see Sledgehammer for more details on running this in a Rust WASM context). However, there are some caveats. Because it of its web-centric nature, it cannot capture the ability to exploit parallelism through multithreading.
The "flexibility" line captures the suitability across a range of use cases. One open question is whether xilem_core is usable as-is without an explicit state management layer, or whether it makes sense to add one. One exploration is integration with hornpipe.
Similarly, we'll want to evaluate whether the
adapt
View actually facilitates factoring a larger application into components. It's always tricky to model interactions between components.Document and explain
A codebase, even of crystalline perfection, is of little use unless people can actually understand how to use it. There are a few breadcrumbs of documentation, but to be viable, xilem_core needs a good writeup.
Starting points:
The text was updated successfully, but these errors were encountered: