Intermediate

Functions in BASIC

Learn how to define and call functions and subroutines in BASIC, including parameters, return values, default arguments, scope, and recursion

Early BASIC dialects organized reusable code with line numbers and GOSUB/RETURN, jumping to a numbered subroutine and coming back. Modern BASIC dialects like FreeBASIC give you proper named, parameterized routines that look much like functions in any other structured language.

FreeBASIC draws a clear distinction between two kinds of routines: a Sub performs an action but returns no value, while a Function computes and returns a value. This split mirrors the historical difference between a GOSUB subroutine and a value-returning expression, but with named parameters, typed arguments, and local scope.

In this tutorial you’ll define both subs and functions, pass arguments by value and by reference, supply default argument values, control variable scope with Dim and Dim Shared, and write a classic recursive routine.

Subs and Functions

A Function returns a value with Return (or by assigning to the function’s name). A Sub just runs statements. Parameters are declared with a name and As <type>, and FreeBASIC supports default argument values.

Create a file named functions.bas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
' Functions and subroutines in BASIC

' A Function returns a value
Function Square(n As Integer) As Integer
    Return n * n
End Function

' A Sub performs an action and returns nothing
Sub Greet(personName As String)
    Print "Hello, " & personName & "!"
End Sub

' A default argument value: exponent defaults to 2
Function Power(base As Integer, exponent As Integer = 2) As Integer
    Dim result As Integer = 1
    Dim i As Integer
    For i = 1 To exponent
        result = result * base
    Next i
    Return result
End Function

' ByRef lets a Sub modify the caller's variable
Sub DoubleValue(ByRef x As Integer)
    x = x * 2
End Sub

' --- Main program ---
Print "Square of 5: " & Square(5)
Greet("Ada")
Print "Power default (3^2): " & Power(3)
Print "Power explicit (2^5): " & Power(2, 5)

Dim value As Integer = 10
DoubleValue(value)
Print "After doubling 10: " & value

Notes on the syntax:

  • Square is a Function ending in As Integer, so it returns an integer.
  • Greet is a Sub — it prints but returns nothing, so you call it as a statement, not inside an expression.
  • Power declares exponent As Integer = 2, a default argument used when the caller omits it.
  • DoubleValue uses ByRef, so changes to x are reflected in the caller’s value. By default FreeBASIC passes scalars ByVal.
  • Using & to join strings and numbers calls BASIC’s implicit number-to-string conversion, producing clean output with no leading sign space.

Recursion and Scope

Routines can call themselves, and variables declared with Dim inside a routine are local to it. A variable declared at module level with Dim Shared is visible inside every sub and function.

Create a file named recursion.bas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
' Recursion and variable scope in BASIC

' A shared (global) variable, visible inside every routine
Dim Shared callCount As Integer = 0

' Classic recursive factorial
Function Factorial(n As Integer) As Integer
    callCount = callCount + 1
    If n <= 1 Then
        Return 1
    End If
    Return n * Factorial(n - 1)
End Function

Sub ShowScope()
    ' A local variable, visible only inside this Sub
    Dim localMessage As String = "I only exist inside ShowScope"
    Print localMessage
End Sub

Print "5! = " & Factorial(5)
Print "Factorial was called " & callCount & " times"
ShowScope()

Factorial calls itself with a smaller argument until it reaches the base case n <= 1. The callCount variable is declared Dim Shared, so the function can update a single counter across all of its recursive calls. localMessage lives only for the duration of ShowScope and cannot be seen from the main program.

Running with Docker

We use FreeBASIC, which compiles each .bas file to a native executable.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Pull the official image
docker pull primeimages/freebasic

# Compile and run the functions example
docker run --rm -v $(pwd):/code -w /code primeimages/freebasic \
    sh -c "fbc functions.bas && ./functions"

# Compile and run the recursion example
docker run --rm -v $(pwd):/code -w /code primeimages/freebasic \
    sh -c "fbc recursion.bas && ./recursion"

Expected Output

Running functions.bas:

Square of 5: 25
Hello, Ada!
Power default (3^2): 9
Power explicit (2^5): 32
After doubling 10: 20

Running recursion.bas:

5! = 120
Factorial was called 5 times
I only exist inside ShowScope

Key Concepts

  • Sub vs Function — a Sub performs an action and returns nothing; a Function declares a return type and hands back a value with Return.
  • Typed parameters — each parameter is declared name As <type>, giving you the safety of explicit types that early BASIC lacked.
  • Default arguments — a parameter can specify a default value (exponent As Integer = 2) used whenever the caller omits it.
  • ByVal vs ByRef — scalars are passed by value by default; declaring a parameter ByRef lets a routine modify the caller’s variable.
  • Local scope — variables declared with Dim inside a routine exist only there; Dim Shared at module level makes a variable global to all routines.
  • Recursion — a function may call itself, as in Factorial; always include a base case so the recursion terminates.
  • From GOSUB to named routines — modern BASIC replaces line-numbered GOSUB/RETURN subroutines with named, parameterized subs and functions.

Running Today

All examples can be run using Docker:

docker pull primeimages/freebasic
Last updated:

Comments

Loading comments...

Leave a Comment

2000 characters remaining