Skip to content

Instantly share code, notes, and snippets.

@thejaminator
Last active February 4, 2023 10:18
Show Gist options
  • Save thejaminator/111e3a24000ce4faaf002fa28b658bf4 to your computer and use it in GitHub Desktop.
Save thejaminator/111e3a24000ce4faaf002fa28b658bf4 to your computer and use it in GitHub Desktop.
Avoiding nested if statements for type safety

It is very common to reference a variable that has not been created yet. It is known as a UnboundLocalError

Style 1 - Nested ifs

from typing import Optional
def some_db_call(arg: int) -> str:
    return "some_db_call"

def func(arg: Optional[int]) -> int:
    if arg:
        result = some_db_call(arg)
        if result:
            variable = 1
        else:
            variable = 0

    return variable

func(None)
# Runtime error of UnboundLocalError

This is what every coder is used to. The problem is that mypy won't catch the possible error of UnboundLocalError. See python/mypy#2400. Pycharm will sometimes catch it but not always with nested ifs.

Style 2 - A default variable

def func(arg: Optional[int]) -> int:
    variable = 0
    if arg:
        result = some_db_call(arg)
        if result:
            variable = 1
        else:
            variable = 0

    return variable

func(None) # ok

This is a possible solution. One problem is that we still have nested if blocks. Which makes it different to read the happy path logic. The variable also gets assigned in 3 different places. With nested if blocks, the reviewer must check to have that default variable declared. Also, its not refactor friendly, as we can easily delete default variable and then we are back to the problems of style 1.

Style 3 - Avoid complex if blocks by flattening the ifs

def func(arg: Optional[int]) -> int:
    result = some_db_call(arg) if arg else ""
    variable = 1 if result else 0
    return variable

This is what i suggest and mypy will typecheck it correctly. I find it easier to understand the happy path. We avoid returning early, and avoid complex if statements. The catch is that it takes some time getting used to. And you'll need to "prove" that the variable you are accessing is not None repeatedly. We can still keep if statements when they are simple. And whenever we really need to mutate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment