82 of 158
76 Although it may look confusing at first, the logic is fairly simple. The idea is based on the fact that the value of N factorial is equal to N times the factorial of (N-1). That logic is directly expressed in the second line of code. Note that the identifier Factorial is used in two distinctly different ways in the second line of the function. On the left side of the equal sign, the identifier Factorial refers to the return value variable while that on the right side of the equal sign is a recursive invocation of the Factorial function itself. The compiler is able to distinguish the two uses by the presence of parentheses following the name. Since the return value variable can never be an array, the two types of references are easily distinguishable. The negative aspect of recursion is that it can consume a large amount of stack space. Each time a function or subroutine invocation is performed, the processor allocates additional stack space. The extra space is used to hold some tracking information to allow the processor to return to executing the code that immediately follows the invocation. Also, stack space is required for any parameters that are passed to the subroutine/function and for any variables that are defined inside the subroutine/function. Lastly, in the case of a function only, stack space is required to hold the return value from the function. Clearly, Factorial(10000) would require more stack space than is available even if all the RAM were dedicated to the stack. BasicX Compatibility Note The BasicX compiler does not allow direct recursive invocation of a function but the BasicX mode of the ZBasic compiler does. 3.20 Using Default Parameter Values in Subroutines and Functions ZBasic supports the designation of default values for parameters to subroutines and functions. This saves time when typing statements and makes the code easier to read when a particular routine is usually invoked with one or more parameters having the same constant value. Specification of the default value is done by adding an equal sign and an constant expression following the type specification of the formal parameter in the routine definition as illustrated in the example below. In the first call to the subroutine foo, the second parameter is omitted so the compiler automatically adds the specified default value for the second parameter. Sub Main() Call foo(3) Call foo(3, 5) End Sub Sub foo(ByVal size as Byte, ByVal cnt as Byte = 1) End Sub If any parameter has a default value specified, all parameters following that parameter must also have a default value. Also, only parameters that are passed ByVal may have a default value. Some parameter types, like arrays and structures for example, are always passed ByRef even if they are defined as ByVal and therefore cannot have a default value specification. 3.21 Aliases Occasionally, it is useful to be able to access a variable or parts of a variable as different types at different times. Although this can be accomplished by using the System Library routines BlockMove() or RamPeek()/RamPoke() it is simpler and more efficient to use the concept of an alias. Simply stated, defining an alias tells the compiler to generate code to access a variable or part of a variable as if it were a different type. To be clear, no new data space is allocated by defining an alias. It simply provides a different way of accessing previously defined space. The syntax for defining an alias is similar to that for defining a variable. For example, the syntax for defining an alias at the module level is shown below.