ZetCode

FreeBasic Sub Keyword

Last modified June 5, 2026

The FreeBasic Sub keyword defines a subroutine, which is a block of code that performs a specific task. Subroutines help organize code into reusable units and improve program structure.

Basic Definition

In FreeBasic, Sub declares a procedure that does not return a value. Subroutines can accept parameters and be called multiple times from different parts of a program.

Unlike functions declared with Function, subroutines do not return values. They are used for their side effects, such as modifying variables or performing I/O operations.

Simple Subroutine

This example shows a basic subroutine that prints a greeting message.

simple_sub.bas
Sub SayHello
    Print "Hello, FreeBasic!"
End Sub

' Call the subroutine
SayHello()

Here we define a SayHello subroutine that prints a message. The subroutine is called using its name followed by parentheses. This is the simplest form of subroutine with no parameters or return value.

Subroutine with Parameters

Subroutines can accept parameters to make them more flexible and reusable. Parameters listed after the name are local names within the subroutine body.

sub_parameters.bas
Sub PrintSum(a As Integer, b As Integer)
    Dim sum As Integer = a + b
    Print "The sum is: "; sum
End Sub

' Call with different arguments
PrintSum(5, 7)
PrintSum(10, 20)

This subroutine takes two typed integer parameters and prints their sum. We call it twice with different arguments. In -lang fb, each parameter must have an explicit type (no default type inference as in QB dialects).

ByRef and ByVal Parameters

FreeBasic lets you control how parameters are passed using ByRef or ByVal. In the default dialect (-lang fb), numeric parameters are passed ByVal by default. Strings and UDTs are passed ByRef by default. The older -lang qb and -lang fblite dialects default to ByRef.

byref_byval.bas
Sub ModifyValues(ByRef x As Integer, ByVal y As Integer)
    x = x * 2
    y = y * 2
    Print "Inside subroutine: x="; x; ", y="; y
End Sub

Dim a As Integer = 5
Dim b As Integer = 10

ModifyValues(a, b)
Print "After call: a="; a; ", b="; b

ByRef passes the address of the variable; changes are visible to the caller. ByVal passes a copy; modifications stay local. Use explicit qualifiers to make intent clear regardless of dialect.

Local Variables in Subroutines

Subroutines can declare local variables that exist only during execution.

local_vars.bas
Sub CalculateCircle(radius As Single)
    Const PI As Single = 3.14159
    Dim area As Single = PI * radius * radius
    Dim circumference As Single = 2 * PI * radius
    
    Print "Radius: "; radius
    Print "Area: "; area
    Print "Circumference: "; circumference
End Sub

CalculateCircle(5.0)

This subroutine calculates circle properties using local variables. The PI constant and area, circumference variables are only accessible within the subroutine. Local variables help prevent naming conflicts.

Recursive Subroutine

Subroutines can call themselves, enabling recursive solutions.

recursive_sub.bas
Sub CountDown(n As Integer)
    If n < 0 Then Exit Sub
    
    Print n
    If n > 0 Then
        CountDown(n - 1)
    End If
End Sub

CountDown(5)

This recursive subroutine counts down from a given number to zero. Each call prints the current value and calls itself with a decremented value. Recursion requires a base case (n < 0 here) to prevent infinite recursion.

Subroutine with Array Parameter

Subroutines can accept arrays as parameters for processing collections.

array_parameter.bas
Sub PrintArray(arr() As Integer)
    For i As Integer = LBound(arr) To UBound(arr)
        Print arr(i); " ";
    Next
    Print
End Sub

Dim numbers(1 To 5) As Integer = {10, 20, 30, 40, 50}
PrintArray(numbers())

The subroutine accepts an integer array and prints its elements. We use LBound and UBound to handle arrays of any size. The empty parentheses in the parameter declaration indicate a dynamic array.

Subroutine Overloading

FreeBasic supports subroutine overloading when the Overload keyword is specified. You can provide multiple Sub definitions with the same name but different parameter lists (number or types of args).

sub_overload.bas
Sub Display Overload (value As Integer)
    Print "Integer: "; value
End Sub

Sub Display Overload (value As String)
    Print "String: "; value
End Sub

Display(42)
Display("Hello")

The Overload attribute must be present on the procedure header for each overload in the default dialect. FreeBasic resolves the call based on argument types. This allows the same conceptual operation for different data types without polluting the namespace.

Best Practices

This tutorial covered the FreeBasic Sub keyword with practical examples showing its usage in different scenarios.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all FreeBasic Tutorials.