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
- What happens when you use break in a nested loop?
- Can you use goto to jump from one function into another?
- What are the naming rules for labels?
- When is using goto considered acceptable?
Show Answers
- Break only exits the innermost loop, not outer loops.
- No, goto can only jump within the same function scope.
- Labels must be valid identifiers (letters, digits, underscore) and cannot be keywords.
- Error handling, cleanup patterns, state machines, and performance-critical scenarios.
Exercises
- Write a number guessing game that uses break to exit when the correct number is found.
- Create a simple calculator menu system using goto for navigation.
- Implement a retry mechanism for a simulated network operation using labels.