Open Sunjammer opened 7 years ago
I propose this simplified syntax:
<Let name="expression" />
for example
<Let foo="{bar} / 2" />`
which will be automatically expanded by the UX compiler to
<Let Key="foo" Value="{bar} / 2" />
I like that too 👍
Actually, lets do:
<Let foo="1" />
expands to
<Let ux:Name="foo" Value="1" />
Where ux:Name
is also implicitly setting a Name
string property on the Let
instance (using the [UXName]
attribute). This in turn allows you to use this syntax for animation:
<Change foo.Value="10" Duration="1" />
And if we are super lazy, we can also add a UX compiler feature that implicitly appends .Value
on Change
targets if it finds a property it doesn't recognize. However, keep in mind that this runs the risk of name collisions, e.g. what if you want to animate the data named Duration
?
We should be able to do the <Let ux:Name="foo" Value="1"/>
syntax without introducing new UX compiler features. It might be worthwhile to do that first.
I've done variants of this in test cases before.
This feature requires lots of testing with different types. The problem I've have in my previous attempts (usually in tests), is that Let
is untyped, which causes a problem for marshalling. Conversion from Value
is fine, but when using Change
with Value
as a target we have a problem: Change
needs to know what type is changing. This applies to Set
, and most cases of 2-way binding as well.
I don't see that we can get away with just Let
and will likely require LetFloat
, LetString
, etc. This may play into what syntax we actually want.
The implementation of this likely depends on https://github.com/fusetools/fuselibs-public/issues/740
It appears I can get it working with weak types despite #740, but the weaknesses shown there become a lot more relevant with Let
availabe. Other than the constant arrays, I've found workarounds for the other forms. Combined with models/contexts though most use-cases won't notice the limitations I think.
Motivation:
UX is a language about construction of objects and establishment of their relationships. As UX documents increase in complexity the depth of these relationships has the side effect of excessive code duplication and verbosity, which has implications for productivity and readability. UX is not a DAG, even if XML pretty much implies that it is, because you can cross reference and databind across any and all boundaries, and this too has implications for verbosity and code dupe. Since we can't/shouldn't eliminate this ability, It should be our goal to reduce it and make it readable, and this needs a language addition for pure data.
UX has ux:Property for receiving data from a source external to the class in which it was defined, but ux:Property is not ideal for establishing a tree-local data source or transform. I like the proposed Let syntax:
<Let ux:Key="name" ux:Value="expression"/>
Where Let can be used anywhere and appends its results to the local data context.
Examples:
Animation drivers
These are three lines out 10 and the duplication is obvious. With the proposed
<Let ux:Key="progress" ux:Value="0"/>
syntax we can clean this up tremendously:We have a single source of truth for animation progress of icon opacities, one which we can scrub in Studio from a single selected node, and one that we can do single timelines for instead of multiple parallel ones. This really shortens the amount of UX markup needed.
Expression reuse and composability
This moves the expression/transform into a reusable node, rather than having to copy/paste expressions around the codebase. It also allows for composability for users less comfortable writing single long expressions.
Tree-local vs Class property
Since Let appends to the data context, it does not need to be declared in a class, nor is it visible to parent nodes. This makes Let a versatile, tree-local data source.
Let
becomes the go-to utility for establishing and contextualizing data as part of a UX subtree, replacing many scenarios whereJavaScript
is the only solution but without the overkill.