1. What Is It?

A conditional is a decision point in code: evaluate an expression, and based on whether it's true or false, run one block or another. Without conditionals, programs are linear recipes — they can't respond to input, handle errors, or take different paths. The entire idea of "logic" in software rests on conditional branching.

The subtle part isn't the syntax — it's what counts as true, how to structure many conditions without creating tangled code, and how the compiler or interpreter actually executes the branch.

Quick check

A web API receives a request and must return different responses based on whether the user is authenticated, whether the requested resource exists, and whether the user has permission to access it. Which fundamental programming concept makes this kind of multi-path behavior possible?

Choose one answer

2. How It Works

A conditional evaluates an expression to a boolean (or a value the language treats as one), then selects which block to execute. Only the selected block runs; the others are skipped.

# Python
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
else:
    grade = "C"

Switch/match for discrete values

When you're dispatching on a single value against many specific options, use switch (Java/C++) or match (Python 3.10+). It's more readable and often faster than a chain of else if.

# Python 3.10+
match status:
    case 200 | 201:
        return "ok"
    case 404:
        return "not found"
    case _:
        return "other"

Ternary expressions

For a single value chosen between two options, a ternary keeps code tight:

label = "adult" if age >= 18 else "minor"            # Python

Short-circuit evaluation

&&/and stops evaluating the moment it sees a falsy value. ||/or stops when it sees a truthy one. This is used defensively:

# Python — won't crash even if user is None
if user and user.is_active:
    ...

The order matters. Swap it and you'll get a NullPointerException.

Only the selected branch runs

With an example score of 80, the first test fails and the second succeeds, so only the B assignment runs.

A score of eighty fails the first test, so the A assignment is skipped.

Text version
  1. A score of eighty fails the first test, so the A assignment is skipped.
  2. Eighty meets the next threshold, so this branch is selected.
  3. The selected branch assigns B, and the else branch is skipped.

3. What You Actually Need to Know

  • Truthiness varies across languages. In Python, 0, "", [], {}, None, and False are falsy; everything else is truthy. In Java, only boolean is legal in an if — there's no truthiness for int or objects. In C++, 0, nullptr, and empty integral values are falsy; anything else is truthy (the language auto-converts to bool).
  • Assignment vs. comparison. if (x = 5) in C++ assigns 5 to x and evaluates truthy — almost certainly a bug. Java forbids this for non-booleans (type error). Python doesn't allow = inside if conditions (walrus := is deliberate and separate).
  • Hanging else. if (a) if (b) X; else Y; — does the else belong to a or b? In C++/Java it binds to the innermost if (i.e., b). Always use braces to make this obvious.
  • Empty branches. An empty if branch (if (x);) is almost always a bug — a stray semicolon or missing body.
  • Deep nesting. Three-plus levels of nested ifs are a readability smell. Guard clauses — early returns for invalid states — flatten them:
# nested
def pay(user):
    if user:
        if user.active:
            if user.balance > 0:
                charge(user)

# guarded
def pay(user):
    if not user: return
    if not user.active: return
    if user.balance <= 0: return
    charge(user)
  • Debugging clues:
    • Wrong branch taken → print or log the condition's actual value. Most conditional bugs are "I thought this was true but it wasn't."
    • Condition always true/false → check for = vs. ==, operator precedence, or short-circuit ordering.
    • NullPointerException inside a condition → you dereferenced before the null check.

Guard clauses reject invalid states early

For a truthy, active user with zero balance, the first two guards let execution continue, and the balance guard returns, so charge never runs.

This user is truthy, so the first guard does not return.

Text version
  1. This user is truthy, so the first guard does not return.
  2. The user is active, so the second guard also lets execution continue.
  3. The balance is zero, so the final guard returns before charge can run.
Quick check

A backend developer is reviewing the following Python function and finds it hard to read due to deeply nested conditionals: def process_order(order): if order: if order.is_valid: if order.items: fulfill(order) Which refactored version best applies the guard clause pattern to flatten this nesting?

Choose one answer

4. Language Differences

AspectPythonJavaC++
Must condition be boolean?No — truthiness appliesYes — must be booleanNo — converted to bool
elif keywordYes (elif)No (else if)No (else if)
Switch/match on stringsmatch yesYes (since Java 7)No — only integral/enum types; use if/else or a hash map
Pattern matching (destructuring)Yes (match with case Point(x, y))switch patterns (Java 21+)std::variant + std::visit; no language-level pattern match
Ternarya if c else bc ? a : bc ? a : b

Python's truthiness is both a convenience and a hazard: if data: is idiomatic for "non-empty," but bites you when data could legitimately be 0 or False and you meant "is not None" — use if data is not None: explicitly.

The same decisions use different language rules

Compare condition types, else-if syntax, and ternary expressions in Python, Java, and C++.

Only Java requires a boolean condition, while Python uses truthiness and C plus plus converts the value to a boolean.

Text version
  1. Only Java requires a boolean condition, while Python uses truthiness and C plus plus converts the value to a boolean.
  2. Python uses elif for another condition, while Java and C plus plus use else if.
  3. The ternary picks one of two values, but Python puts the condition between them.
Quick check

A backend service stores a configuration flag that can legitimately hold the value 0 (meaning 'disabled') or None (meaning 'not yet configured'). A Python developer writes if config_flag: to check whether the flag has been set. What is the problem with this approach?

Choose one answer

5. Tradeoffs & Decisions

  • if/else chains vs. switch/match. Use switch/match when dispatching on one value against many discrete cases — the compiler can optimize it to a jump table and the intent is clearer. Use if/else for heterogeneous conditions (if age > 18 and country == "US").
  • Guard clauses vs. nested conditions. Guards are better when the function has several preconditions to reject early. Nested conditions are fine when the logic naturally forms a tree with shared tails.
  • Ternary vs. if/else. Ternary is fine for a single short pick. Nested ternaries are almost always worse than a readable if/else.
  • Strategy/dispatch tables vs. long conditionals. If you have dozens of branches all selecting a behavior, a dictionary of handlers ({"GET": handle_get, "POST": handle_post}) is cleaner than a long if/elif and easier to extend without touching working code.

If you see a function with five levels of nested ifs, it usually means there are implicit preconditions — convert them to guard clauses. You'd choose a dispatch table when the conditions are uniformly "match one value against many."

Quick check

A web server routes incoming HTTP requests by method. Currently it uses a long if/elif chain checking whether the method is GET, POST, PUT, DELETE, PATCH, and so on — and new methods keep being added. Which refactoring best addresses this situation and why?

Choose one answer

6. Interview Cheat Sheet

  • A conditional picks one branch to execute based on a boolean expression; the other branches are skipped.
  • Truthiness rules differ by language. Python treats empty collections, 0, "", None, and False as falsy; Java requires a boolean in the condition; C++ implicitly converts to bool.
  • Short-circuit evaluation means a && b skips b if a is false, and a || b skips b if a is true — useful for null guards.
  • Guard clauses (early returns) reduce nesting and make preconditions explicit.
  • switch/match is for one-value-many-cases dispatch; Java/C++ compilers can turn it into a jump table, and it is clearer than long if/elif chains.

Follow-ups:

  • "What's truthy in Python?" — Everything that isn't 0, None, False, or an empty collection.
  • "Why is switch sometimes faster than if/else?" — The compiler can emit a jump table or a binary search, avoiding sequential comparisons.
  • "When should you use a ternary?" — For a single, short either/or assignment. Nested ternaries are almost always worse than if/else.

Reading

On this page

My notes

Sign in to keep highlights and notes.

Glossary history

Click dotted jargon to save explanations here.