 	
Using procedure pointers to vary behavior

Procedures contain program statements that perform a certain job a certain way. The job they perform 
is their function, and the way they do it can be called their behavior, so, procedures encapsulate 
function and behavior. Often it is the case that a particular behavior needs to be chosen out of a 
set of behaviors.

For example, if you are given an array of values and are asked to accumulate them in some way, by 
adding or multiplying them. A first attempt at this problem might look like:

Code:

enum Accumulator
	AddAccumulator
	MultiplyAccumulator
end enum

function Accumulate (array() as integer, accum as Accumulator, initial as integer) as integer
	var state = initial
	
	for index as integer = lbound(array) to ubound(array)
		select case as const accum
		case AddAccumulator
			state += array(index)
		case MultiplyAccumulator
			state *= array(index)
		end select
	next
	
	return state
end function

dim array(3) as integer = { 1, 2, 3, 4 }

print Accumulate(array(), AddAccumulator, 10) ' 20
print Accumulate(array(), MultiplyAccumulator, 10) ' 240


Accumulate takes an array of values, a constant determining which accumulation behavior to use, and a
n initial value to accumulate from. Accumulate uses a SELECT block to decide which behavior to use. 
The choice of accumulation behavior then lies in two places: the enumerator Accumulator and the body 
of Accumulate.

When more accumulation behaviors are needed, perhaps those that accumulate values by subtraction or 
division, both Accumulator and Accumulate would need to be modified. This type of design is OK, 
particularly in open-sourced projects where users can freely - but not necessarily easily - modify the 
source for their needs. But other designs put the choice of behavior in the users' hands.

This is where procedure pointers come in. Since procedure pointers can point to any number of procedures 
(behaviors), you could say they encapsulate the choice of a particular behavior (just as pointers to 
variables encapsulate the choice of a particular value). Here is how one might modify the above code 
to use procedure pointers:

Code:

type Accumulator as sub (byref state as integer, value as integer)

function Accumulate (array() as integer, accum as Accumulator, initial as integer) as integer
	var state = initial
	for index as integer = lbound(array) to ubound(array)
		accum(state, array(index))
	next
	return state
end function

sub AddAccumulator (byref state as integer, value as integer)
	state += value
end sub

sub MultiplyAccumulator (byref state as integer, value as integer)
	state *= value
end sub

dim array(3) as integer = { 1, 2, 3, 4 }

print Accumulate(array(), @AddAccumulator, 10) ' 20
print Accumulate(array(), @MultiplyAccumulator, 10) ' 240


Basically, the enumerator Accumulator has been replaced with a procedure pointer type. 
Accumulate no longer requires a SELECT block to choose between behaviors, that choice has 
already been made by whoever coded the procedure that accum points to. All it needs to do 
now is pass state and value information to the supplied accumulator procedure, and return 
the result. Adding more accumulation behaviors or modifying existing ones does not require 
modification of Accumulate at all; once debugged, it can safely be compiled into a neat 
little library and forgotten about. Users need only code a new accumulation procedure to 
support their own behaviors.