This is something I thought I could avoid doing, but with the number of methods and traits such as StrExt grows I feel like the prelude becomes kind of bloated, and it might not be so easy to figure out where those methods come from when traits are imported with use Trait as _;
This PR deprecates the old methods and reintroduces them as keywords that can be used inside the { ... } expressions in the view! macro:
ref turns on reference-diffing for strings, replaces the StrExt::fast_diff method.
static stops updates to the DOM after initial render of the value, replaces the Stringify::no_diff method.
In addition this PR introduces a keyword that currently has no equivalent:
use disables diffing, value is set in DOM on every render. This will be more useful once fencing gets added (to effectively prevent diffing the same value multiple times).
Documentation & Rationale
All of the keywords are implemented as plain functions in a new keywords module:
The view! macro might do some extra optimizations, but fundamentally all of these are just function calls using raw identifiers, meaning this:
Originally I felt like adding keywords to expressions obfuscated things: using for with iterators makes the view! macro less like ordinary Rust and even more specialized DSL. After adding all the diffing interactions however I now believe keywords organized in a module are actually more discoverable, while not being significantly more DSL-y than trait extension methods.
rust-analyzer also handles this really well:
Alternatives considered:
Using plain functions like { no_diff(foo) }: this has similar effect to trait extension methods in terms of polluting the prelude, and I just personally find this to not spark joy.
Using custom faux keywords like { no_diff foo }: This has two issues:
Unlike actual Rust keywords we get no syntax highlighting in editors here.
Using an actual keyword is a stronger indication that this is a view! DSL syntax rather than just two random identifiers in a row. Someone might think that no_diff is a variable that's defined in scope and/or that foo is a mistake.
Keywords
This is something I thought I could avoid doing, but with the number of methods and traits such as
StrExt
grows I feel like the prelude becomes kind of bloated, and it might not be so easy to figure out where those methods come from when traits are imported withuse Trait as _;
This PR deprecates the old methods and reintroduces them as keywords that can be used inside the
{ ... }
expressions in theview!
macro:for
makes an iterator into aView
, replaces theListIteratorExt::list
method.ref
turns on reference-diffing for strings, replaces theStrExt::fast_diff
method.static
stops updates to the DOM after initial render of the value, replaces theStringify::no_diff
method.In addition this PR introduces a keyword that currently has no equivalent:
use
disables diffing, value is set in DOM on every render. This will be more useful once fencing gets added (to effectively prevent diffing the same value multiple times).Documentation & Rationale
All of the keywords are implemented as plain functions in a new
keywords
module:The
view!
macro might do some extra optimizations, but fundamentally all of these are just function calls using raw identifiers, meaning this:Desugars into:
Originally I felt like adding keywords to expressions obfuscated things: using
for
with iterators makes theview!
macro less like ordinary Rust and even more specialized DSL. After adding all the diffing interactions however I now believe keywords organized in a module are actually more discoverable, while not being significantly more DSL-y than trait extension methods.rust-analyzer also handles this really well:
Alternatives considered:
{ no_diff(foo) }
: this has similar effect to trait extension methods in terms of polluting the prelude, and I just personally find this to not spark joy.{ no_diff foo }
: This has two issues:view!
DSL syntax rather than just two random identifiers in a row. Someone might think thatno_diff
is a variable that's defined in scope and/or thatfoo
is a mistake.