Differences

This shows you the differences between two versions of the page.

Link to this comparison view

programming:functional_layout [2018/09/03 17:30]
sam [Delayed evaluation]
programming:functional_layout [2019/09/04 16:08]
Line 2: Line 2:
  
 Functional layout is a layout concept inspired by spreadsheets where the value of a cell can reference the value of another cell. For example "​WidgetA.left"​ can be set to the expression "​WidgetB.right + 10" which places WidgetA 10 pixels to the right of WidgetB. Functional layout is a layout concept inspired by spreadsheets where the value of a cell can reference the value of another cell. For example "​WidgetA.left"​ can be set to the expression "​WidgetB.right + 10" which places WidgetA 10 pixels to the right of WidgetB.
 +
 +The concept is somewhat similar to [[https://​vuejs.org/​v2/​guide/​computed.html|Vue.js computed properties]]. ​
  
 Live demo is here: [[https://​codepen.io/​samhepworth/​project/​full/​AONPBY/​]] Live demo is here: [[https://​codepen.io/​samhepworth/​project/​full/​AONPBY/​]]
Line 7: Line 9:
 The live demo is a "proof of concept"​ it is not intended for any real-world usage. The source code for the demo is optimized, but it can be optimized a lot more. However, more optimization will make the source code more difficult to read. Capabilities of the demo include: The live demo is a "proof of concept"​ it is not intended for any real-world usage. The source code for the demo is optimized, but it can be optimized a lot more. However, more optimization will make the source code more difficult to read. Capabilities of the demo include:
  
-  * Browser stack size is not a limitation. Recursive functions have been replaced with iterative functions where needed. 
   * The code is fast and it is not difficult to make it even faster.   * The code is fast and it is not difficult to make it even faster.
   * Only when a value change is it written to the DOM elements. This makes the code very fast.   * Only when a value change is it written to the DOM elements. This makes the code very fast.
Line 13: Line 14:
   * There are some nice operators to select widgets in the expression language.   * There are some nice operators to select widgets in the expression language.
   * Expressions are compiled to javascript functions making expression evaluation very fast.   * Expressions are compiled to javascript functions making expression evaluation very fast.
-  * Expression references are looked up before expressions are evaluated. This enables expressions to be evaluated in a topologically sorted order.+  * Expression references are looked up before expressions are evaluated. This enables expressions to be evaluated in a topologically sorted order. Browser stack size is not a limitation. Recursive functions have been replaced with iterative functions where needed. 
 +  * If a value is not used directly or indirectly to update a property on a DOM element, then this value is not evaluated unless is it read directly. Not evaluating "​unused"​ values provide a major performance boost.
   * The code is open source and distributed with a MIT license.   * The code is open source and distributed with a MIT license.
  
Line 22: Line 24:
   * Properties are not inserted into the generated HTML when widgets are rendered. All properties are applied after creating the DOM elements. Rendering selected properties when the HTML is generated is a simple addition.   * Properties are not inserted into the generated HTML when widgets are rendered. All properties are applied after creating the DOM elements. Rendering selected properties when the HTML is generated is a simple addition.
   * Values cannot have properties (composite values) - a value must be a property of a widget. It might be an advantage to rewrite the code so that widgets are a special kind of values, and that values can have properties.   * Values cannot have properties (composite values) - a value must be a property of a widget. It might be an advantage to rewrite the code so that widgets are a special kind of values, and that values can have properties.
-  ​Elimination of evaluation of "used" values. ​If a value is not used directly or indirectly ​to update ​a property on a DOM element, then this value does not need to be evaluated unless is it readNot evaluating ​"used" ​values will provide ​major performance boost+ 
 +Ideas: 
 + 
 +  ​Re-evaluate references based "lowest level" ​(nearest root) widget observation. No need to evaluate all references when widgets are added/​removed. 
 +  * Implement something like shadow DOM for widget children that are "​private"​ to the widget. 
 +    * a.private.b (widget b is a private child of a, ^b == a) 
 +  * Implement widgets as values ​that returns reference to self when read. 
 +  * New operators for accessing properties vs children: 
 +    * a'b.c (property c of child b of property a) 
 +    * '​a'​b.c (property c of child b of child a) 
 +    * 'a (child a not property a) 
 +    * a (property a) 
 +    * .a (property a) 
 +    * a..b (simple property b of property a) 
 +    * .a..b (simple property b of property a) 
 +    * 'a..b (simple property b of child a) 
 +    * ..a (simple property a) 
 +    * a..b'c (error - when new value is assigned ​to a.b then this is not discovered.) 
 +    * a..b.c (error)  
 +    * < > ^ (sibling widget, parent widget) 
 +    * '* (all children) 
 +    * '​*'​* (all children of all children) 
 +    * a\sa (property ​"a a") 
 +    * .\1a\sa (property "1a a") 
 +    *  
 +    * a'"​hello world"​.c (child with special name) 
 +    * a."​hello world"​.c (property with special name) 
 +    * '"​hello world"​.c (child with special name) 
 +    * ."​hello world"​.c "​property with special name) 
 +    * ^.a (property a on parent) 
 +    * ^'(child a on parent) 
 +    * ^a (property on parent) 
 +    * <.a (property a on previous child) 
 +    * <'a (child a on previous child) 
 +    * <a (property on previous child) 
 +    *  
 +    * (old) a (assume property, then child) 
 +    * (old) a.b (assume a is child, b is property) 
 +    * (old) a.b.c (assume a, b is child, c is property) 
 +    * (old) a.b..c (c simple property of value b of widget a) 
 +    * (old) a.b..c..d (d simple property of simple property c of value b of widget a) 
 +    * (old) a.b..c.d (error?) 
 +    * (old) @a (child a - never property a) 
 +    * (old) a@b (child b of widget a - not property b of child a) 
 +    * (old) a|b.c (property c of property b of widget a - not property c of widget b of widget a) 
 +    * (old) |b (property b - never widget b) 
 +    * (old) |"​a-1"​ (property with special name) 
 +    * (old) @"​a-1"​ (child with special name"​) 
 +  * Arrays 
 +    * [b] (value with index b of values) 
 +    * .[b] (value with index b) 
 +    * '[b] (child with index b) 
 +    * a[b] (value with index b of property a) 
 +    * .a[b] (value with index b of property a) 
 +    * 'a[b] (value with index b of child a) 
 +    * length (number of values) 
 +    * push(b) (push b on values) 
 +    * pop() (pull value from values) 
 +    * a.length (number of values of a) 
 +    * a.push(b) (push b on values of a) 
 +    * a.pop() (pull value from values of a) 
 +    * children (number of children) 
 +    * a.children (number of children of property a) 
 +    * '​a.children (number of children of child a) 
 +    * '​a'​[b] (child with index b of child a) 
 +    * '​a'​[b]'​[c] (child with index c of child with index b of child a) 
 +    * array(a, b, c) (create array [a, b, c]) 
 +    * {x: a, y: b, z: c}..a (create object and get simple property a)  
 +  * References 
 +    * ref(a) (reference ​to property or child a) 
 +    * val(a) (value of reference a - when a changes a new lookup must be performed) 
 +    * lookup("​a'​b"​) (dynamic lookup) 
 +    * lookup("<"​).b (property b of dynamic lookup) 
 +    * lookup("<")'b (child b of dynamic lookup)  
 +    * store(a, ref(b)) (store value a in property b - at some interval) 
 +  * States 
 +    * Transition from state a to state b. 
 +      * A state override selected property expressions when the state is active. 
 +        * a.c = ~state = "​a"​ ? 1 : ~state = "​b"​ ? 2 : ~state = "​c"​ ? 3 : 4
  
  
Line 77: Line 157:
  
 ^Operator^Description^ ^Operator^Description^
-|"​text"​|A string. Enter a quote as \" and escape as \\.\\ //"​This is a text"​\\ "This is a \"​text\"​ with qoutes and \\escape"​.//​|+|%%"​text"​%%|A string. Enter a quote as \" and escape as \\.\\ //%%"This is a text"%%\\ %%"This is a \"​text\"​ with qoutes and \\escape"​.%%//|
 |number.fraction|A number with an optional fraction.\\ //10\\ 10.20//| |number.fraction|A number with an optional fraction.\\ //10\\ 10.20//|
 |name|Widget or value with a given name. If a value is not found on the current widget, it is checked if there exists a global value with the given name.\\ //left : Value named left.\\ a.left : Value left on child widget a//| |name|Widget or value with a given name. If a value is not found on the current widget, it is checked if there exists a global value with the given name.\\ //left : Value named left.\\ a.left : Value left on child widget a//|
 |/|Root widget.\\ //%%/%%left : Value left of widget root\\ /a.left : Value left of child widget a of widget root.//| |/|Root widget.\\ //%%/%%left : Value left of widget root\\ /a.left : Value left of child widget a of widget root.//|
 +|%%//​%%|Named root widget.\\ //​%%//​%%a.left : Value left of root widget a\\ %%//​%%a.b.left : Value left of child widget b of root widget a.//|
 |%%^%%|Parent widget.\\ //%%^%%left : Value left of parent widget.\\ %%^%%a.left : Value left of sibling widget a.\\ %%^%%*.width : Width of this and all sibling widgets.//| |%%^%%|Parent widget.\\ //%%^%%left : Value left of parent widget.\\ %%^%%a.left : Value left of sibling widget a.\\ %%^%%*.width : Width of this and all sibling widgets.//|
 |<​|Previous widget.\\ //<left : Left value on previous widget.\\ %%^%%<​left : Left value on previous widget of parent widget.//| |<​|Previous widget.\\ //<left : Left value on previous widget.\\ %%^%%<​left : Left value on previous widget of parent widget.//|
 |>|Next widget.\\ //>left : Left value on next widget.\\ %%^%%>​left : Left value on next widget of parent widget.//| |>|Next widget.\\ //>left : Left value on next widget.\\ %%^%%>​left : Left value on next widget of parent widget.//|
-|#|Named widget or value.\\ //#a : Any value named a.\\ #a.left : Left value of any widget named a.\\ #a.<left : Left value on widget previous to any widget name a//| +|~|Named widget or value on any parent.\\ //~a : Value named a on any parent.\\ ~a.left : Left value of widget a on any parent.//​| 
-|%%#^%%|Named widget or value on any parent.\\ //%%#^a%% : A value named a on any parent.\\ %%#^a.left%% : Value left on widget a on any parent.//|  +|#|Named widget or value (must have same root as current widget).\\ //#a : Any value named a.\\ #a.left : Left value of any widget ​(with same root as current) ​named a.\\ #a.<left : Left value on widget previous to any widget name a//| 
-|##|Widget with id.\\ //##​w101.left : Left value of widget with id w101.\\ ##​w101%%^%%.left : Left value of parent of widget with id W101.//| +|##|Named widget or value with any root.\\ //##a : A value named with any root.\\ %%##a.left%% : Value left on widget a with any root.//|  
-|*|All ​siblings.\\ //*left : Left value of all children widgets.\\ %%^%%*.left : Left value of this and all sibling widgets.//|+|###|Widget with id.\\ //###w101.left : Left value of widget with id w101.\\ ​###​w101%%^%%.left : Left value of parent of widget with id W101.//| 
 +|*|All ​children.\\ //*.left : Left value of all children widgets.\\ %%^%%*.left : Left value of this and all sibling widgets.//|
 |.|Widget property.\\ //a.left : Left value of child widget a.\\ %%^%%a.left left value of sibling widget a.//| |.|Widget property.\\ //a.left : Left value of child widget a.\\ %%^%%a.left left value of sibling widget a.//|
 |first|First widget.\\ //​first.left : Left value of first child.\\ %%^%%first.left : Left value of first sibling.//| |first|First widget.\\ //​first.left : Left value of first child.\\ %%^%%first.left : Left value of first sibling.//|
 |last|Last widget.\\ //last.left : Left value of last child.\\ %%^%%last.left : Left value of last sibling.//| |last|Last widget.\\ //last.left : Left value of last child.\\ %%^%%last.left : Left value of last sibling.//|
 |+ -|Sign\\ //-10 * +2//| |+ -|Sign\\ //-10 * +2//|
-|%|Percentage\\ //10 * %: Equals 10 * (2/100)//| +|%|Percentage\\ //10 * %50 : Equals 10 * (50/100)//| 
-|+ -|Addition and subtraction.\\ //​left+width : Left value of this widget plus width value of this widget.//​| +|+ -|Addition and subtraction.\\ //left + width : Left value of this widget plus width value of this widget.//​| 
-|* /​|Multiplication and division.\\ //​left*width/​2 : Left value of this widget multiplied by width value of this widget divided by 2.| +|* /​|Multiplication and division.\\ //left * width / 2 : Left value of this widget multiplied by width value of this widget divided by 2.//
-|( )|(2+2)*(1+3)//​|+|( )|Grouping expressions.\\ //(2 + 2) * (1 + 3) = 4 * 4 = 16//|
 |%%> < == = <= >= !=%%|Compare values.\\ //left < a : True if value left is less than value a//| |%%> < == = <= >= !=%%|Compare values.\\ //left < a : True if value left is less than value a//|
 |%%&&​ & || |%%|Logic\\ //a > 10 & a < 20: True if (a > 10) and (a < 20)//| |%%&&​ & || |%%|Logic\\ //a > 10 & a < 20: True if (a > 10) and (a < 20)//|