R PROGRAMMING • CONTROL FLOW

next & break — Use next and break to control loop flow

Master R's two loop-control statements that let you skip iterations or terminate loops early for cleaner, more efficient code.

Historical Context & Motivation

The ability to alter the natural flow of a loop—skipping an iteration or exiting entirely—has been a staple of structured programming since the 1960s. Early imperative languages relied heavily on goto statements, which made programs notoriously difficult to read and maintain. The structured-programming movement championed by Edsger Dijkstra advocated replacing arbitrary jumps with well-defined control structures—including disciplined loop-exit mechanisms. R, a language whose lineage passes through S and Scheme, inherited these structured alternatives as the next and break keywords, analogous to continue and break in C, Java, and Python.

1966
Dijkstra's "Go To Statement Considered Harmful"
Dijkstra argued that unstructured jumps impair program reasoning, catalyzing the move toward structured loop-control mechanisms like break and continue.
1972
C Introduces break & continue
Dennis Ritchie's C language formalized break and continue as first-class loop-control statements, establishing a pattern adopted by virtually every imperative language that followed.
1988
S Language at Bell Labs
The S language, R's predecessor, included next and break for controlling for, while, and repeat loops. R later adopted these keywords directly.
2000
R 1.0 Released
R 1.0.0 shipped with next and break as reserved words, ensuring they could not be overridden by user-defined variables and could be relied upon across all loop constructs.

Why do we need these statements at all? Consider a data-processing pipeline that iterates over thousands of records: some records may be incomplete and should be skipped, while others may signal that no further processing is useful. Without next and break, programmers would need to nest deeply or use auxiliary flag variables—both of which reduce clarity. The central question this lesson addresses is: How do next and break provide fine-grained control over loop execution in R, and when should each be used?

Core Principles & Definitions

R provides three loop constructs—for, while, and repeat—each of which supports both next and break. Understanding these two keywords rests on grasping how R's interpreter advances through a loop body and what happens when control is diverted.

1

next — Skip to the Next Iteration

When the interpreter encounters next, it immediately halts execution of the current iteration's remaining statements and jumps back to the loop's condition check (or the next element in a for-loop). No code below the next call is executed for that iteration.
2

break — Exit the Loop Entirely

The break statement terminates the innermost enclosing loop immediately. Execution resumes at the first statement after the loop's closing brace. It is the only way to exit a repeat loop, which has no built-in termination condition.
3

Scope: Innermost Loop Only

Both next and break affect only the innermost loop that contains them. In nested-loop scenarios, the outer loop continues unaffected unless it also contains its own control statements.
4

Guard Pattern — if + next / break

In practice, next and break are almost always wrapped inside an if statement. The condition acts as a guard clause, making the intent of the skip or exit explicit and readable.
KEY TAKEAWAY
Think of a loop as an assembly line. next is like an inspector who spots a defective part and sends it to the reject bin so the line immediately moves to the next part. break is hitting the emergency-stop button: the entire line halts. One skips a single item; the other shuts down the process.

Visual Explanation — Loop Flow with next & break

The flowchart above traces a for loop's lifecycle. After the guard-condition diamond, the cyan path (next) sends control back to the top of the loop—skipping the remaining body—while the pink path (break) exits the loop entirely and resumes execution after the closing brace.

Observe that next does not terminate the loop; it merely short-circuits the current iteration and returns control to the loop header, where the iterator variable advances to the next value. In a while loop, next jumps back to the condition test; if the condition is still TRUE, the body executes again. Conversely, break unconditionally ends the loop—no further iterations occur, regardless of remaining elements or condition state. Both statements affect only the innermost enclosing loop; outer loops are unaffected.

How next & break Work Under the Hood

At the interpreter level, R implements next and break via non-local jumps—internally similar to how R handles conditions and restarts. When the evaluator encounters next, it raises an internal signal that the loop handler catches, causing it to skip the remaining body and proceed to the next iteration. The break keyword raises a different signal that causes the loop handler to transfer control past the loop entirely. Importantly, neither statement is a function—they are reserved words with special evaluation semantics, and attempting to use them outside a loop context generates an error.

Syntax in Each Loop Type

Behavior of next and break across R's three loop constructs.
Loop Typenext Behaviorbreak Behavior
for (var in seq) { ... }Advances iterator to next element of seq; if none remain, loop ends normally.Exits the loop immediately; remaining elements of seq are not processed.
while (cond) { ... }Jumps to the condition re-evaluation. If cond is still TRUE, the body runs again.Exits the loop regardless of whether cond is TRUE or FALSE.
repeat { ... }Jumps to the top of the repeat body. Since repeat has no condition, this restarts the body.The only way to exit a repeat loop. Without break, the loop runs forever.

Canonical Code Patterns

The idiomatic pattern in R is to place the guard condition at the top of the loop body—a technique sometimes called a guard clause. For next, this looks like: if (should_skip) next. The remainder of the loop body then executes only when the guard condition is FALSE, avoiding deeply nested else blocks. The analogous pattern for break is: if (should_stop) break. This pattern is particularly powerful in data-cleaning pipelines where certain records are malformed or where a sentinel value signals end-of-data.

⚠️ Common Pitfall: Infinite while Loops
When using next inside a while loop, ensure that the counter or state variable is updated before the next call. If the increment appears after next, it will be skipped, and the loop will never terminate.

Common Patterns & Nested Loop Behavior

In real-world R scripts, next and break appear in several recurring patterns. Understanding these patterns helps you recognize when to reach for a loop-control statement versus restructuring your logic with vectorized operations or the apply family. The most important nuance arises in nested loops: since both keywords affect only the innermost loop, controlling an outer loop from within an inner loop requires a flag variable or refactoring into a function with return().

This diagram shows a nested loop where break is called inside the inner loop when j == 3. Green cells represent executed iterations, the pink cell is where break fires, and dashed cells are skipped. Notice that the outer loop (i) continues for all three values—only the inner loop is terminated each time.

Pattern Catalog

Common patterns involving next and break in R.
PatternKeywordUse Case
Filter-in-LoopnextSkip NA values, malformed rows, or records that fail a validation check before processing.
Early TerminationbreakStop iterating once a target value is found (e.g., linear search) or a convergence criterion is met.
Sentinel LoopbreakUse repeat with break to process input of unknown length, terminating on a sentinel value.
Nested Searchbreak + flagSet a flag variable in the inner loop, then check it in the outer loop to decide whether to break there as well.

Worked Example — Cleaning & Searching a Data Vector

Suppose you have a numeric vector containing some NA values and you need to find the first element greater than 100, skipping any missing data. This example demonstrates both next and break in the same loop.

Find the First Value > 100, Skipping NAs
1
Step 1 — Define the DataCreate a vector with a mix of numeric values and NAs: data <- c(23, NA, 47, NA, 105, 88, 210). Initialize a result variable to NULL to store the first qualifying value.
result <- NULL
2
Step 2 — Write the Loop with Guard ClausesIterate over each element. The first guard uses next to skip NA values: for (x in data) { if (is.na(x)) next. This ensures that subsequent code never has to handle NAs.
3
Step 3 — Add the break ConditionAfter the NA guard, check whether the current value exceeds 100. If so, store it and exit immediately: if (x > 100) { result <- x; break }. The closing brace ends the loop body.
4
Step 4 — Trace ExecutionIteration 1: x = 23, not NA, not > 100 → continue. Iteration 2: x = NA → next fires, skip. Iteration 3: x = 47, not NA, not > 100 → continue. Iteration 4: x = NA → next fires, skip. Iteration 5: x = 105, not NA, 105 > 100 → store and break.
5
Step 5 — Verify the ResultAfter the loop, result holds the value 105. Elements 88 and 210 were never examined because break terminated the loop as soon as the first qualifying value was found.
result # [1] 105
💻 Complete Code
data <- c(23, NA, 47, NA, 105, 88, 210) result <- NULL for (x in data) { if (is.na(x)) next if (x > 100) { result <- x break } } cat("First value > 100:", result, "\n") # Output: First value > 100: 105

Strengths, Limitations & Alternatives

While next and break are invaluable in imperative loop contexts, R's functional programming paradigm often offers vectorized or apply-based alternatives that can be more idiomatic and performant. Understanding the tradeoffs helps you choose the right tool for each situation.

Strengths and limitations of next and break in R.
AspectStrengthsLimitations
ReadabilityGuard clauses with next/break flatten nested if-else structures, making intent explicit.Overuse in deeply nested loops can create spaghetti-like flow that is hard to trace.
Performancebreak enables early termination, avoiding unnecessary computation (e.g., linear search stops at first match).R's for loops are generally slower than vectorized operations; adding next/break doesn't fix the overhead of interpreted iteration.
Nested LoopsSimple to use within a single loop level.Cannot break out of multiple levels at once; requires flag variables or function-based refactoring.
Functional AlternativesLoops with next/break handle side effects and stateful logic naturally.Filter + which, vapply, or purrr::detect can replace many next/break patterns more concisely.
DebuggingEasy to set breakpoints around next/break in RStudio's debugger.When next is triggered, browser() or print() statements after it are silently skipped, which can confuse debugging.
WHEN TO USE LOOPS VS. VECTORIZED CODE
If your task can be expressed as a filter followed by a transformation—e.g., "process all non-NA values"—prefer vectorized code like data[!is.na(data)]. Reserve explicit loops with next and break for situations that require sequential state, side effects (writing files, updating databases), or truly conditional early termination that cannot be expressed declaratively.

Connection to Advanced Control Flow

The next and break keywords are the simplest form of non-local transfer of control in R. As you move into more advanced R programming, you will encounter a richer family of control-flow mechanisms—tryCatch for exception handling, withCallingHandlers for restartable conditions, and the rlang package's abort/warn/inform system—that generalize the idea of jumping out of normal execution flow.

Comparison of basic loop control with advanced control-flow mechanisms.
Featurenext / breakAdvanced Mechanism
ScopeInnermost loop onlytryCatch can unwind multiple call frames; return() exits a function from any depth.
Use Outside LoopsError: no loop to break fromtryCatch/tryCatchLog works anywhere; return() works inside any function body.
Data PassingNo value is returned by next or break; results must be stored in variables before invoking them.tryCatch handlers receive the condition object; return(value) passes data to the caller.
Iteration AbstractionManual iteration with for/while/repeat.purrr::detect(), purrr::keep(), and base R's Filter() abstract iteration + early exit into functional idioms.

As a forward-looking note, many tasks that seem to require a loop with break—such as finding the first element satisfying a predicate—can be elegantly handled by Find(f, x) in base R or purrr::detect(x, f) in the tidyverse. Similarly, filtering with next can often be replaced by Filter(f, x) or purrr::keep(x, f). Mastering next and break provides the conceptual foundation for understanding why these higher-level abstractions exist and when the imperative approach remains the better choice.

Practice Problems

PROBLEM 1CONCEPTUAL
Explain, in your own words, the difference between next and break in terms of what happens to (a) the current iteration, (b) remaining iterations, and (c) execution after the loop.
PROBLEM 2BASIC CALCULATION
Given the code below, what is the final value of total? total <- 0 for (i in 1:10) { if (i %% 3 == 0) next total <- total + i } Trace through each iteration to justify your answer.
PROBLEM 3INTERMEDIATE
Write an R while loop that reads integers from a predefined vector inputs <- c(4, -1, 7, 0, 12, 3) one at a time, accumulates a running sum, but (a) skips negative values using next, and (b) stops immediately if the running sum exceeds 20 using break. Be careful about updating the index before calling next.
PROBLEM 4APPLIED
You are processing a list of file paths and need to read each file, but some paths are invalid. Write a for loop that iterates over paths <- c("data1.csv", "missing.csv", "data3.csv"). Use file.exists() combined with next to skip files that don't exist, and process the rest. Include a message indicating which files were skipped.
PROBLEM 5CRITICAL THINKING
Consider the following nested loop that searches a matrix for a target value: mat <- matrix(1:20, nrow = 4, ncol = 5) target <- 14 found <- FALSE for (i in 1:nrow(mat)) { for (j in 1:ncol(mat)) { if (mat[i, j] == target) { found <- TRUE break } } if (found) break } (a) Explain why a single break inside the inner loop is insufficient to exit both loops. (b) Propose an alternative design that avoids the flag variable entirely—hint: wrap the search in a function.

Summary

R provides two loop-control keywords: next, which skips the remainder of the current iteration and advances to the next element or condition check, and break, which terminates the innermost enclosing loop entirely. Both are typically paired with guard clauses (if-statements) that make the skip or exit condition explicit. They work identically across R's three loop constructs—for, while, and repeat—with the caveat that break is the only way to exit a repeat loop.

Key practical considerations include: always update loop counters before calling next in while loops to avoid infinite loops; remember that both keywords affect only the innermost loop in nested contexts; and prefer vectorized alternatives (such as Filter, Find, or purrr's detect and keep) when the logic can be expressed declaratively. Mastering next and break builds the conceptual foundation for R's more advanced control-flow mechanisms, including tryCatch, condition handling, and functional iteration.

Varsity Tutors • R Programming • next & break — Use next and break to control loop flow