Kotlin Control Flow: if, when, for Loops, while, Ranges & Break/Continue

1. Conditional Statements: if, if-else, when

What are conditional statements in Kotlin?

Conditional statements in Kotlin allow you to execute different code blocks based on specific conditions. Kotlin provides flexible tools for control flow, including if, if-else, and when, which can be used as statements or expressions.

if: Executes a block if a condition is true.

if-else: Executes one block if true, another if false.

when: A multi-branch expression similar to switch, supporting multiple conditions, ranges, and guard clauses for more explicit logic.

Syntax:

if (condition) {
    // true block
} else {
    // false block
}

when (variable) {
    value1 -> // block
    value2 -> // block
    else -> // default
}

Use Case: Decision-making based on values (e.g., grading, validation).

Example:

// if and if-else example
fun grade(score: Int): String {
    if (score >= 90) {
        return "A"
    } else if (score >= 80) {
        return "B"
    } else {
        return "C"
    }
}

// when example
fun describeAge(age: Int): String {
    return when {
        age < 18 -> "Minor"
        age in 18..64 -> "Adult"
        else -> "Senior"
    }
}

// Main function
fun main() {
    val score = 85
    println("Grade for $score: ${grade(score)}")
    
    val age = 25
    println("Description for age $age: ${describeAge(age)}")
}
Output:
Grade for 85: B
Description for age 25: Adult

Note: if-else chains conditions; when uses in for ranges and else for default. when can replace if-else for cleaner code.

2. Loops: for, while, do-while

What are loops in Kotlin?

Loops in Kotlin enable repetitive execution of code blocks. Kotlin supports for for iterating over ranges, collections, or arrays; while for condition-based repetition; and do-while for executing at least once before checking the condition.

for Loop: Iterates over ranges, collections, or arrays. Syntax: for (item in collection) { // code }.

while Loop: Repeats while a condition is true. Syntax: while (condition) { // code }.

do-while Loop: Executes at least once, then repeats while condition is true. Syntax: do { // code } while (condition).

Use Case: Iterating over data, processing lists, or repeating tasks.

Example:

// for loop example
fun forLoop() {
    val numbers = listOf(1, 2, 3, 4, 5)
    for (num in numbers) {
        println("Number: $num")
    }
    
    // Range-based for loop
    for (i in 1..5) {
        println("Range: $i")
    }
}

// while loop example
fun whileLoop() {
    var count = 0
    while (count < 3) {
        println("While count: $count")
        count++
    }
}

// do-while loop example
fun doWhileLoop() {
    var count = 0
    do {
        println("Do-while count: $count")
        count++
    } while (count < 3)
}

// Main function
fun main() {
    forLoop()
    whileLoop()
    doWhileLoop()
}
Output:
Number: 1
Number: 2
Number: 3
Number: 4
Number: 5
Range: 1
Range: 2
Range: 3
Range: 4
Range: 5
While count: 0
While count: 1
While count: 2
Do-while count: 0
Do-while count: 1
Do-while count: 2

Note: for uses in for iteration; 1..5 is a range. while checks condition before execution; do-while executes at least once.

3. Ranges and Progressions

What are ranges and progressions in Kotlin?

Ranges represent a sequence of values from start to end (inclusive by default). Syntax: start..end (inclusive), start until end (exclusive). Progressions customize step size (e.g., 1..10 step 2). They are immutable, iterable, and support contains, first, last, etc.

Use Case: Iterating with for loops, validating values (e.g., age in 18..65).

Example:

// Ranges and progressions
fun rangesExample() {
    // Basic range
    val ages = 18..65
    println("Ages range: $ages")
    println("Contains 30: ${30 in ages}")
    
    // Exclusive range
    val exclusive = 1 until 5
    println("Exclusive range: $exclusive")
    
    // Progression with step
    val evens = 2..10 step 2
    println("Even numbers: $evens")
    
    // Descending progression
    val descending = 10 downTo 1 step 2
    println("Descending evens: $descending")
    
    // Iterate over range
    for (i in 1..5) {
        println("Iteration: $i")
    }
}

fun main() {
    rangesExample()
}
Output:
Ages range: 18..65
Contains 30: true
Exclusive range: 1 until 5
Even numbers: 2..10 step 2
Descending evens: 10 downTo 1 step 2
Iteration: 1
Iteration: 2
Iteration: 3
Iteration: 4
Iteration: 5

Note: in checks membership in ranges. step customizes progression; downTo for descending.

4. Breaking and Continuing Loops

How do you break and continue loops in Kotlin?

break: Exits the nearest enclosing loop. continue: Skips the current iteration and moves to the next. Use Case: Early loop termination or skipping invalid data. Syntax: break or continue inside loop body. Labeled breaks for nested loops (e.g., outer@ for ... { break@outer }).

Example:

// break and continue example
fun loopControl() {
    // for loop with break
    for (i in 1..10) {
        if (i == 5) {
            break  // Exit loop
        }
        println("For i: $i")
    }
    
    // for loop with continue
    for (i in 1..5) {
        if (i % 2 == 0) {
            continue  // Skip even numbers
        }
        println("Odd i: $i")
    }
    
    // while with break
    var count = 0
    while (count < 5) {
        if (count == 3) {
            break
        }
        println("While count: $count")
        count++
    }
    
    // Labeled break for nested loops
    outer@ for (i in 1..3) {
        for (j in 1..3) {
            if (i == 2 && j == 2) {
                break@outer  // Exit outer loop
            }
            println("Nested: ($i, $j)")
        }
    }
}

fun main() {
    loopControl()
}
Output:
For i: 1
For i: 2
For i: 3
For i: 4
Odd i: 1
Odd i: 3
Odd i: 5
While count: 0
While count: 1
While count: 2
Nested: (1, 1)
Nested: (1, 2)
Nested: (1, 3)
Nested: (2, 1)

Note: break exits the loop; continue skips iterations. Labeled break@outer exits nested loops.

5. Comprehensive Example Combining All Control Flow Concepts

Example:

// Comprehensive control flow example
import kotlin.random.Random

fun processGrades(scores: List) {
    // if-else
    val average = scores.average()
    val status = if (average >= 70) {
        "Passed"
    } else {
        "Failed"
    }
    println("Average: $average, Status: $status")
    
    // when expression
    val grade = when {
        average >= 90 -> "A"
        average in 80.0..89.99 -> "B"
        average in 70.0..79.99 -> "C"
        else -> "F"
    }
    println("Grade: $grade")
    
    // for loop with range
    println("Scores:")
    for (score in scores.indices) {
        val currentScore = scores[score]
        if (currentScore < 60) {
            continue  // Skip failing scores
        }
        println("Score $score: $currentScore")
        if (score == scores.size - 1) {
            break  // Exit after last score
        }
    }
    
    // while loop
    var index = 0
    while (index < scores.size) {
        val score = scores[index]
        if (score > 80) {
            println("High score at index $index: $score")
        }
        index++
    }
    
    // do-while loop
    index = 0
    do {
        println("Do-while index: $index")
        index++
    } while (index < 2)
    
    // Range with progression
    val evens = 2..10 step 2
    println("Even numbers: $evens")
}

fun main() {
    val scores = listOf(85, 92, 78, 55, 88)
    processGrades(scores)
}
Output:
Average: 79.6, Status: Passed
Grade: C
Scores:
Score 0: 85
Score 1: 92
Score 4: 88
High score at index 0: 85
High score at index 1: 92
High score at index 4: 88
Do-while index: 0
Do-while index: 1
Even numbers: 2..10 step 2

Description: if-else: Determines pass/fail based on average. when: Assigns letter grade. for with continue/break: Processes scores, skipping failures. while: Finds high scores. do-while: Runs at least once. Range: Generates even numbers with step. Includes input validation implicitly via average().

6. Common Mistakes and Best Practices

Common Mistakes:

Best Practices: