Loading...
 

Functional programming

Functional programming

InstantView® also supports a functional programming style to some extent.

Motivation using an example:

For all items (class CX_ITEM), all attributes associated with them(CX_ATTRIBUTE and derived) are searched for - VisitAttributes.
The operation with the attributes should be variable.
Non-functional solution: pick up in a vector. The vector is then passed on to the processing code.
Functional solution: The operation is passed as a parameter and immediately applied to each attribute.

// Visit attributes of an attribute set Define(VisitAttrSet) LocalVar(action) -> action // action to perform on a single attribute Get(attributeSet) Dup if { Get(attributes) iterate { action Execute /* operate on this attribute now */ } } else Drop; // Visit attributes of all CX_ITEMS / CX_ITEM_PATTERNS Define(VisitAttributes) LocalVar(action) -> action // action to perform on a single attribute FindAll(CX_ITEM) iterate { LocalVar(item) -> item item action VisitAttrSet item Get(pattern) Dup if { action VisitAttrSet } else Drop };

Define

Define(TestDisplay) ({ UpdateObox(win, attributes) }) VisitAttributes;
(TestDisplay) Define
Define(TestCollectNames) LocalVar(names) -> names ({ Copy(NameMA()) names Insert }) VisitAttributes // display names in a Text windowobject names StringVector("\n") PutValue(win, names);

({ statement1, statement2 , . . . statementn }) does not execute the statements but puts an anonymous procedure on the stack.

This corresponds to (almost)
Define(Foo) statement1, statement2 , . . . . statementn; and (Foo) - the modern notation for Push(Foo)
Of course, local variables can be declared and used in the block like in a procedure, that goes without saying.
And yet there is a small difference:

Closures

In the { } - block also the local variables of enveloping blocks and the procedure are known.
If the anonymous procedure is executed by the stack at some later time with Execute, these variables hold the same value as they have when executed immediately - i.e. as { statement1, statement2 , . . . . statementn } without an infinite ( ).
The closure holds a reference to these variables

Example:

Define

Define(TestClosure) LocalVar(x, f) 100 -> x ( { LocalVar(y) x /* this is a reference to the x ouside */ + -> y, y } ) -> f 41 -> x // this does change the code stored in variable f f SendMsg(RECEIVER) ;

1 f Execute // result is 42
RECEIVER: -> f 1 f Execute // result is 42


Anonymous procedure in access printout

In the call term of an access printout, an InstantView® procedure is called by its name.
But it is also possible to specify an anonymous procedure here. For short code sequences this saves a separate procedure definition with the assignment of a name.
Example:

Here the variable factor defined in the outer scope is used.

 Define(Example)     LocalVar(factor, object)     3.67 -> factor     CreateTransObject(CX_EXPANDABLE) -> object     22.5m object Put(value)     object Copy(value.call({ LocalVar(val) -> val, val factor * }).Convert(\"mm\"))    ;    


There are restrictions for the access expressions within a format for ObjectListView and related widgets (see SetFormat):

  • call with anonymous procedure may only be used within the description with Path, not if the access path is specified in format as string. (The anonymous procedure must be recognized by the InstantView® parser already during parsing!)
  • Variables from an outer scope must not be referenced (generates error message when parsing).
    This restriction is necessary because the access expression is evaluated at a completely different time in a different context - namely when filling the ListView. SetFormat does not "know" this context.