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
Copy file name to clipboardExpand all lines: src/overview/whack_ds.md
+23-95Lines changed: 23 additions & 95 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,52 +1,44 @@
1
1
# Whack DS
2
2
3
-
Whack DS is a feature of the Whack engine used for extending the closed set of Whack element classes with reactive UI components. It is functionally similar to ReactJS, but its syntax is more similar to Adobe MXML.
3
+
Whack DS takes inspiration from both ReactJS and Adobe MXML for GUI dev.
4
4
5
5
## Memoization
6
6
7
-
Whack DS automatically memoizes components, allowing for user customizable Prop/State equality comparison and clones through overriding the `equals` method and implementing a `clone` method.
7
+
Whack DS memoizes components.
8
8
9
-
Memoization allows to skip re-rendering a component when its Props do not change.
10
-
11
-
Just like with ReactJS, memoizing components has drawbacks such as possibly volatile code regions (such as when internationalizing a product with locale-specific translation strings). In such cases, relying on a Whack DS context will re-render the component when the context changes regardless of whether props did or not change.
12
-
13
-
Whack DS skips re-rendering component if the parent re-renders and the props are equals to the previous render; the Whack DS component's own states updating with a different value will always re-render it.
14
-
15
-
Whack DS implementation stores previous state or previous properties by performing a `generic::clone`. For using custom classes inside states or Properties — like when a tuple, record, `Array` or `Map` is not enough — you may need a `clone` method that returns an object of the same kind and perhaps an `equals` method.
16
-
17
-
- Custom classes do not need a `clone` method if they are, say, purely data with an optional constructor.
18
-
- Custom classes whose instances should be references (that is, cloned by reference and equal by reference) should implement a `clone` method that returns the this receiver as is and an `equals` method that does simply `===`.
9
+
- It invokes `generic::clone` to clone an object and keep it as a previous state.
10
+
- It invokes `equals` to compare two objects.
19
11
20
12
## Style sheets
21
13
22
-
Whack DS supports style sheets out of the box. Here is a simple example:
Notet that instances of a component class are throwaway. It's not recommended to explicitly construct such classes or share instances with other code locations.
53
+
import z = zero.*;
54
+
55
+
var xn:whack.ds.Node;
56
+
57
+
xn = <z:Box/>
58
+
```
63
59
64
-
Here's a slightly bigger code snippet for a linear second accumulator:
60
+
## Monotonic counter
65
61
66
62
```sx
67
63
package {
@@ -98,58 +94,20 @@ package {
98
94
}
99
95
```
100
96
101
-
Even though the constructor is frequently re-evaluated, objects originating from the initial rendering phase are reused for the instance fields.
102
-
103
97
## Immutability
104
98
105
99
Ensure you follow immutability principles with States, Contexts and Props.
106
100
107
-
> **Note**: ReactJS and Adobe Flex also present the same limitation.
108
-
>
109
-
> For a language compiler to implement any actual transitive immutability,
110
-
> significant effort is required, and it may end up increasing the language
111
-
> complexity.
112
-
113
-
## Callback caching
114
-
115
-
Whack DS caches callbacks (either lambdas, inline event handlers, instance methods of the same component or Functions declared inside the constructor) within applicable E4X attributes, since they are naturally ever changing `Function` objects regardless of whether they are lambdas or fixtures ─ for example, since they capture locals, `this` or ShockScript lexical contexts, they tend to return different `Function` objects ─ and this is crucial for memoization.
116
-
117
-
> **Note**: Whack currently **does not cache** callbacks nested in objects. It is not recommended to use lambdas or ever changing Functions inside Prop objects within an E4X literal, as Whack will not give an error or warning for now.
118
-
>
119
-
> For the tag-form of setting a Prop in an E4X literal (as in `<s:f>{function(){}}</s:f>`), we have not considered caching either, since this is not very common; although that is easy to support in the future as well.
120
-
121
-
If a callback appears within a nested block, Whack tries contributing it as a `whack.ds.useCallback` to the component main evaluation's body.
122
-
123
-
Whack DS doesn't attempt to cache such a callback if it it does not belong to a component's constructor or instance method. If it does belong to a constructor, the callback is cached; but after IR generation, if there is a chance of the constructor exiting execution before the generated `whack.ds.useCallback` callback, the compiler generates an error at the respective tag's attribute.
124
-
125
-
## Auto dependency tracking
126
-
127
-
- Whack DS presents extra overhead for State/Context/Prop accessors, so that, say, the surrounding effect or callback is said to be dependent on an used State/Context/Prop.
128
-
- Subsequent renders may still accumulate more dependencies, like conditional ones.
129
-
- Whack DS E4X attributes assigned to functions or methods from the same component are cached based on dependency tracking; same for E4X event handlers **&=**.
130
-
131
-
### Props tracking
132
-
133
-
Whack DS automatically tracks not only states and context dependencies in an effect or callback, but also props.
134
-
135
-
What Whack DS does internally:
136
-
137
-
- The Props object is reused across renders. For every render, its internal hash map is cleared and then overwritten.
138
-
-**tap \{\}** types, which are used for representing props, desugar into classes which use a hash map internally for storing only props that are specified. Each prop gets its own getter, which detects surrounding effect or callback and returns the current value of the prop at the internal hash map.
139
-
- Track prop name for comparison + previous value for the surrounding effect/callback if any
101
+
> **Note**: ReactJS, Adobe Flex and many other technologies also present the same limitation. Since Whack DS uses always imposes references for States, Contexts and Props, not following these principles may lead to internal bugs.
140
102
141
103
## Deriveds
142
104
143
-
Variables derived from States, Contexts, Bindables or Props are often expressed as virtual accessors, as in:
144
-
145
105
```sx
146
-
private function get combination() : decimal {
147
-
use decimal ctx
148
-
return x + y
149
-
}
150
-
```
106
+
[State] var x : decimal = 0;
107
+
[Bindable] var y : decimal = 0;
151
108
152
-
Using methods is also an option.
109
+
private function get z() : decimal (x + y)
110
+
```
153
111
154
112
## Understanding Bindables
155
113
@@ -217,27 +175,6 @@ State annotatated variables are represented as `State.<T>` instances.
217
175
218
176
A `State` annotatated variable may be assigned, in addition to its expected value type, a compatible `whack.ds.State.<T>`.
219
177
220
-
## Component validation
221
-
222
-
The following apply when using E4X literals to construct `whack.ds.Node`.
223
-
224
-
- A tag name must resolve to either
225
-
- A component class that extends `whack.ds.UIComponent`
226
-
- May be an Alias itself
227
-
- A Prop (clarified in the subsections)
228
-
- A context provider
229
-
- An intrinsic element
230
-
231
-
Class definitions that extend `whack.ds.UIComponent` are validated in a flat way to avoid programmer bugs:
232
-
233
-
- The `Alias` meta-data
234
-
- Every instance variable is either
235
-
-**tap \{\}** typed (at most one variable of this kind, which is usually the Props object)
236
-
- A `Bindable` annotatated variable
237
-
- A `Context` annotatated variable
238
-
- A `State` annotatated variable
239
-
- The class either omits the constructor, or defines a constructor whose signature is either `function():void` or `function(Props):void`, where `Props` must be a **tap \{\}** type.
240
-
241
178
## Aliases
242
179
243
180
A component may be an alias by using the Alias meta-data, which specifies a ShockScript qualified identifier which is treated like a tag name.
@@ -280,15 +217,6 @@ package {
280
217
281
218
Monochrome icons are filled with the current CSS `color`.
282
219
283
-
## Recommendations
284
-
285
-
-*Props*
286
-
- Don't destructure the props object in large method bodies.
287
-
- Don't mutate props (although their fields are read-only, unfortunately they are not transitively read-only).
288
-
- Say you want to reuse a `style` prop from the component inside a `final` tag but also set specific fields: You better create a new `style` object spreading that prop, then pass it to that tag.
289
-
- A best order for a component's constructor may be 1. `super` statement followed by 2. any initial values for instance variables (e.g. Props, States and/or Bindables) followed by 3. effects followed by 4. any custom hooks followed by 5. the `final` construction.
290
-
- If, say, a loop or `switch` creating Whack DS nodes contains its own event handlers, it might be better to define a separate component (perhaps nested) for that purpose, thus getting advantage of callback caching.
291
-
292
220
## Tips
293
221
294
222
- Remember that user-defined hooks do not take *props* as actual components do. If an user-defined hook returns any result, it should typically be either a `State` or `BindableReference` which can be assigned to a State or Bindable annotatated variable.
Whack DS automatically memoizes components, allowing for user customizable Prop/State equality comparison and clones through overriding the `equals` method and implementing a `clone` method.
6
+
7
+
Memoization allows to skip re-rendering a component when its Props do not change.
8
+
9
+
Just like with ReactJS, memoizing components has drawbacks such as possibly volatile code regions (such as when internationalizing a product with locale-specific translation strings). In such cases, relying on a Whack DS context will re-render the component when the context changes regardless of whether props did or not change.
10
+
11
+
Whack DS skips re-rendering component if the parent re-renders and the props are equals to the previous render; the Whack DS component's own states updating with a different value will always re-render it.
12
+
13
+
Whack DS implementation stores previous state or previous properties by performing a `generic::clone`. For using custom classes inside states or Properties — like when a tuple, record, `Array` or `Map` is not enough — you may need a `clone` method that returns an object of the same kind and perhaps an `equals` method.
14
+
15
+
- Custom classes do not need a `clone` method if they are, say, purely data with an optional constructor.
16
+
- Custom classes whose instances should be references (that is, cloned by reference and equal by reference) should implement a `clone` method that returns the this receiver as is and an `equals` method that does simply `===`.
17
+
18
+
## Callback caching
19
+
20
+
Whack DS caches callbacks (either lambdas, inline event handlers, instance methods of the same component or Functions declared inside the constructor) within applicable E4X attributes, since they are naturally ever changing `Function` objects regardless of whether they are lambdas or fixtures ─ for example, since they capture locals, `this` or ShockScript lexical contexts, they tend to return different `Function` objects ─ and this is crucial for memoization.
21
+
22
+
> **Note**: Whack currently **does not cache** callbacks nested in objects. It is not recommended to use lambdas or ever changing Functions inside Prop objects within an E4X literal, as Whack will not give an error or warning for now.
23
+
>
24
+
> For the tag-form of setting a Prop in an E4X literal (as in `<s:f>{function(){}}</s:f>`), we have not considered caching either, since this is not very common; although that is easy to support in the future as well.
25
+
26
+
If a callback appears within a nested block, Whack tries contributing it as a `whack.ds.useCallback` to the component main evaluation's body.
27
+
28
+
Whack DS doesn't attempt to cache such a callback if it it does not belong to a component's constructor or instance method. If it does belong to a constructor, the callback is cached; but after IR generation, if there is a chance of the constructor exiting execution before the generated `whack.ds.useCallback` callback, the compiler generates an error at the respective tag's attribute.
29
+
30
+
## Auto dependency tracking
31
+
32
+
- Whack DS presents extra overhead for State/Context/Prop accessors, so that, say, the surrounding effect or callback is said to be dependent on an used State/Context/Prop.
33
+
- Subsequent renders may still accumulate more dependencies, like conditional ones.
34
+
- Whack DS E4X attributes assigned to functions or methods from the same component are cached based on dependency tracking; same for E4X event handlers **&=**.
35
+
36
+
### Props tracking
37
+
38
+
Whack DS automatically tracks not only states and context dependencies in an effect or callback, but also props.
39
+
40
+
What Whack DS does internally:
41
+
42
+
- The Props object is reused across renders. For every render, its internal hash map is cleared and then overwritten.
43
+
-**tap \{\}** types, which are used for representing props, desugar into classes which use a hash map internally for storing only props that are specified. Each prop gets its own getter, which detects surrounding effect or callback and returns the current value of the prop at the internal hash map.
44
+
- Track prop name for comparison + previous value for the surrounding effect/callback if any
45
+
46
+
## Component validation
47
+
48
+
The following apply when using E4X literals to construct `whack.ds.Node`.
49
+
50
+
- A tag name must resolve to either
51
+
- A component class that extends `whack.ds.UIComponent`
52
+
- May be an Alias itself
53
+
- A Prop (clarified in the subsections)
54
+
- A context provider
55
+
- An intrinsic element
56
+
57
+
Class definitions that extend `whack.ds.UIComponent` are validated in a flat way to avoid programmer bugs:
58
+
59
+
- The `Alias` meta-data
60
+
- Every instance variable is either
61
+
-**tap \{\}** typed (at most one variable of this kind, which is usually the Props object)
62
+
- A `Bindable` annotatated variable
63
+
- A `Context` annotatated variable
64
+
- A `State` annotatated variable
65
+
- The class either omits the constructor, or defines a constructor whose signature is either `function():void` or `function(Props):void`, where `Props` must be a **tap \{\}** type.
0 commit comments