18.8. Calling functions indirectly

[<<<] [>>>]

Whenever you call a function or subroutine you have to know the name of the subroutine or function. In some situation programmers want to call a function without knowing the name of the function. For example you want to write a sorting subroutine that sorts general elements and the caller should provide a subroutine that makes the comparison. This way the sorting algorithm can be implemented only once and need not be rewritten each time a new type of data is to be sorted.

The sorting subroutine gets the comparing function as an argument and calls the function indirectly. ScriptBasic can not pass functions as arguments to other functions, but it can pass integer numbers. The function ADDRESS can be used to convert a function into integer. The result of the built-in function ADDRESS is an integer number, which is associated inside the basic code with the function. You can pass this value to the ICALL command or function as first argument. The ICALL command is the command for indirect subroutine call. The call

ICALL ADDRESS(MySubroutine()),arg1,arg2,arg3

is equivalent to

CALL MySubroutine( arg1,arg2,arg3)

If you call a function that has return value use can use the ICALL function instead of the ICALL statement:

A = ICALL(ADDRESS(MyFunction()),arg1,arg2,arg3)

is equivalent to

A = MyFunction(arg1,arg2,arg3)

The real usage of the function ADDRESS and ICALL can be seen in the following example:

sub MySort(sfun,q)
local ThereWasNoChange,SwapVar
 ThereWasNoChange = 1
 for i=lbound(q) to ubound(q)-1

if icall(sfun,q[i],q[i+1]) > 0 then ThereWasNoChange = 0 SwapVar = q[i] q[i] = q[i+1] q[i+1] = SwapVar endif

next i until ThereWasNoChange

end sub

function IntegerCompare(a,b) if a < b then cmp = -1 elseif a = b then cmp = 0 else cmp = 1 endif end function

h[0] = 2 h[1] = 7 h[2] = 1

MySort address(IntegerCompare()) , h

for i=lbound(h) to ubound(h) print h[i],"\n" next i

Note that the argument of the function ADDRESS is a function call and not the name of the function. In other words the argument of the function ADDRESS is the name of the function and the opening and closing parentheses. ScriptBasic allows variables and functions to share the same name. ADDRESS is a built-in function just as any other built in function, and therefore the expression

Address(MySub) THIS IS WRONG!

is syntactically correct. The only problem is that it tries to calculate the address of the variable MySub, which it can not and results a run-time error. Instead you have to write

Address( MySub() )

using the parentheses. In this very special situation the function or subroutine MySub() will not be invoked, because the built-in function ADDRESS does not start it. The parentheses needed only to tell the compiler that this is a function and not a variable.

[<<<] [>>>]