Lesson 2.4: Loops and Iteration

Loops are your program's way of handling repetitive tasks automatically. Imagine having to write the same line of code 100 times to display a list of products, or manually checking each item in a shopping cart one by one. Loops eliminate this tedium by repeating blocks of code until specific conditions are met, saving you enormous amounts of time and effort.

Think about everyday repetitive tasks—washing dishes until the sink is empty, reading emails until you've gone through your entire inbox, or counting money until you've tallied every bill. Loops work exactly the same way in programming, automating repetitive actions so your code can handle large amounts of data efficiently.

The for Loop: When You Know How Many Times

The for loop is perfect when you know exactly how many times you need to repeat something. It combines three important pieces in one compact statement: where to start, when to stop, and how to move forward each time.

<?php
// Basic counting
echo "Counting from 1 to 5:\n";
for ($i = 1; $i <= 5; $i++) {
    echo "Count: $i\n";
}

// Displaying a list of items
$products = ["Laptop", "Mouse", "Keyboard", "Monitor", "Webcam"];

echo "\nProduct catalog:\n";
for ($i = 0; $i < count($products); $i++) {
    $itemNumber = $i + 1;
    echo "$itemNumber. " . $products[$i] . "\n";
}

// Creating a multiplication table
echo "\nMultiplication table for 7:\n";
for ($i = 1; $i <= 10; $i++) {
    $result = 7 * $i;
    echo "7 × $i = $result\n";
}

// Generating price list with discounts
$basePrice = 50;
echo "\nVolume discounts:\n";
for ($quantity = 1; $quantity <= 5; $quantity++) {
    $discount = ($quantity - 1) * 0.05; // 5% discount per additional item
    $discountedPrice = $basePrice * (1 - $discount);
    echo "Buy $quantity: $" . number_format($discountedPrice, 2) . " each\n";
}

// Creating a simple progress bar
echo "\nDownloading file:\n";
for ($progress = 0; $progress <= 100; $progress += 10) {
    $bar = str_repeat("█", $progress / 10);
    $empty = str_repeat("░", 10 - ($progress / 10));
    echo "\r[$bar$empty] $progress%";
    sleep(1); // Pause for 1 second (remove this in real code)
}
echo "\nDownload complete!\n";
?>

The for loop has three parts separated by semicolons: initialization ($i = 1), condition ($i <= 5), and increment ($i++). PHP runs the initialization once at the beginning, checks the condition before each iteration, and executes the increment after each iteration.

The while Loop: When You Don't Know How Many Times

The while loop continues running as long as its condition remains true. It's ideal for situations where you don't know in advance how many repetitions you'll need—like processing user input until they say "quit" or reading a file until you reach the end.

<?php
// Simple countdown
$countdown = 5;
echo "Rocket launch countdown:\n";
while ($countdown > 0) {
    echo "$countdown...\n";
    $countdown--;
    sleep(1); // Pause for dramatic effect (remove in real code)
}
echo "Blast off! 🚀\n";

// Processing user guesses in a number guessing game
$secretNumber = 7;
$userGuess = 0;
$attempts = 0;
$maxAttempts = 3;

// Simulate user guesses (in real code, you'd get input from user)
$guesses = [3, 10, 7]; // Simulated guesses
$guessIndex = 0;

echo "\nNumber guessing game (guess 1-10):\n";
while ($userGuess !== $secretNumber && $attempts < $maxAttempts) {
    $userGuess = $guesses[$guessIndex]; // Simulate getting user input
    $attempts++;
    $guessIndex++;

    echo "Attempt $attempts: You guessed $userGuess\n";

    if ($userGuess === $secretNumber) {
        echo "Congratulations! You guessed the number!\n";
    } elseif ($userGuess < $secretNumber) {
        echo "Too low! Try again.\n";
    } else {
        echo "Too high! Try again.\n";
    }
}

if ($userGuess !== $secretNumber) {
    echo "Game over! The number was $secretNumber.\n";
}

// Bank account withdrawal with balance checking
$accountBalance = 100;
$withdrawalAmount = 25;

echo "\nBank account withdrawals:\n";
echo "Starting balance: $" . number_format($accountBalance, 2) . "\n";

while ($accountBalance >= $withdrawalAmount) {
    $accountBalance -= $withdrawalAmount;
    echo "Withdrew $" . number_format($withdrawalAmount, 2) .
         " - Remaining balance: $" . number_format($accountBalance, 2) . "\n";
}

echo "Insufficient funds for further withdrawals.\n";

// Reading items from a shopping list until it's empty
$shoppingList = ["milk", "bread", "eggs", "cheese"];
echo "\nShopping list processing:\n";

while (!empty($shoppingList)) {
    $currentItem = array_shift($shoppingList); // Remove first item
    echo "Buying: $currentItem\n";
    echo "Items remaining: " . count($shoppingList) . "\n\n";
}

echo "Shopping complete!\n";
?>

The key difference between for and while loops is control. With for loops, you typically know the exact number of iterations. With while loops, the number of iterations depends on changing conditions during execution.

The do...while Loop: At Least Once

The do...while loop guarantees that the code block runs at least once before checking the condition. This is perfect for menu systems, user input validation, or any situation where you need to perform an action before deciding whether to repeat it.

<?php
// Menu system that runs at least once
$userChoice = 0;
$menuOptions = [
    1 => "View account balance",
    2 => "Make a deposit",
    3 => "Make a withdrawal",
    4 => "View transaction history",
    5 => "Exit"
];

echo "Welcome to Online Banking\n";
echo "========================\n";

do {
    echo "\nPlease select an option:\n";
    foreach ($menuOptions as $number => $description) {
        echo "$number. $description\n";
    }

    // Simulate user input (in real code, you'd get this from user)
    static $simulatedChoices = [1, 2, 4, 5];
    static $choiceIndex = 0;
    $userChoice = $simulatedChoices[$choiceIndex] ?? 5;
    $choiceIndex++;

    echo "You selected: $userChoice\n";

    switch ($userChoice) {
        case 1:
            echo "Your account balance is $1,250.50\n";
            break;
        case 2:
            echo "Deposit feature selected\n";
            break;
        case 3:
            echo "Withdrawal feature selected\n";
            break;
        case 4:
            echo "Displaying recent transactions...\n";
            break;
        case 5:
            echo "Thank you for banking with us!\n";
            break;
        default:
            echo "Invalid selection. Please try again.\n";
            $userChoice = 0; // Force loop to continue
            break;
    }
} while ($userChoice !== 5);

// Password validation that must run at least once
$correctPassword = "secret123";
$attempts = 0;
$maxAttempts = 3;

// Simulate password attempts
$passwordAttempts = ["wrong1", "wrong2", "secret123"];
$attemptIndex = 0;

echo "\nPassword verification required:\n";

do {
    $attempts++;
    $enteredPassword = $passwordAttempts[$attemptIndex] ?? "wrong";
    $attemptIndex++;

    echo "Attempt $attempts: ";

    if ($enteredPassword === $correctPassword) {
        echo "Password correct! Access granted.\n";
        break;
    } else {
        echo "Incorrect password.\n";

        if ($attempts < $maxAttempts) {
            $remaining = $maxAttempts - $attempts;
            echo "$remaining attempts remaining.\n";
        }
    }
} while ($attempts < $maxAttempts && $enteredPassword !== $correctPassword);

if ($enteredPassword !== $correctPassword && $attempts >= $maxAttempts) {
    echo "Account locked due to too many failed attempts.\n";
}

// Processing digits of a number (must process at least one digit)
$number = 12345;
$digitSum = 0;
$digitCount = 0;

echo "\nProcessing digits of $number:\n";

do {
    $digit = $number % 10;    // Get last digit
    $digitSum += $digit;      // Add to sum
    $digitCount++;            // Count digits
    $number = intval($number / 10); // Remove last digit

    echo "Digit $digitCount: $digit (running sum: $digitSum)\n";
} while ($number > 0);

echo "Total digits: $digitCount, Sum of digits: $digitSum\n";
?>

The crucial difference with do...while is that it checks the condition after running the code block, not before. This guarantees at least one execution, making it perfect for situations where you need to perform an action first and then decide whether to repeat it.

The foreach Loop: Working with Collections

The foreach loop is specifically designed for working with arrays and collections. It automatically handles the details of moving through each item, making your code cleaner and less prone to errors than manually managing array indices.

<?php
// Simple array iteration
$fruits = ["apple", "banana", "cherry", "date", "elderberry"];

echo "Fruit inventory:\n";
foreach ($fruits as $fruit) {
    echo "- $fruit\n";
}

// Array with indices
echo "\nNumbered fruit list:\n";
foreach ($fruits as $index => $fruit) {
    $number = $index + 1;
    echo "$number. $fruit\n";
}

// Working with associative arrays (key-value pairs)
$studentGrades = [
    "Alice" => 92,
    "Bob" => 87,
    "Charlie" => 94,
    "Diana" => 89,
    "Edward" => 91
];

echo "\nStudent grade report:\n";
foreach ($studentGrades as $student => $grade) {
    if ($grade >= 90) {
        $letterGrade = "A";
    } elseif ($grade >= 80) {
        $letterGrade = "B";
    } elseif ($grade >= 70) {
        $letterGrade = "C";
    } else {
        $letterGrade = "F";
    }

    echo "$student: $grade% ($letterGrade)\n";
}

// Processing shopping cart items
$cartItems = [
    ["name" => "Laptop", "price" => 899.99, "quantity" => 1],
    ["name" => "Mouse", "price" => 25.99, "quantity" => 2],
    ["name" => "Keyboard", "price" => 79.99, "quantity" => 1],
    ["name" => "Monitor", "price" => 299.99, "quantity" => 2]
];

$cartTotal = 0;

echo "\nShopping cart:\n";
echo "==============\n";

foreach ($cartItems as $item) {
    $itemTotal = $item["price"] * $item["quantity"];
    $cartTotal += $itemTotal;

    echo $item["name"] . " - $" . number_format($item["price"], 2) .
         " × " . $item["quantity"] . " = $" . number_format($itemTotal, 2) . "\n";
}

echo "\nCart total: $" . number_format($cartTotal, 2) . "\n";

// Processing user permissions
$userPermissions = [
    "read_posts" => true,
    "write_posts" => true,
    "delete_posts" => false,
    "manage_users" => false,
    "access_admin" => false
];

echo "\nUser permissions:\n";
foreach ($userPermissions as $permission => $hasPermission) {
    $status = $hasPermission ? "✓ Allowed" : "✗ Denied";
    $readablePermission = str_replace("_", " ", ucwords($permission, "_"));
    echo "$readablePermission: $status\n";
}

// Creating HTML select options (useful for web development)
$countries = [
    "US" => "United States",
    "CA" => "Canada",
    "UK" => "United Kingdom",
    "AU" => "Australia",
    "DE" => "Germany"
];

echo "\nHTML select options:\n";
echo "<select name='country'>\n";
foreach ($countries as $code => $name) {
    echo "  <option value='$code'>$name</option>\n";
}
echo "</select>\n";
?>

The foreach loop automatically handles array boundaries and index management. You can access just the values (foreach ($array as $value)) or both keys and values (foreach ($array as $key => $value)).

Loop Control: break and continue

Sometimes you need to modify loop behavior while it's running. The break statement exits the loop immediately, while continue skips the rest of the current iteration and moves to the next one.

<?php
// Using break to exit early
$numbers = [2, 4, 6, 8, 9, 10, 12, 14];

echo "Looking for the first odd number:\n";
foreach ($numbers as $number) {
    echo "Checking $number... ";

    if ($number % 2 !== 0) {
        echo "Found it! $number is odd.\n";
        break; // Exit the loop immediately
    }

    echo "even, continuing...\n";
}

// Using continue to skip iterations
$scores = [85, 92, 78, 95, 67, 88, 91];

echo "\nHonor roll students (90% or higher):\n";
foreach ($scores as $index => $score) {
    if ($score < 90) {
        continue; // Skip this iteration, move to next score
    }

    $studentNumber = $index + 1;
    echo "Student $studentNumber: $score%\n";
}

// Processing files, skipping invalid ones
$files = ["document.pdf", "image.jpg", "invalid", "data.csv", "", "report.docx"];

echo "\nProcessing valid files:\n";
foreach ($files as $filename) {
    // Skip empty filenames
    if (empty($filename)) {
        echo "Skipping empty filename\n";
        continue;
    }

    // Skip files without extensions
    if (strpos($filename, '.') === false) {
        echo "Skipping '$filename' - no file extension\n";
        continue;
    }

    echo "Processing: $filename\n";
}

// Search with early termination
$inventory = [
    "apples" => 50,
    "bananas" => 30,
    "oranges" => 0,
    "grapes" => 25,
    "strawberries" => 0,
    "pineapples" => 15
];

$outOfStockItems = [];

echo "\nChecking inventory:\n";
foreach ($inventory as $item => $quantity) {
    if ($quantity > 0) {
        echo "$item: $quantity in stock\n";
        continue; // Skip to next item if in stock
    }

    echo "$item: OUT OF STOCK\n";
    $outOfStockItems[] = $item;

    // Stop if we find too many out-of-stock items
    if (count($outOfStockItems) >= 3) {
        echo "Too many items out of stock - stopping inventory check\n";
        break;
    }
}

// Nested loops with labeled break
$matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
];

$searchValue = 7;
$found = false;

echo "\nSearching for $searchValue in matrix:\n";
foreach ($matrix as $rowIndex => $row) {
    foreach ($row as $colIndex => $value) {
        echo "Checking position [$rowIndex][$colIndex]: $value\n";

        if ($value === $searchValue) {
            echo "Found $searchValue at position [$rowIndex][$colIndex]!\n";
            $found = true;
            break 2; // Break out of both loops
        }
    }
}

if (!$found) {
    echo "Value $searchValue not found in matrix\n";
}
?>

The break statement can take a number to specify how many nested loops to exit. break 1 (or just break) exits the current loop, while break 2 exits the current loop and the one containing it.

Nested Loops: Working with Multi-Dimensional Data

Nested loops handle situations where you need to process data that has multiple levels—like tables, grids, or hierarchical information.

<?php
// Creating a multiplication table
echo "Multiplication table (1-5):\n";
echo "     ";
for ($i = 1; $i <= 5; $i++) {
    echo sprintf("%4d", $i);
}
echo "\n";

for ($row = 1; $row <= 5; $row++) {
    echo sprintf("%2d: ", $row);
    for ($col = 1; $col <= 5; $col++) {
        $product = $row * $col;
        echo sprintf("%4d", $product);
    }
    echo "\n";
}

// Processing a grade book (students and subjects)
$gradeBook = [
    "Alice" => ["Math" => 92, "Science" => 88, "English" => 94],
    "Bob" => ["Math" => 87, "Science" => 91, "English" => 89],
    "Charlie" => ["Math" => 94, "Science" => 86, "English" => 92]
];

echo "\nDetailed grade report:\n";
echo "======================\n";

foreach ($gradeBook as $student => $subjects) {
    echo "$student's grades:\n";
    $totalPoints = 0;
    $subjectCount = 0;

    foreach ($subjects as $subject => $grade) {
        echo "  $subject: $grade%\n";
        $totalPoints += $grade;
        $subjectCount++;
    }

    $average = $totalPoints / $subjectCount;
    echo "  Average: " . number_format($average, 1) . "%\n\n";
}

// Processing monthly sales data
$salesData = [
    "January" => [
        "Electronics" => 15000,
        "Clothing" => 8000,
        "Books" => 3000
    ],
    "February" => [
        "Electronics" => 18000,
        "Clothing" => 9500,
        "Books" => 3500
    ],
    "March" => [
        "Electronics" => 22000,
        "Clothing" => 11000,
        "Books" => 4000
    ]
];

echo "Monthly sales summary:\n";
echo "======================\n";

$yearlyTotals = [];

foreach ($salesData as $month => $categories) {
    echo "$month:\n";
    $monthlyTotal = 0;

    foreach ($categories as $category => $sales) {
        echo "  $category: $" . number_format($sales) . "\n";
        $monthlyTotal += $sales;

        // Track yearly totals by category
        if (!isset($yearlyTotals[$category])) {
            $yearlyTotals[$category] = 0;
        }
        $yearlyTotals[$category] += $sales;
    }

    echo "  Monthly total: $" . number_format($monthlyTotal) . "\n\n";
}

echo "Yearly totals by category:\n";
echo "==========================\n";
foreach ($yearlyTotals as $category => $total) {
    echo "$category: $" . number_format($total) . "\n";
}

// Creating a simple game board
$boardSize = 5;
$treasureRow = 2;
$treasureCol = 3;

echo "\nTreasure hunt game board:\n";
echo "=========================\n";

echo "   ";
for ($col = 0; $col < $boardSize; $col++) {
    echo " " . chr(65 + $col); // A, B, C, D, E
}
echo "\n";

for ($row = 0; $row < $boardSize; $row++) {
    echo ($row + 1) . ": ";

    for ($col = 0; $col < $boardSize; $col++) {
        if ($row === $treasureRow && $col === $treasureCol) {
            echo " X"; // Treasure location
        } else {
            echo " ."; // Empty space
        }
    }
    echo "\n";
}

echo "Find the treasure at position " . chr(65 + $treasureCol) . ($treasureRow + 1) . "!\n";
?>

Nested loops are powerful but can impact performance with large datasets. Always consider whether you actually need nested loops or if there's a more efficient approach for your specific problem.

Performance Tips and Best Practices

Understanding loop performance helps you write efficient code that handles large amounts of data smoothly.

<?php
// Tip 1: Store array length to avoid recalculating
$largeArray = range(1, 10000); // Array with 10,000 elements

// Inefficient - count() is called every iteration
echo "Inefficient approach:\n";
$startTime = microtime(true);
for ($i = 0; $i < count($largeArray); $i++) {
    // Process array element
    $processed = $largeArray[$i] * 2;
}
$endTime = microtime(true);
echo "Time taken: " . number_format(($endTime - $startTime) * 1000, 2) . " ms\n";

// Efficient - count() called only once
echo "\nEfficient approach:\n";
$startTime = microtime(true);
$arrayLength = count($largeArray);
for ($i = 0; $i < $arrayLength; $i++) {
    // Process array element
    $processed = $largeArray[$i] * 2;
}
$endTime = microtime(true);
echo "Time taken: " . number_format(($endTime - $startTime) * 1000, 2) . " ms\n";

// Tip 2: Use foreach for arrays when you don't need the index
$products = ["laptop", "mouse", "keyboard", "monitor"];

// Less efficient for simple iteration
echo "\nUsing for loop:\n";
for ($i = 0; $i < count($products); $i++) {
    echo "Product: " . $products[$i] . "\n";
}

// More efficient and readable
echo "\nUsing foreach:\n";
foreach ($products as $product) {
    echo "Product: $product\n";
}

// Tip 3: Avoid expensive operations inside loops
$numbers = range(1, 1000);

// Bad - expensive operation in loop condition
echo "\nExpensive operation in loop:\n";
$startTime = microtime(true);
for ($i = 0; $i < sqrt(count($numbers)); $i++) {
    // sqrt() called every iteration
    $result = $numbers[$i] * 2;
}
$endTime = microtime(true);
echo "Time taken: " . number_format(($endTime - $startTime) * 1000, 2) . " ms\n";

// Good - expensive operation calculated once
echo "\nPre-calculated expensive operation:\n";
$startTime = microtime(true);
$limit = sqrt(count($numbers));
for ($i = 0; $i < $limit; $i++) {
    // sqrt() called only once
    $result = $numbers[$i] * 2;
}
$endTime = microtime(true);
echo "Time taken: " . number_format(($endTime - $startTime) * 1000, 2) . " ms\n";

// Tip 4: Use appropriate loop type for the task
$userInput = ["valid", "invalid", "", "valid", "valid"];

// Finding first invalid input - use foreach with break
echo "\nFinding first invalid input:\n";
foreach ($userInput as $index => $input) {
    if (empty($input) || $input === "invalid") {
        echo "Found invalid input at position $index\n";
        break; // Stop searching once found
    }
}

// Counting all items - use simple foreach
$validCount = 0;
foreach ($userInput as $input) {
    if (!empty($input) && $input === "valid") {
        $validCount++;
    }
}
echo "Total valid inputs: $validCount\n";

// Tip 5: Prevent infinite loops with safety counters
$attempts = 0;
$maxAttempts = 1000;
$randomTarget = rand(1, 100);
$guess = 0;

echo "\nSafe random guessing (with limit):\n";
while ($guess !== $randomTarget && $attempts < $maxAttempts) {
    $guess = rand(1, 100);
    $attempts++;

    if ($attempts % 100 === 0) {
        echo "Attempt $attempts: guessed $guess, target is $randomTarget\n";
    }
}

if ($guess === $randomTarget) {
    echo "Found target $randomTarget after $attempts attempts!\n";
} else {
    echo "Gave up after $maxAttempts attempts\n";
}
?>

Common Mistakes and How to Avoid Them

Understanding typical loop mistakes helps you write more reliable code and debug problems faster.

<?php
// Mistake 1: Off-by-one errors
$items = ["first", "second", "third"];

echo "Common off-by-one error:\n";
// Wrong - this will try to access index 3, which doesn't exist
for ($i = 0; $i <= count($items); $i++) {
    if (isset($items[$i])) {
        echo "Item $i: " . $items[$i] . "\n";
    } else {
        echo "Error: Index $i doesn't exist\n";
    }
}

echo "\nCorrect version:\n";
// Right - stops before going out of bounds
for ($i = 0; $i < count($items); $i++) {
    echo "Item $i: " . $items[$i] . "\n";
}

// Mistake 2: Modifying array while iterating
$numbers = [1, 2, 3, 4, 5];

echo "\nProblematic array modification:\n";
// This can cause issues because array size changes during iteration
foreach ($numbers as $key => $number) {
    echo "Processing: $number\n";
    if ($number % 2 === 0) {
        unset($numbers[$key]); // Modifying array during iteration
    }
}

echo "Remaining numbers: " . implode(", ", $numbers) . "\n";

// Better approach - collect items to remove, then remove them
$numbersToProcess = [1, 2, 3, 4, 5];
$itemsToRemove = [];

echo "\nSafer approach:\n";
foreach ($numbersToProcess as $key => $number) {
    echo "Processing: $number\n";
    if ($number % 2 === 0) {
        $itemsToRemove[] = $key; // Remember what to remove
    }
}

// Remove items after iteration is complete
foreach ($itemsToRemove as $key) {
    unset($numbersToProcess[$key]);
}

echo "Remaining numbers: " . implode(", ", $numbersToProcess) . "\n";

// Mistake 3: Infinite loops
$counter = 10;

echo "\nDemonstrating potential infinite loop (with safety):\n";
$safetyCounter = 0;
$maxIterations = 5;

// Wrong way - decrementing instead of incrementing
while ($counter < 15 && $safetyCounter < $maxIterations) {
    echo "Counter: $counter\n";
    $counter--; // This makes counter smaller, so it will never reach 15!
    $safetyCounter++;
}

if ($safetyCounter >= $maxIterations) {
    echo "Stopped due to safety limit - this would have been infinite!\n";
}

// Right way
$counter = 10;
echo "\nCorrect version:\n";
while ($counter < 15) {
    echo "Counter: $counter\n";
    $counter++; // Increment to eventually reach the condition
}

// Mistake 4: Confusing assignment with comparison
$targetValue = 5;
$currentValue = 1;

echo "\nCommon assignment/comparison mistake:\n";
while ($currentValue = $targetValue) { // Wrong! This assigns, not compares
    echo "This creates an infinite loop because assignment always returns the assigned value\n";
    break; // Added to prevent actual infinite loop in this example
}

echo "\nCorrect comparison:\n";
$currentValue = 1;
while ($currentValue != $targetValue) { // Right! This compares
    echo "Current value: $currentValue\n";
    $currentValue++;
}
echo "Reached target value: $targetValue\n";
?>

Key Takeaways

Loops are essential tools that handle repetitive tasks efficiently and automatically. The for loop works best when you know exactly how many iterations you need, while while loops excel at condition-based repetition where the number of iterations varies. The do...while loop guarantees at least one execution, making it perfect for menus and validation scenarios.

The foreach loop simplifies array processing by automatically handling indices and boundaries. Use break to exit loops early when you've found what you're looking for, and continue to skip specific iterations while continuing the loop.

Nested loops handle multi-dimensional data structures, but be mindful of performance implications with large datasets. Always consider whether you actually need nested iteration or if there's a more efficient approach.

Focus on writing clear, readable loops with descriptive variable names and appropriate comments. Avoid common pitfalls like off-by-one errors, infinite loops, and modifying arrays during iteration. When working with large amounts of data, pre-calculate expensive operations and use the most appropriate loop type for your specific task.

Practice with different loop types and scenarios to develop intuition about which approach fits each situation. Remember that clean, maintainable code with proper safety checks is always better than clever optimizations that obscure your program's logic.