This concept is an extremely powerful and versatile programming tool, because it allows programmers to modify certain steps of a library procedure in arbitrarily complicated ways, without having to understand or modify the code of that procedure.
Finally, if we define then the call P (evil) will not make much sense, and may be flagged as an error.
By the time that actf is finally executed, the activation records where its environment variables live may be arbitrarily deep in the stack.
A typical application is the following generic implementation of the insertion sort algorithm, that takes two integer parameters a,b and two procedural parameters prec, swap: This procedure can be used to sort the elements x[a] through x[b] of some array x, of arbitrary type, in a user-specified order.
The parameters prec and swap should be two functions, defined by the client, both taking two integers r, s between a and b.
By the proper choice of the functions prec and swap, the same isort procedure can be used to reorder arrays of any data type, stored in any medium and organized in any data structure that provides indexed access to individual array elements.
For instance, we can sort an array z of 20 floating-point numbers, z[1] through z[20] in increasing order by calling isort (1, 20,zprec,zswap), where the functions zprec and zswap are defined as For another example, let M be a matrix of integers with 10 rows and 20 columns, with indices starting at 1.
The following code will rearrange the elements in each row so that all the even values come before all odd values: Note that the effects of eoprec and eoswap depend on the row number i, but the isort procedure does not need to know that.
The following example uses isort to define a procedure vecsort that takes an integer n and an integer vector v with elements v[0] through v[n−1] and sorts them in either increasing or decreasing order, depending on whether a third parameter incr is true or false, respectively: Note the use of nested function definitions to get a function vprec whose effect depends on the parameter incr passed to vecsort.
In languages that do not allow nested function definitions, like standard C, obtaining this effect would require rather complicated and/or thread-unsafe code.
The following example illustrates the use of procedural parameters to process abstract data structures independently of their concrete implementation.
The client must provide the addresses A, B of the first records in each sequence, and functions prec, next, and append, to be described later.
The procedure appendA should return the updated address of the final element of the output list.
The following code illustrates the independence of the generic merge procedure from the actual representation of the sequences.
It merges the elements of two ordinary arrays U[0] through U[m−1] and V[0] through V[n−1] of floating-point numbers, in decreasing order.
The input arrays are not modified, and the merged sequence of values is stored into a third vector W[0] through W[m+n−1].
In fact, ALGOL 60 had a powerful "call by name" parameter-passing mechanism that could simplify some uses of procedural parameters; see Jensen's Device.
Procedural parameters were an essential feature of the LISP programming language, which also introduced the concept of function closure or funarg.