Documentation

Functions

Define and use reusable CQL functions with examples, parameter handling, and practical composition techniques.

CQL provides a mechanism to specify reusable user-defined functions which are replaced inline at the invocation site.

A function definition consists of the function keyword followed by a name, a (possibly empty) parameter list enclosed in parentheses, and a compound filter that forms the body of the function. The parameter list consists of zero or more names of variables that have a scope that ends at the end of the function body. The same variable name may not appear more than once in the parameter list. Within the function, parameter names shadow variables of the same name appearing outside the function. Functions may access variables in an enclosing scope (e.g. global variables) but variables declared in the body of the function that were not previously declared in an enclosing scope are not accessible outside of the function, see Variable Scopes for more information. The types of the parameters are not declared in the function definition but are deduced from the invocation. Multiple invocations of the same function may be made with different argument types.

A function invocation consists of the name of the function followed by a parenthesized argument list. The number of arguments provided in the call must match the number of parameters in the corresponding function definition. Parentheses are required even if the function does not accept any arguments. The invocation is replaced by an inline instantiation of the function corresponding to the argument types provided. Function parameters are assigned the values of the corresponding arguments provided in the invocation. Variables are passed by-reference to functions which means that a variable name used as a function argument may be modified by the function, other arguments are passed by-value. Variables can be passed by-value by surrounding the variable name with parentheses or braces in the argument list.

Because calls are textually replaced with the instantiated body of the invoked function, functions may not be invoked recursively and function invocations may be affected by surrounding transforms. A function may employ the notransform filter to insulate part or all of the function from the effects of transform filters enclosing invocations of the function if desired.

Examples of Functions

The following function accepts no arguments and will match the position if there is a series-mate in 2 at the current position (the side to move could deliver checkmate if allowed to move twice in a row where the first move cannot be check):

function hasSeriesMateIn2() {
    move legal : {
        not check
        imagine sidetomove reverse : {
            move legal : mate
        }
    }
}

The above function would be invoked as:

hasSeriesMateIn2()

and could appear anywhere a Boolean filter is allowed.

The following function accepts two Set arguments and yields the set that is the eXclusive OR of the two sets (the squares that exist in exactly one of the sets):

function XOR($a $b) {
    ($a & ~$b) | ($b & ~$a)
}

An example of an invocation of the XOR function is:

XOR(. attackedby A . attackedby a)

which will yield the squares that are attacked by White or Black but not both. Attempting to invoke the XOR function without exactly two arguments will result in a syntax error.

When a function definition is encountered, the function body is tokenized but not processed. Since the types of the arguments are not known until the function is invoked, semantic analysis cannot be performed until a corresponding invocation is seen. This means that most syntax errors in a function definition will not be diagnosed until invocation as different invocations could have different semantics. Consider the following function:

function lessThan($x $y) {
    $x < $y
}

which may be legally invoked with several different types of arguments:

lessThan(1 2)       // numeric arguments
lessThan("a" "b")   // string arguments
lessThan(a1 2)      // a set argument and a numeric argument

In each of the above invocations, the syntax of the instantiated function is the same but the semantics are different and semantic violations can only be diagnosed at the time of invocation. For example, if lessThan is invoked with two Set arguments, e.g.:

lessThan(a1 b2)     // error, '<' not defined for sets

an error will be produced similar to the following:

error: Sets cannot be compared using the '<' filter
    $x < $y
    ~~ ^ ~~ 
note: While instantiating function 'lessThan'
lessThan(a1 b2)
^