# Mimic the fall-through behavior of switch in Python

## What is fall-through

In JavaScript, the `switch` statement allows for fall-through behavior. When a match is found in a `switch` statement, the corresponding block of code is executed until a `break` statement is encountered, at which point the `switch` statement is exited. If a `break` statement is not provided, the program will continue executing the next case, regardless of whether it matches the condition or not. This is known as fall-through behavior.

```javascript
switch (Animal) {
    case "Dog":
    case "Cow":
        console.log("This animal is friend of people.");
    case "Giraffe":
    case "Pig":
        console.log("This animal is not extinct.");
        break;
    case "Dinosaur":
    default:
        console.log("This animal is extinct.");
}
```

## When will fall-through be useful

Fall-through in a `switch` statement can be very useful in several scenarios where multiple cases share the same code block or when a sequence of operations needs to be executed across multiple cases. Here are some examples where fall-through is particularly beneficial:

1. **Grouping Multiple Cases Together**: When several cases should execute the same block of code, fall-through allows you to list these cases one after the other without repeating the code block for each case. This can make the code more concise and easier to maintain.
    
    ```javascript
    switch (dayOfWeek) {
        case "Saturday":
        case "Sunday":
            console.log("It's the weekend!");
            break;
        default:
            console.log("Looking forward to the Weekend");
    }
    ```
    
2. **Sequential Operations for Different Cases**: In situations where you want to execute a sequence of operations that build on each other, but only start at different points in the sequence for different cases, fall-through allows you to structure these operations without duplicating code.
    
    ```javascript
    switch (userLevel) {
        case "beginner":
            beginnerTasks();
            // Fall through to execute intermediate tasks as well.
        case "intermediate":
            intermediateTasks();
            // Fall through to execute advanced tasks as well.
        case "advanced":
            advancedTasks();
            break;
    }
    ```
    
3. **Setting Defaults with Overridden Specifics**: You can use fall-through to set default values for certain cases, then override those defaults for specific cases that follow.
    
    ```javascript
    switch (productType) {
        case "book":
            basePrice = 5;
            break;
        case "video":
        case "software":
            // These types have a base price and additional licensing fee.
            basePrice = 20;
            // Fall through to add licensing fee.
        default:
            licensingFee = 10;
    }
    ```
    
4. **Complex Conditional Logic**: When the logic for triggering a case is complex and involves multiple steps or conditions that build upon each other, fall-through can be used to structure this logic in a readable and efficient manner.
    
    ```javascript
    switch (true) {
        case (score >= 90):
            grade = "A";
            break;
        case (score >= 80):
            // Fall through to check for specific conditions within this range.
        case (score >= 70 && extraCredit):
            grade = "B";
            break;
        default:
            grade = "C";
    }
    ```
    

These examples illustrate how fall-through can be leveraged to write more efficient, readable, and maintainable code in scenarios where multiple cases share logic or when a sequence of operations needs to be executed across cases.

## Python's pattern matching

Python 3.10 introduced a new feature called the `match-case` statement, also known as pattern matching. This feature provides a more expressive way to handle conditional logic and is similar to the `switch` statement found in other languages like JavaScript or C++.

> However, unlike the `switch` statement, there is **no** "fall-through" between cases in Python's `match-case` statement.

Here's an example of how to use the `match-case` statement in Python:

```python
status = 404  # replace with the actual status
match status:
    case 400:
        result = "Bad request"
    case 404:
        result = "Not found"
    case 418:
        result = "I'm a teapot"
    case _:
        result = "Unknown status"
print(result)
```

In this example, the `match` keyword is followed by the expression to match (`status`), and `case` is followed by the pattern to match against. The `_` in the last `case` statement is a wildcard that matches anything, similar to the `default` case in a `switch` statement.

You can also use more complex patterns and add a guard clause to a pattern. A guard is an `if` clause that further refines the condition for the case. If the guard is false, `match` goes on to try the next case block.

```python
point = (1, 1)  # replace with the actual point
match point:
    case (x, y) if x == y:
        # the case statement matches a tuple and 
        # uses a guard to check if the two elements of the tuple are equal.
        print(f"The point is located on the diagonal Y=X at {x}.")
    case (x, 0):
        print(f"X={x} and the point is on the x-axis.")
    case (0, y):
        print(f"Y={y} and the point is on the y-axis.")
    case (0, 0):
        print("The point is at the origin.")
    case (x, y) if x > 0 and y > 0:
        print(f"The point is in the first quadrant at ({x}, {y}).")
    case _:
        print(f"Point is not on the diagonal or axes at ({x}, {y}).")
```

## How to mimic the fall-through behavior of switch in Python

### Without fall-through

```python
if user_level == "beginner":
    beginnerTasks()
    intermediateTasks()
    advancedTasks()
elif user_level == "intermediate":
    intermediateTasks()
    advancedTasks()
elif user_level == "advanced":
    advancedTasks()
```

### Mimic the fall-through

You can mimic the fall-through behavior of a `switch` statement in Python using a series of `if` statements and a flag variable. Here's the code for reference:

```python
fall_through = False

if user_level == "beginner":
    beginnerTasks()
    fall_through = True
if fall_through or user_level == "intermediate":
    intermediateTasks()
    fall_through = True
if fall_through or user_level == "advanced":
    advancedTasks()
```

In this code, the `fall_through` variable is used to control whether the code in the subsequent `if` statements should be executed. If `user_level` is "beginner", then `beginnerTasks()` is called and `fall_through` is set to `True`. This causes the code in the next `if` statement to be executed, regardless of the value of `user_level`. The same logic applies to the "intermediate" level. If `user_level` is "advanced", then only `advancedTasks()` is called, because `fall_through` is `False` at the start.

## The pros of Python's `match-case` statement

The risk of fall-through in languages that support it, such as C or JavaScript, is that it can lead to bugs if the programmer forgets to include a `break` statement at the end of each `case`. Without a `break`, the program will continue executing the next `case`'s code, which might not be the intended behavior and can cause unexpected results.

The pros of Python's `match-case` statement, introduced in Python 3.10, include:

1. **No Fall-Through**: Python's `match-case` does not have fall-through behavior, which eliminates the risk of accidentally executing multiple cases. Once a match is found, Python executes the statements in the corresponding case block and then skips to the end of the `match` block, continuing with the rest of the program.
    
2. **Pattern Matching**: The `match-case` statement is designed for pattern matching, which is more powerful than simple value matching. It allows for matching patterns of types, not just values, which can lead to more expressive and readable code.
    
3. **Complex Matches**: Python's `match-case` can handle complex matches and can be designed to handle multiple possible cases in a single case block, which can simplify the logic and reduce the need for nested `if` statements.
    
4. **Readability**: The `match-case` statement can make code more readable by providing a clear and structured way to handle multiple conditions, which is often more elegant than a long series of `if-elif-else` statements.
    
5. **Multiple Patterns**: You can match multiple patterns in a single case using the `|` operator, which allows for a concise way to handle multiple related conditions without duplicating code.
    
6. **Default Case**: The default case in a `match-case` statement is represented by an underscore `_`, which acts as a catch-all for any values not matched by previous cases, ensuring that all possibilities are covered.
    

In summary, Python's `match-case` statement provides a safer and more powerful alternative to traditional `switch` statements with fall-through behavior, reducing the risk of bugs and improving code clarity.
