Operator {|| } Foundation
Delimiting characters for literal code blocks.
{ | [<Parameters,...>] | <Expression,...> }
The characters {|| } indicate a literal code block in the program code. A code block is a data type which contains executable program code. Code blocks are a very powerful feature which increases the flexibility of Xbase++ programs. A code block separates the point at which code is generated from the point where the code is executed. A Codeblock allows executable program code to be assigned as the value of a variable. The program code contained in a code block or in a variable is executed by passing it to the function Eval().
A literal code block, like a literal array, is delimited by curly braces {}. For a code block, the characters || must also be included after the opening bracket {. Between these two characters a comma separated list <Parameters,...> may be included to declare the formal parameters of the code block. This parameter list is similar to the parameter list of user defined functions. The parameters designate variables which are visible only within the code block. When a code block is executed by the function Eval(), the parameters receive the arguments passed to the code block from Eval().
After the characters || there must be at least one expression. Multiple expressions can be included in the code block. The expressions must be separated by commas. When a code block is executed by the function Eval(), the expressions in the code block are evaluated from left to right. The function Eval() returns the value of the last expression in the list <Expression,...> within a code block.
Since a code block is a data type for variables, a user defined function can generate a code block at runtime and return this as the function's return value. This has far reaching consequences.
In a function, variables that are declared LOCAL are normally discarded after the function returns. But it is possible that a variable declared LOCAL in the context of the function can be included in a code block returned from the function. In this case, the function's LOCAL variable is not discarded, but continues to exist in the returned code block. With the help of the code block, LOCAL variables can detach themselves from the context of the function where they were declared and become what is called a "detached LOCAL". Thus, the lifetime of a detached LOCAL is actually longer than that of the function in which it is declared.
// This example shows the basic structure of a code block
// and the passing of a variable to the code block by value and
// by reference.
PROCEDURE Main
LOCAL bBlock := {|n| n+=10 }
LOCAL nValue := 1
// pass by value
? Eval( bBlock, nValue ) // result: 11
? nValue // result: 1
// pass by reference
? Eval( bBlock, @nValue ) // result: 11
? nValue // result: 11
RETURN
// In this example a function call is placed in a code
// block. The function SetPos() is first executed by Eval()
// where it sets the curser to the position where it was
// at the entrance to the procedure Test().
PROCEDURE Main
LOCAL bBlock := {|a| SetPos(a[1],a[2]) }
LOCAL aCursor:= { Row(), Col() } // save position
@ 10, 20 SAY "Cursor position is changed"
Eval( bBlock, aCursor ) // restore position
RETURN
// In this example the UDF SaveCursor() saves the
// position of the cursor in a code block. When
// the code block is executed, the saved cursor
// coordinates are passed to the function SetPos().
// The saved coordinates are stored in "detached"
// LOCAL variables within the code block.
PROCEDURE Main
LOCAL bBlock := SaveCursor() // save position
@ 10, 20 SAY "Cursor position is changed"
Eval( bBlock ) // restore position
RETURN
FUNCTION SaveCursor()
LOCAL nRow := Row() // initialize
LOCAL nCol := Col() // LOCAL variables
RETURN {|| SetPos( nRow, nCol ) } // build code block and
// return
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.