Operators
Summary
An operator is a symbol that performs an operation on one or more values
(its operands) and produces a result. +, -, ==, &&, and = are all
operators. Operators are how individual values combine into the larger
computations that make up an expression — nearly every line of game logic
is built from a handful of operators applied to variables and literals.
Mental Model
An operator is a small machine with input slots and one output slot.
Feed it operands of the right type, and it produces a result of a
(possibly different) type. 5 + 3 feeds two integers into + and gets an
integer out; 5 > 3 feeds two integers into > and gets a boolean
out — the input and output types need not match, and knowing what type an
operator produces is as important as knowing what it accepts.
Operators chain: the output of one becomes the input of the next
(a + b * c), which is why order — which machine runs first — has to be
a fixed, learnable rule (precedence) rather than left to guesswork.
Core Explanation
Operators group by what they do:
- Arithmetic —
+ - * / %operate on numbers.%(modulo) returns the remainder of division and is the standard tool for "wrap around every N" logic (cycling through an array, alternating frames). - Comparison / relational —
== != < > <= >=compare two values and always produce abool.==checks equality; critically, it is a different operator from=(assignment) even though they look similar. - Logical —
&& || !combine or invertboolvalues: "both true", "either true", "the opposite". They are how multiple conditions combine into one (isGrounded && !isStunned). - Assignment —
=stores a value into a variable. Compound forms (+= -= *= /=) combine an operation with assignment:health -= damageis shorthand forhealth = health - damage, doing both in one expression. - Increment / decrement —
++and--add or subtract one. The prefix (++x) and postfix (x++) forms both incrementx, but differ in what value the expression itself evaluates to — prefix yields the new value, postfix yields the old one. This distinction only matters when the increment is used inside a larger expression, not on its own line.
Precedence and associativity decide the order operators apply in when
an expression has more than one. Multiplication and division bind tighter
than addition and subtraction (2 + 3 * 4 is 14, not 20) — the same
rule taught in arithmetic class, extended to every operator the language
defines. Parentheses override precedence explicitly, and are the
recommended way to remove any doubt about evaluation order rather than
relying on a reader to recall the full precedence table.
Short-circuit evaluation. && and || stop evaluating as soon as the
overall result is already determined: in a && b, if a is false, b
is never evaluated at all, because the whole expression must be false
regardless. This is not just an optimization — code deliberately relies on
it, e.g. enemy != null && enemy.IsAlive is safe specifically because a
null enemy short-circuits before .IsAlive would run and throw.
Syntax / Examples
C# (Unity)
int total = 5 + 3 * 2; // 11 — * before +
int remainder = 17 % 5; // 2
bool canAct = isGrounded && !isStunned;
health -= damage; // compound assignment
int next = index++; // postfix: next = old index, index now +1
// Short-circuit — safe even when enemy is null
if (enemy != null && enemy.IsAlive) { /* ... */ }
C++ (Unreal)
int32 Total = 5 + 3 * 2; // 11
int32 Remainder = 17 % 5; // 2
bool bCanAct = bIsGrounded && !bIsStunned;
Health -= Damage;
int32 Next = Index++;
if (Enemy != nullptr && Enemy->IsAlive()) { /* ... */ }
Unreal Blueprint
Arithmetic and comparison operators are individual nodes (+, >,
AND Boolean, NOT Boolean) wired between pins. There is no dedicated
short-circuit node — AND Boolean in the visual graph evaluates both
input pins before combining them, so the null-check-then-use pattern above
must be expressed as a Branch node checking "Is Valid" first, not a
single combined condition.
Practical Example
Deciding whether a jump input should be accepted combines several conditions with logical operators:
bool canJump = isGrounded && !isJumping && jumpCooldown <= 0f;
if (canJump && Input.GetButtonDown("Jump"))
{
velocity.y = jumpForce;
isJumping = true;
}
Each sub-condition is a comparison producing a bool; && combines them
into one. Short-circuiting means jumpCooldown <= 0f is only checked if
the character is actually grounded and not already jumping — cheaper, and
it also means the expression's order can matter for readability even when
it doesn't change the result.
Common Mistakes
=where==was meant. Covered in Variables, but worth repeating here because it is specifically an operator confusion: two operators that look almost identical do very different things.- Assuming
&&/||always evaluate both sides. Code that relies on a side effect happening inside the right-hand operand (isReady() && Log()) can silently skip that side effect when the left side short-circuits. - Operator precedence surprises, especially mixing
&&and||without parentheses:a || b && cisa || (b && c), not(a || b) && c, because&&binds tighter than||. Relying on memory of the full precedence table is fragile — parenthesize when combining more than one kind of logical operator. - Integer division inside a larger expression —
total / count * 100truncates before multiplying if both are integers, giving a different (and usually wrong) result thantotal * 100 / count. - Confusing prefix and postfix increment inside a larger expression
(
array[i++]vsarray[++i]) — indexes a different element depending on which form is used, because the two forms produce different values for the surrounding expression even though both incrementi.
Best Practices
- Parenthesize any expression mixing more than one kind of operator
(arithmetic with comparison, or
&&with||) — it costs nothing and removes the need to recall precedence rules. - Order
&&/||operands so cheap, safety-establishing checks come first (enemy != null && enemy.IsAlive), deliberately relying on short-circuiting rather than fighting it. - Prefer compound assignment (
x += n) overx = x + n— it states intent ("modify this variable") more directly. - Avoid combining an increment/decrement operator with another use of the same variable in one expression; split it into two statements instead.
- Use
%for any "wrap around" logic instead of hand-rolled conditional subtraction.
Exercises
- Evaluate
10 - 4 / 2 + 3 % 2by hand using precedence rules, then verify with code. - Write the jump-eligibility condition from the Practical Example using
only
ifstatements nested instead of&&, and compare readability. - Demonstrate, with a small example, a case where
a++and++aproduce different observable results. - Rewrite
a || b && cwith explicit parentheses matching how the language actually evaluates it, without changing behavior.
Related Concepts
- Variables and Data Types — operators only make sense in the context of the types they operate on.
- Expressions — operators are the pieces expressions are built from.
References
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules.- C# Language Reference — Operators: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/
- cppreference — Operator precedence: https://en.cppreference.com/w/cpp/language/operator_precedence