← All posts
6 min read

Conditions and Decisions: How Programs Choose What to Do

#technology#computer-science#conditionals#programming
📑 On this page

Programs must respond differently to different data:

  • Accept or reject login
  • Apply or skip discount
  • Show mobile or desktop layout
  • Retry or report failure

A condition evaluates an expression to true or false, and control flow uses that result to select instructions.

Reliable decisions require clear rules, correct operators, and attention to edge cases.

Boolean values

A Boolean has two values:

true
false

Comparisons produce Booleans:

age >= 18
passwordLength >= 12
status === "active"

The expression is evaluated using current values.

Names such as isActive, hasPermission, and canRetry make Boolean meaning clear.

If and else

if (temperature > 38) {
  showHighTemperatureWarning();
} else {
  showNormalStatus();
}

Only one branch executes.

Additional branches:

if (score >= 90) {
  grade = "A";
} else if (score >= 80) {
  grade = "B";
} else {
  grade = "C";
}

Order matters. The first true branch wins.

Comparison boundaries

Small operator differences change behavior:

age > 18
age >= 18

Ask:

  • Is the boundary included?
  • What happens exactly at zero?
  • Are units consistent?
  • Can the value be absent?

Boundary testing checks values:

  • Just below
  • Exactly equal
  • Just above

Many bugs live at the edge rather than the ordinary middle.

Logical AND

AND requires both conditions:

ABA AND B
falsefalsefalse
falsetruefalse
truefalsefalse
truetruetrue

Example:

const canCheckout = cartHasItems && addressIsValid;

Both requirements must hold.

Logical OR

OR requires at least one condition:

ABA OR B
falsefalsefalse
falsetruetrue
truefalsetrue
truetruetrue
const canEdit = isOwner || isAdministrator;

Security rules need precise grouping when AND and OR combine.

Logical NOT

NOT reverses a Boolean:

if (!isLoggedIn) {
  showLogin();
}

Double negatives are hard to read:

if (!isNotDisabled) { ... }

Prefer positive names where possible.

Operator precedence

Expressions have precedence rules:

isOwner || isAdmin && accountActive

AND commonly binds more tightly than OR, so this means:

isOwner || (isAdmin && accountActive)

If the intended policy is:

(isOwner || isAdmin) && accountActive

parentheses are required.

For security-sensitive conditions, explicit grouping is worth the extra characters.

Short-circuit evaluation

Logical operators often stop once the result is known.

For AND:

user !== null && user.isActive

If user !== null is false, the second expression is not evaluated.

For OR:

cachedValue || loadValue()

The second expression runs only if the first is falsy.

Short-circuiting enables safe guards but can hide side effects. Avoid relying on it for unrelated state changes.

Truthiness

Some languages convert non-Boolean values in conditions.

JavaScript treats values such as these as falsy:

false, 0, "", null, undefined, NaN

This can be convenient:

if (name) { ... }

But it merges missing name and empty name.

Use explicit checks when those states mean different things.

A concrete checkout decision

function canPlaceOrder(cart, customer) {
  if (cart.items.length === 0) return false;
  if (!customer.deliveryAddress) return false;
  if (!customer.paymentMethod) return false;
  return cart.totalInPaise > 0;
}

These early returns are guard clauses.

They handle invalid conditions first and keep the successful path clear.

The server must repeat these checks even if the client disables the checkout button.

Switch and pattern matching

When choosing among several distinct values:

switch (status) {
  case "pending":
    return showPending();
  case "paid":
    return showReceipt();
  case "cancelled":
    return showCancelled();
  default:
    return showUnknown();
}

Pattern-matching features in some languages can inspect structured data and require exhaustive cases.

An exhaustive compiler check helps when a new state is added.

Decision tables

Complex business rules can be represented as a table.

MemberCoupon validCart minimum metDiscount
yesyesyes20%
yesnoyes10%
noyesyes5%
anyanyno0%

A decision table exposes missing and overlapping cases better than nested conditions.

Tests can be generated for each row.

Floating-point comparisons

Direct equality with computed floating-point values can fail because of rounding:

0.1 + 0.2 === 0.3 // false

Compare within a tolerance when appropriate:

Math.abs(actual - expected) < epsilon

The tolerance depends on the domain and scale.

For exact values such as money, choose a suitable representation instead.

Common misunderstandings

"An if statement checks intent"

It evaluates the exact expression written, including mistakes and missing cases.

"AND and OR can be read casually"

Grouping and precedence can change authorization and business behavior.

"Truthy means valid"

A non-empty value can still violate format or domain rules.

"Client conditions protect server actions"

Clients can be modified. The authoritative system must validate independently.

Knowledge check

1. What does AND require?

Every combined condition must be true.

2. Why test values at a condition boundary?

Inclusive versus exclusive operators and off-by-one mistakes often fail exactly at the edge.

3. What is short-circuit evaluation?

The language stops evaluating a logical expression once the final result is already determined.

4. Why use guard clauses?

They handle invalid or exceptional cases early and reduce deeply nested control flow.

The one idea to remember

Conditions turn values into branches by evaluating precise Boolean rules.

Correct decisions depend on boundaries, grouping, absence handling, explicit policy, and tests for every meaningful case.

Next, we will use loops to express controlled repetition over ranges and collections.