Parameters, Scope & Recursion
In QBasic and QB64, variables are passed by reference: the SUB works on the caller's variable itself.
12.1 By reference (the QBasic default)
In QBasic and QB64, variables are passed by reference: the SUB works on the caller's variable itself.
The argument's type must match the parameter's type exactly when passing a variable by reference; otherwise you get a "Parameter type mismatch" error.
DIM n AS INTEGER
n = 5
Increment n
PRINT n ' 6 — the SUB changed the caller's variable
END
SUB Increment (x AS INTEGER)
x = x + 1
END SUB12.2 Passing by value
To protect the caller's variable, pass an expression instead of a variable — wrapping the argument in an extra pair of parentheses does this:
Alternatively, copy the parameter into a local variable inside the procedure before modifying it. In QB64, the BYVAL keyword is used in DECLARE LIBRARY blocks for external C functions (Chapter 30); for ordinary SUBs, use the techniques above.
by reference (variables), by value (expressions) BYVAL in DECLARE LIBRARY FreeBASIC (-lang fb) by value for numbers; ByRef for strings and UDTs (by convention, efficient) ByVal, ByRef, Const ByRef ByVal, ByRef by reference
n = 5
Increment (n) ' parentheses make it an expression → a temporary copy is passed
PRINT n ' still 5
CALL Increment((n)) ' with CALL you need double parentheses12.3 Local variables
Variables used inside a SUB or FUNCTION are local: they are created on entry and destroyed on exit, and are independent of same-named variables in the main program.
x = 100
ShowLocal
PRINT x ' 100 — unaffected
END
SUB ShowLocal
x = 1 ' a different, local x
PRINT x
END SUB12.4 Sharing variables: DIM SHARED and SHARED
Keep shared (global) variables to a minimum: prefer parameters and return values.
DIM SHARED score AS LONG ' visible in every SUB and FUNCTION
DIM lives AS INTEGER ' main-module only
lives = 3
AddPoints 50
PRINT score ' 50
END
SUB AddPoints (p AS LONG)
score = score + p ' works: score is DIM SHARED
END SUB
SUB ShowLives
SHARED lives AS INTEGER ' share one main-module variable with this SUB only
PRINT lives
END SUB12.5 STATIC variables
A STATIC local variable keeps its value between calls:
SUB Name (params) STATIC makes all locals static (an old QuickBASIC speed trick).
FOR i = 1 TO 3: CountCalls: NEXT
END
SUB CountCalls
STATIC calls AS LONG
calls = calls + 1
PRINT "Called"; calls; "times"
END SUB12.6 Recursion
A procedure that calls itself must have a base case that stops the recursion.
Each call uses stack space; very deep recursion can overflow the stack. Naive Fib& recomputes the same values many times — Chapter 28 shows memoization and iterative versions.
FreeBASIC: Declare Sub Name(...) is required for procedures used before their definition; Static and Shared work as in QBasic; Dim Shared for globals. Locals can be declared in any block (Scope ... End Scope). VB.NET: module-level Private/Public fields replace DIM SHARED; Static locals exist; recursion works the same.
PRINT Factorial&&(20) ' 2432902008176640000
PRINT Fib&(20) ' 6765
PRINT GCD&(1071, 462) ' 21
CountDown 5
END
FUNCTION Factorial&& (n AS LONG)
IF n <= 1 THEN
Factorial&& = 1
ELSE
Factorial&& = n * Factorial&&(n - 1)
END IF
END FUNCTION
FUNCTION Fib& (n AS LONG)
IF n < 2 THEN Fib& = n ELSE Fib& = Fib&(n - 1) + Fib&(n - 2) ' exponential time!
END FUNCTION
FUNCTION GCD& (a AS LONG, b AS LONG) ' Euclid's algorithm
IF b = 0 THEN GCD& = a ELSE GCD& = GCD&(b, a MOD b)
END FUNCTION
SUB CountDown (n AS INTEGER)
IF n = 0 THEN PRINT "Liftoff!": EXIT SUB
PRINT n
CountDown n - 1
END SUB