0Pricing
R Academy · Lesson

Operator Precedence and Complex Expressions

Understand evaluation order and write complex expressions safely.

Operator Precedence and Complex Expressions is a free R Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the R Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What is Operator Precedence?

Operator precedence determines the order in which operations are evaluated in an expression. Just like in mathematics, multiplication is evaluated before addition. R follows a well-defined precedence table.

# Precedence in action
result1 <- 2 + 3 * 4    # * before +
result2 <- (2 + 3) * 4  # parentheses override
cat('2 + 3 * 4 =', result1, '
')   # 14
cat('(2+3) * 4 =', result2, '
')   # 20

R Precedence Table (High to Low)

R evaluates operators in this order (highest priority first):

  1. ^ — exponentiation
  2. - (unary) — negation
  3. : — sequence
  4. %%, %/%, %*%, %in% — special infix
  5. *, / — multiply, divide
  6. +, - (binary) — add, subtract
  7. <, >, <=, >=, ==, != — comparison
  8. ! — NOT
  9. &, && — AND
  10. |, || — OR
  11. <-, = — assignment
# Exponentiation before multiplication
cat('2 * 3 ^ 2 =', 2 * 3 ^ 2, '
')   # 2 * 9 = 18
cat('(2*3)^2 =', (2 * 3) ^ 2, '
')   # 6^2 = 36

# Unary minus applied after exponentiation
cat('-2 ^ 2 =', -2 ^ 2, '
')    # -(2^2) = -4
cat('(-2)^2 =', (-2) ^ 2, '
')  # 4

Colon Operator Precedence

The : sequence operator has higher precedence than + and -, which causes a common beginner mistake: 1:n+1 is read as (1:n)+1, not 1:(n+1).

n <- 5

# Common mistake: colon before addition
cat('1:n+1 =', 1:n + 1, '
')   # (1:5)+1 = 2 3 4 5 6
cat('1:(n+1) =', 1:(n + 1), '
') # 1:6 = 1 2 3 4 5 6

# These are DIFFERENT results!
# Always use parentheses when the upper bound involves arithmetic

Special Operator Precedence

Special operators like %%, %/%, and %in% have higher precedence than + and - but lower than ^. Misunderstanding this leads to subtle bugs.

# %% has higher precedence than +
cat('10 + 7 %% 3 =', 10 + 7 %% 3, '
')   # 10 + (7%%3) = 10+1 = 11
cat('(10+7) %% 3 =', (10 + 7) %% 3, '
') # 17 %% 3 = 2

# %in% precedence
nums <- 1:5
cat('1 + 1 %in% nums =', 1 + 1 %in% nums, '
')  # (1+1) %in% nums? No! 1 + (1 %in% nums) = 2

Comparison Before Logical

Comparison operators (<, >, ==, etc.) are evaluated before logical operators (!, &, |). This means x > 0 & y < 10 works as expected without extra parentheses.

x <- 5
y <- 8

# This works as intended: comparisons first, then &
cat('x > 0 & y < 10:', x > 0 & y < 10, '
')  # TRUE & TRUE = TRUE

# ! NOT has higher precedence than &
vec <- c(TRUE, FALSE, TRUE)
cat('!vec & TRUE:', !vec & TRUE, '
')  # (!vec) & TRUE, not !(vec & TRUE)
cat('!(vec & TRUE):', !(vec & TRUE), '
')

Tricky Precedence Bug #1

A common bug: forgetting that ! has lower precedence than comparison, meaning !x == y is read as (!x) == y, not !(x == y).

x <- 5
y <- 5

# BUG: meant to check 'x is not equal to y'
bug_result <- !x == y      # reads as (!x) == y
cat('!x == y (bug):', bug_result, '
')   # !5 means FALSE, FALSE==5 is FALSE

# CORRECT: use != or !(x == y)
cat('x != y:', x != y, '
')             # FALSE (correct)
cat('!(x == y):', !(x == y), '
')       # FALSE (correct)

Tricky Precedence Bug #2

Another subtle bug: -1:5 creates the sequence -1, 0, 1, 2, 3, 4, 5 — the unary minus only applies to 1, not to the entire range. To get a range starting from a negative, use parentheses.

# Misleading: looks like range from -1 to 5 starting at negative
seq1 <- -1:5
cat('-1:5 =', seq1, '
')  # -1 0 1 2 3 4 5 (correct here)

# But -2^2 is a trap:
cat('-2^2 =', -2 ^ 2, '
')    # -4 (not 4)
cat('(-2)^2 =', (-2) ^ 2, '
') # 4

# Always parenthesise to be safe
cat('(-1):5 =', (-1):5, '
')   # same as -1:5 but explicit

Using Parentheses for Clarity

Even when parentheses are not strictly required, using them makes code easier to read and less error-prone. Never rely on memorising the full precedence table — use parentheses to express your intent clearly.

# Hard to read — requires knowing precedence
result_unclear <- 2 + 3 * 4 ^ 2 / 8 - 1

# Clear intent with parentheses
result_clear <- 2 + ((3 * (4 ^ 2)) / 8) - 1

cat('Unclear:', result_unclear, '
')
cat('Clear:  ', result_clear, '
')
cat('Same result?', result_unclear == result_clear, '
')

Assignment in Expressions

Assignment (<-) has very low precedence — lower than most operators. This means you can assign the result of any complex expression in one line, but it also means assignment inside expressions behaves unexpectedly.

# <- has very low precedence
# This assigns (3 + 4) to x, then evaluates (TRUE)
result <- x <- 3 + 4   # x gets 7, result gets 7
cat('x:', x, 'result:', result, '
')

# Be careful with == vs <- 
# x <- 5 is assignment
# x == 5 is comparison (always use == for testing)

Practical: Avoiding Precedence Errors

Here is a practical strategy for writing correct complex expressions: break long expressions into named intermediate steps. This also makes debugging easier because you can inspect each step.

# Complex formula: compound interest
principal <- 1000
rate <- 0.05
years <- 10

# Hard to verify in one line
bad <- principal * (1 + rate) ^ years

# Easier to verify step by step
growth_factor <- (1 + rate) ^ years
final_amount <- principal * growth_factor
cat('Growth factor:', round(growth_factor, 4), '
')
cat('Final amount: $', round(final_amount, 2), '
')

Precedence with Logical AND/OR

& (AND) has higher precedence than | (OR). So A | B & C is evaluated as A | (B & C). Always use parentheses when mixing AND and OR to avoid subtle logic bugs.

A <- TRUE
B <- FALSE
C <- TRUE

# & before | — may surprise you
cat('A | B & C:', A | B & C, '
')     # A | (B & C) = TRUE | FALSE = TRUE
cat('(A|B) & C:', (A | B) & C, '
')   # TRUE & TRUE = TRUE

# Different with:
A2 <- FALSE
cat('A2 | B & C:', A2 | B & C, '
')   # FALSE | (FALSE & TRUE) = FALSE
cat('(A2|B) & C:', (A2 | B) & C, '
') # (FALSE|FALSE) & TRUE = FALSE

Quick Check

What does -3 ^ 2 evaluate to in R?

Recap: Operator Precedence

Excellent! Here are the key takeaways from this lesson:

  • Precedence order (high → low): ^, unary -, :, %%/%/%*%%in%, */, +-, comparisons, !, &, |, assignment
  • -2^2 = -4 because ^ beats unary minus — use (-2)^2 for 4
  • 1:n+1 means (1:n)+1 — use 1:(n+1) if you want a longer range
  • & binds tighter than | — parenthesise mixed AND/OR logic
  • When in doubt, use parentheses to make your intent explicit and avoid bugs
# Golden rule: parentheses for clarity
n <- 4
# Intended: sequence 1 to n+1
cat('Wrong : 1:n+1  =', 1:n + 1, '
')
cat('Correct: 1:(n+1)=', 1:(n + 1), '
')

# Intended: -(2^2)
cat('Correct: -2^2 = -(2^2) =', -2 ^ 2, '
')

Frequently asked questions

Is the “Operator Precedence and Complex Expressions” lesson free?

Yes — the full text of “Operator Precedence and Complex Expressions” is free to read here on the web, and the R Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the R Academy course, upgrade to CoddyKit PRO.

What will I learn in “Operator Precedence and Complex Expressions”?

Understand evaluation order and write complex expressions safely. You practise R Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start R Academy?

No prior experience is required. R Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Operator Precedence and Complex Expressions” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this R Academy lesson?

Yes. Every R Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Arithmetic and Comparison Operators
  2. Logical Operators and Boolean Logic
  3. Assignment and Special Operators
  4. Operator Precedence and Complex Expressions
← Back to R Academy