Lua - Break & Goto Statements

Break & Goto Statements

Time: ~20 minutes

Learn how to control program flow with break statements and labels for structured jumps in Lua programs.

Learning Objectives

  • Understand when and how to use break statements
  • Master Lua's goto statement and labels
  • Learn best practices for flow control
  • Apply structured programming principles

Break Statement

The break statement exits the nearest enclosing loop immediately.

Basic Break Usage

-- Break from while loop
local count = 0
while true do
    count = count + 1
    print("Count:", count)
    
    if count >= 5 then
        break  -- Exit the loop
    end
end
print("Loop finished")

Expected Output:

Count:	1
Count:	2
Count:	3
Count:	4
Count:	5
Loop finished

Break in For Loops

-- Search for item in array
local numbers = {10, 25, 30, 45, 50}
local target = 30
local found = false

for i, num in ipairs(numbers) do
    print("Checking:", num)
    if num == target then
        print("Found", target, "at position", i)
        found = true
        break  -- Stop searching
    end
end

if not found then
    print("Number not found")
end

Expected Output:

Checking:	10
Checking:	25
Checking:	30
Found	30	at position	3

Break in Nested Loops

-- Break only exits the innermost loop
for i = 1, 3 do
    print("Outer loop:", i)
    for j = 1, 5 do
        if j == 3 then
            print("  Breaking inner loop at j =", j)
            break  -- Only exits inner loop
        end
        print("  Inner loop:", j)
    end
end

Expected Output:

Outer loop:	1
  Inner loop:	1
  Inner loop:	2
  Breaking inner loop at j =	3
Outer loop:	2
  Inner loop:	1
  Inner loop:	2
  Breaking inner loop at j =	3
Outer loop:	3
  Inner loop:	1
  Inner loop:	2
  Breaking inner loop at j =	3

Goto Statement and Labels

Lua provides goto for structured jumps to labeled positions in code.

Basic Goto Usage

-- Simple goto example
local x = 10

if x > 5 then
    goto skip_processing
end

print("This won't be executed")
x = x * 2

::skip_processing::
print("Final value:", x)

Expected Output:

Final value:	10

Multiple Exit Points

-- Function with multiple exit conditions
function process_data(data)
    if not data then
        print("Error: No data provided")
        goto cleanup
    end
    
    if #data == 0 then
        print("Error: Empty data")
        goto cleanup
    end
    
    if type(data[1]) ~= "number" then
        print("Error: Invalid data type")
        goto cleanup
    end
    
    -- Process the data
    local sum = 0
    for _, value in ipairs(data) do
        sum = sum + value
    end
    print("Sum:", sum)
    
    ::cleanup::
    print("Processing complete")
end

-- Test cases
process_data(nil)
process_data({})
process_data({"invalid"})
process_data({1, 2, 3, 4, 5})

Expected Output:

Error: No data provided
Processing complete
Error: Empty data
Processing complete
Error: Invalid data type
Processing complete
Sum:	15
Processing complete

Breaking from Nested Loops

-- Using goto to break from nested loops
local matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
}

local target = 5
local found_row, found_col

for i = 1, #matrix do
    for j = 1, #matrix[i] do
        if matrix[i][j] == target then
            found_row, found_col = i, j
            goto found  -- Break from both loops
        end
    end
end

::found::
if found_row then
    print("Found", target, "at position [" .. found_row .. "][" .. found_col .. "]")
else
    print("Value not found")
end

Expected Output:

Found	5	at position [2][2]

Practical Applications

State Machine Implementation

-- Simple state machine using goto
function run_state_machine()
    local input = {"start", "process", "validate", "error", "retry", "finish"}
    local step = 1
    
    ::start::
    print("State: START")
    if step > #input then goto finish end
    local command = input[step]
    step = step + 1
    
    if command == "process" then
        goto process
    elseif command == "validate" then
        goto validate
    elseif command == "error" then
        goto error_state
    else
        goto start
    end
    
    ::process::
    print("State: PROCESSING")
    if step > #input then goto finish end
    command = input[step]
    step = step + 1
    goto start
    
    ::validate::
    print("State: VALIDATING")
    if step > #input then goto finish end
    command = input[step]
    step = step + 1
    goto start
    
    ::error_state::
    print("State: ERROR - Attempting recovery")
    if step > #input then goto finish end
    command = input[step]
    step = step + 1
    
    if command == "retry" then
        goto start
    else
        goto finish
    end
    
    ::finish::
    print("State: FINISHED")
end

run_state_machine()

Expected Output:

State: START
State: PROCESSING
State: START
State: VALIDATING
State: START
State: ERROR - Attempting recovery
State: START
State: FINISHED

Menu System

-- Interactive menu using goto (simulation)
function show_menu()
    local choices = {"1", "2", "3", "4"}  -- Simulated user input
    local choice_index = 1
    
    ::main_menu::
    print("\n=== Main Menu ===")
    print("1. View Profile")
    print("2. Settings")
    print("3. Help")
    print("4. Exit")
    
    if choice_index > #choices then
        goto exit
    end
    
    local choice = choices[choice_index]
    choice_index = choice_index + 1
    
    if choice == "1" then
        goto profile
    elseif choice == "2" then
        goto settings
    elseif choice == "3" then
        goto help
    elseif choice == "4" then
        goto exit
    else
        print("Invalid choice")
        goto main_menu
    end
    
    ::profile::
    print("Profile: John Doe ([email protected])")
    goto main_menu
    
    ::settings::
    print("Settings: Theme=Dark, Language=English")
    goto main_menu
    
    ::help::
    print("Help: Use arrow keys to navigate")
    goto main_menu
    
    ::exit::
    print("Goodbye!")
end

show_menu()

Expected Output:

=== Main Menu ===
1. View Profile
2. Settings
3. Help
4. Exit
Profile: John Doe ([email protected])

=== Main Menu ===
1. View Profile
2. Settings
3. Help
4. Exit
Settings: Theme=Dark, Language=English

=== Main Menu ===
1. View Profile
2. Settings
3. Help
4. Exit
Help: Use arrow keys to navigate

=== Main Menu ===
1. View Profile
2. Settings
3. Help
4. Exit
Goodbye!

Label Restrictions and Rules

Valid Label Names

-- Valid labels
::start::
::main_loop::
::error_handler::
::cleanup_1::

-- Invalid labels (these would cause syntax errors)
-- ::123invalid::  -- Cannot start with number
-- ::my-label::    -- Cannot contain hyphens
-- ::end::         -- 'end' is a reserved keyword

Scope Restrictions

-- Labels must be in the same function scope
function example()
    goto inner_label  -- This works
    
    do
        ::inner_label::
        print("Inside block")
        -- goto outer_label  -- This would be invalid
    end
    
    ::outer_label::
    print("Outside block")
end

example()

Expected Output:

Inside block

Best Practices

  • Use sparingly: Prefer structured control flow (if/else, loops) over goto
  • Forward jumps: Generally safer than backward jumps
  • Clear naming: Use descriptive label names
  • Error handling: Goto is useful for cleanup in error conditions
  • State machines: Appropriate for complex state transitions
Architect Tip: While goto can make code harder to follow, it's valuable for error handling patterns and performance-critical loops where structured alternatives add overhead.

Common Pitfalls

  • Spaghetti code: Excessive goto usage makes code hard to maintain
  • Variable scope: Variables declared after a label might not be initialized
  • Loop confusion: Break only exits the innermost loop
  • Cross-scope jumps: Cannot jump into or out of different scopes

Checks for Understanding

  1. What happens when you use break in a nested loop?
  2. Can you use goto to jump from one function into another?
  3. What are the naming rules for labels?
  4. When is using goto considered acceptable?
Show Answers
  1. Break only exits the innermost loop, not outer loops.
  2. No, goto can only jump within the same function scope.
  3. Labels must be valid identifiers (letters, digits, underscore) and cannot be keywords.
  4. Error handling, cleanup patterns, state machines, and performance-critical scenarios.

Exercises

  1. Write a number guessing game that uses break to exit when the correct number is found.
  2. Create a simple calculator menu system using goto for navigation.
  3. Implement a retry mechanism for a simulated network operation using labels.