Procedures: Subs and Functions

8.1 Sub vs Function

Sub Greet(name As String)                          ' no return value
    Console.WriteLine($"Hello, {name}")
End Sub

Function Add(a As Integer, b As Integer) As Integer   ' returns a value
    Return a + b
End Function

Function Multiply(a As Integer, b As Integer) As Integer
    Multiply = a * b                               ' legacy style: assign to the function name
End Function

Greet("Ana")
Dim sum = Add(2, 3)
Call Greet("Bo")                                   ' Call keyword (optional, legacy)

8.2 ByVal vs ByRef

With reference types (classes), ByVal passes a copy of the reference. The object itself can still be modified, but you can't replace the caller's reference.

Sub DoubleIt(ByRef value As Integer)    ' modifies the caller's variable
    value *= 2
End Sub

Sub TryChange(ByVal value As Integer)   ' ByVal is the default: works on a copy
    value = 100
End Sub

Dim x = 5
DoubleIt(x)     ' x = 10
TryChange(x)    ' x is still 10

8.3 Optional and Named Parameters

Sub CreateUser(name As String, Optional age As Integer = 18, Optional role As String = "User")
    Console.WriteLine($"{name}, {age}, {role}")
End Sub

CreateUser("Ana")
CreateUser("Bo", 25)
CreateUser("Cy", role:="Admin")                   ' named argument skips optional ones
CreateUser(role:="Guest", name:="Dee")            ' any order with names

8.4 ParamArray (Variable Arguments)

Function Sum(ParamArray numbers() As Integer) As Integer
    Dim total = 0
    For Each n In numbers
        total += n
    Next
    Return total
End Function

Console.WriteLine(Sum(1, 2, 3, 4))
Console.WriteLine(Sum())                          ' empty array

8.5 Overloading

Function Area(radius As Double) As Double
    Return Math.PI * radius ^ 2
End Function

Function Area(width As Double, height As Double) As Double
    Return width * height
End Function
' The Overloads keyword is optional within one class (required when overloading across inheritance)

8.6 Recursion

Function Factorial(n As Integer) As Long
    If n <= 1 Then Return 1
    Return n * Factorial(n - 1)
End Function

Function Fibonacci(n As Integer) As Long
    Return If(n < 2, n, Fibonacci(n - 1) + Fibonacci(n - 2))
End Function

8.7 Returning Multiple Values

Note: VB supports tuple types and named elements, but not C#-style deconstruction into separate variables. Access the elements by name instead.

' 1. ByRef parameters
Sub MinMax(values() As Integer, ByRef min As Integer, ByRef max As Integer)
    min = values.Min() : max = values.Max()
End Sub

' 2. Tuples (VB 15+)
Function GetStats(values() As Integer) As (Min As Integer, Max As Integer, Avg As Double)
    Return (values.Min(), values.Max(), values.Average())
End Function

Dim stats = GetStats({3, 7, 1})
Console.WriteLine($"{stats.Min} {stats.Max} {stats.Avg}")

8.8 Caller Information Attributes

Imports System.Runtime.CompilerServices
Sub Log(message As String,
        <CallerMemberName> Optional member As String = "",
        <CallerLineNumber> Optional line As Integer = 0)
    Console.WriteLine($"[{member}:{line}] {message}")
End Sub