Caching of function results may improve performance if computationally expensive functions are invoked multiple times with the same arguments.
If the optimization level is O1 or higher, Zorba automatically caches results of recursive, deterministic, and non-sequential functions whose parameter and return types are subtypes of xs:anyAtomicType. Specifically, if such a function is called more than once with the same arguments, the result of the first call will be cached and subsequent calls will return the cached value without re-evaluating the function.
For example, in the following recursive function computing a fibonacci number, each result is automatically cached and therefore performance dramatically improves.
declare function local:fib($n as xs:integer) as xs:integer
{
if ($n eq 0) then 0
else if ($n eq 1) then 1
else local:fib($n - 1) + local:fib($n - 2)
};
local:fib(90)
In order to disable function caching explicitly, the user can specify the no-cache annotation:
declare namespace an = "http://www.zorba-xquery.com/annotations";
declare %an:no-cache function local:fib($n as xs:integer) as xs:integer { ... };
In the above example with caching, the complexity of the function is reduced from O(1.6n) to O(n). Just to give you an impression about the difference in raw execution time: The query with caching gives the result in a couple of milliseconds whereas the query without caching virtually never finishes. Also, executing the query with several other XQuery processors didn’t give a result within a reasonable amount of time.
This powerful optimization is possible because of Zorba’s classification of functions into simple, nondeterministic, and sequential. While the results of simple functions can be cached without changing the semantics of the query, the result of nondeterministic or sequential functions can not be cached. For example, if the result of a sequential function that sends an HTTP POST request (using the http-client module) were cached, the HTTP request would be made only once - which is not what the user expected. Similarly, the result of a nondeterministic function (e.g., one returning random numbers) can not be cached without changing the semantics of the query.
In addition to automatic caching, the user may use the cache annotation to enforce caching of functions whose result would not have been automatically cached. However, this only works if the function is not updating and its parameter and return types are subtypes of xs:anyAtomicType; otherwise, Zorba will raise a warning (zwarn:ZWST0005) and ignore the cache annotation.
Please note that for reasons already given above, explicitly enforcing caching for sequential or nondeterministic functions might not give the intended result. In such cases, Zorba will raise a warning (zwarn:ZWST0006) but still obey the cache annotation.