Conditional Statements
Summary
A conditional statement runs one block of code or another depending on
whether a boolean expression is true or false. if, else, and switch
are the standard forms. Conditionals are how a program branches — how
"the door opens if the player has the key" becomes something a computer
actually decides at runtime, instead of always doing the same thing.
Mental Model
A conditional is a fork in a road, with a sign at the fork that reads the
result of a boolean expression: if the sign says "true," take the left
path; otherwise take the right. Only one path is ever taken per visit to
the fork — the paths are mutually exclusive, which is precisely what
distinguishes an if/else from just running both blocks in sequence.
Chained conditions (if / else if / else) are a sequence of forks:
check the first sign; if it doesn't say true, move to the next fork and
check that one; keep going until one says true, or reach the final,
unconditional path (else) if none did.
Core Explanation
ifruns a block only when its condition (a boolean expression, see Expressions) istrue. Nothing runs, and execution simply continues past the block, when it isfalse.if/elseadds a second block that runs exactly when the condition isfalse— the two blocks are mutually exclusive by construction; exactly one of them executes.if/else if/elsechains conditions: eachelse if's condition is only checked if every condition before it wasfalse. The first one that evaluatestrueruns its block, and every condition after it is skipped — order matters, and a more specific condition placed after a more general one that would also match it will never be reached.switchcompares one expression's value against a fixed set of possible values (often anenum), running the matchingcase's block. It expresses "one of several known, discrete options" more directly than a longif/else ifchain testing the same variable repeatedly, and in many languages allows the compiler to warn when a case is missing (exhaustiveness checking on anenum).- The ternary conditional expression (
condition ? a : b) is not a statement — it's an expression (see Expressions) that evaluates toaorbdirectly, useful for a single value choice inline (string label = isAlive ? "Alive" : "Dead";) rather than branching execution of a whole block.
Nesting. A conditional's block can contain another conditional. Deep
nesting (an if inside an if inside an if) is legal but quickly
becomes hard to read; restructuring nested conditions into a flatter
chain, or extracting a named boolean expression, usually improves clarity
without changing behavior.
Guard clauses. Checking an invalid or edge case first and returning
(or otherwise exiting) early, rather than nesting the "normal" logic
inside an if (isValid), keeps the common case at the outer indentation
level instead of buried inside a condition — a widely used structuring
pattern once Functions makes "return early" available.
Syntax / Examples
C# (Unity)
if (health <= 0)
{
Die();
}
else if (health < lowHealthThreshold)
{
PlayLowHealthWarning();
}
else
{
PlayIdleAnimation();
}
switch (currentState)
{
case PlayerState.Idle: PlayIdle(); break;
case PlayerState.Moving: PlayMoving(); break;
case PlayerState.Attacking: PlayAttack(); break;
default: PlayIdle(); break;
}
string label = isAlive ? "Alive" : "Dead"; // ternary expression
C++ (Unreal)
if (Health <= 0)
{
Die();
}
else if (Health < LowHealthThreshold)
{
PlayLowHealthWarning();
}
else
{
PlayIdleAnimation();
}
switch (CurrentState)
{
case EPlayerState::Idle: PlayIdle(); break;
case EPlayerState::Moving: PlayMoving(); break;
case EPlayerState::Attacking: PlayAttack(); break;
default: PlayIdle(); break;
}
Unreal Blueprint
The Branch node is the visual if/else: one input (a boolean), two
output execution pins (True, False). Chained conditions are expressed as
a Branch feeding into another Branch on its False pin, mirroring
else if. A Switch on Enum node (or Switch on Int/String) mirrors
switch, with one execution output pin per case.
Practical Example
Deciding a monster's action each turn is a natural fit for a chained conditional, checked in priority order from most to least urgent:
if (health < fleeThreshold)
{
Flee();
}
else if (Vector3.Distance(transform.position, player.position) <= attackRange)
{
Attack();
}
else if (CanSeePlayer())
{
Chase();
}
else
{
Patrol();
}
Order encodes priority here: fleeing is checked first because it should override attacking even if the player happens to be in range — reordering these conditions would change the monster's behavior even though each individual condition is unchanged.
Common Mistakes
- Dangling
elseambiguity avoided by always using braces — omitting braces on a single-statementifinvites a later edit to add a second statement that silently falls outside the conditional. - Order-dependent
else ifchains authored as if order didn't matter — placing a general condition before a more specific one that it also satisfies means the specific branch is unreachable; the fix is ordering from most specific/urgent to least, as in the Practical Example. - Using a chain of
ifs (notelse if) when the conditions are mutually exclusive alternatives — every condition gets evaluated even after an earlier one matched, which is both wasted work and, if the conditions aren't actually mutually exclusive, a source of double-execution bugs. - Forgetting a
defaultcase in aswitch— an unhandled value falls through silently unless adefaultexists to catch it (or the language is configured to error on non-exhaustive matches). - Deeply nested conditionals that could be flattened with guard clauses or early returns, making the common path easier to find by eye.
Best Practices
- Always use braces, even for a single-statement block.
- Order
else ifbranches from most specific/urgent to least, when they could otherwise overlap. - Prefer
switchover a longif/else ifchain when comparing one value against several discrete known options, especially anenum. - Use guard clauses / early returns to avoid nesting the common case inside a validity check.
- Reach for the ternary expression only for a single inline value choice, not as a substitute for a full conditional with real branching logic.
Exercises
- Convert a three-level nested
ifinto an equivalent flat chain of guard clauses, and confirm the behavior is unchanged. - Write a
switchover aDirectionenum (Up,Down,Left,Right) that returns the corresponding movement vector, including adefaultcase. - Given the monster-action example, explain what would change in
behavior if the
FleeandAttackbranches were swapped. - Rewrite a chain of independent
ifstatements (that should have been mutually exclusive) as a properelse ifchain, and identify the bug the original version could cause.
Related Concepts
- Expressions — every condition is a boolean expression.
- Loops — repeatedly re-evaluates a condition, rather than branching once.
References
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules.- C# Language Reference — Selection statements: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/selection-statements
- cppreference — if statement: https://en.cppreference.com/w/cpp/language/if