GDKB

Expressions

Beginner12 Minutes readUpdated July 21, 20262 related concepts

An expression is any piece of code that evaluates to a value. `5`, `x`, `a + b`, and `IsAlive() && HasAmmo()` are all expressions — each one *produces something*, as opposed to a statement, which *does something* (and may or may not contain an expression). Understanding where an expression ends and a statement begins clarifies what is actually legal to write in each part of a program's syntax (an `if`'s condition must be an expression that produces a `bool`; a loop body is statements, not a single expression).

On this page

Expressions

Summary

An expression is any piece of code that evaluates to a value. 5, x, a + b, and IsAlive() && HasAmmo() are all expressions — each one produces something, as opposed to a statement, which does something (and may or may not contain an expression). Understanding where an expression ends and a statement begins clarifies what is actually legal to write in each part of a program's syntax (an if's condition must be an expression that produces a bool; a loop body is statements, not a single expression).

Mental Model

An expression is a small calculation with a definite answer. Some expressions are trivially simple (a single literal like 42, or a single variable name like health); others are built by combining smaller expressions with operators (health - damage), or by calling a function that returns a value (GetDistance(a, b)).

The key mental shift: an expression always has a value and a type, even when it's not obviously "doing math" — isGrounded is an expression whose value is whatever bool that variable currently holds, and a function call is an expression whose value is whatever the function returns. Anywhere the language expects "a value of type X", any expression that produces type X is legal there, no matter how it's built.

Core Explanation

Expressions compose: an expression can itself be built from smaller expressions, recursively, down to literals and variable names as the base case. (a + b) * (c - d) is one expression made of two parenthesized sub-expressions, each made of a variable, an operator, and a variable.

This is exactly why operator precedence (see Operators) matters — the compiler has to decide, for an expression with more than one operator, which sub-expression to evaluate first to build up the final value correctly.

Expressions vs. statements. A statement is a complete instruction — if (...) { ... }, a for loop, a variable declaration. A statement can contain expressions (the loop's condition, the value assigned to a new variable) but is not itself a value that could be used somewhere else. In most C-family languages, an expression becomes a statement simply by adding a semicolon (health -= damage; is the assignment expression, used as a statement) — which is why assignment can be written on its own line, even though = is technically producing a value (the assigned value) that this usage just discards.

Side effects. Some expressions only compute a value (a + b has no effect beyond producing a number); others also change program state as a side effect of evaluating them (health -= damage both produces a value and mutates health; a function call can do arbitrary work before returning its result). Relying on which expressions have side effects, and in what order they run, is where short-circuit evaluation (Operators) and evaluation order genuinely matter for correctness, not just style.

Boolean expressions deserve special mention because they are what every conditional statement and loop condition is built from — see Conditional Statements and Loops, both of which require their condition to be an expression whose value is a bool.

Syntax / Examples

C# (Unity)

csharp
int a = 3, b = 4;
int sum = a + b;                 // expression: a + b
bool canFire = ammo > 0 && !isReloading; // boolean expression
int closest = Mathf.Min(distA, distB);   // function-call expression

// Assignment is itself an expression, used here as a statement:
health -= damage;

// A conditional (ternary) expression: produces a value directly.
string status = health > 0 ? "Alive" : "Dead";

C++ (Unreal)

cpp
int32 A = 3, B = 4;
int32 Sum = A + B;
bool bCanFire = Ammo > 0 && !bIsReloading;
int32 Closest = FMath::Min(DistA, DistB);

Health -= Damage;

FString Status = Health > 0 ? TEXT("Alive") : TEXT("Dead");

Unreal Blueprint

A wire carrying a value between two nodes is an expression, visually — the "+" node's output pin is the expression a + b, ready to feed into whatever needs that value next. There is no visual distinction between "a value" and "an expression that produces a value"; a literal pin and a computed pin are interchangeable anywhere a value of that type is needed.

Practical Example

Computing whether an attack lands combines several sub-expressions into one boolean expression, which a conditional statement then acts on:

csharp
bool inRange = Vector3.Distance(attacker.position, target.position) <= attackRange;
bool hasLineOfSight = !Physics.Linecast(attacker.position, target.position, obstacleMask);
bool attackLands = inRange && hasLineOfSight && target.IsAlive;

if (attackLands)
{
    target.TakeDamage(attackPower);
}

Naming each sub-expression (inRange, hasLineOfSight) rather than inlining everything into one long condition is a readability choice, not a functional requirement — if (Vector3.Distance(...) <= attackRange && ...) would evaluate identically, but the named version documents what each piece of the overall expression means.

Common Mistakes

  • Treating an assignment's side effect as its purpose while forgetting it's also an expression — while ((line = reader.ReadLine()) != null) relies on assignment producing a value (the line just read) that the loop condition then tests; missing that assignment is an expression makes this pattern look like a syntax error rather than what it is.
  • Overly long, un-decomposed expressions — a single condition combining five comparisons with mixed &&/|| is hard to verify by eye. Breaking it into named boolean sub-expressions (as in the Practical Example) costs nothing at runtime and is far easier to review.
  • Assuming a function call is "free" inside a larger expression — a condition like while (GetEnemyCount() > 0) calls GetEnemyCount() every single iteration; if that function does real work, the loop is repeating that work, not just checking a cached number.
  • Losing evaluation order across expressions with side effects — Attack(target) && target.IsAlive differs from target.IsAlive && Attack(target) because &&'s short-circuit means the second one may skip the attack entirely if IsAlive is already false.

Best Practices

  • Give a name to any boolean sub-expression whose meaning isn't obvious from its code alone — a well-named bool is cheaper to read than a comment explaining a raw condition.
  • Keep expressions with side effects (assignment, function calls that mutate state) out of larger boolean expressions unless the ordering and short-circuit behavior are deliberate and understood.
  • Cache the result of an expensive function call in a local variable before using it more than once, rather than calling it repeatedly inside a condition or loop.
  • Use parentheses to make the intended grouping of a multi-operator expression unambiguous to a reader, even where the language's precedence rules would already produce the intended result.

Exercises

  1. Identify every expression in the line float speed = Mathf.Clamp(baseSpeed + bonus, 0f, maxSpeed); and state each one's type.
  2. Rewrite a five-condition if statement (write one) by extracting each sub-condition into a named boolean variable, then compare readability.
  3. Explain, using short-circuit evaluation, why swapping the operand order in Attack(target) && target.IsAlive changes behavior.
  4. Write a while loop whose condition both assigns and tests a value in one expression (mirroring the ReadLine() example), and explain what would break if assignment were not itself an expression.
  • Operators — the pieces expressions are built from.
  • Conditional Statements and Loops — both consume a boolean expression as their condition.

References

Related Concepts