Files: Widespread — every for(i in 1:length(x)) pattern in the codebase.
Affected locations:
| File |
Lines |
R/gmse_summary.R |
21, 44, 84, 167 |
R/gmse_apply.R |
121, 1674, 1699, 1736, 1900, 1938, 1954, 2013, 2019, 2475, 2565, 2697, 2933 |
R/plotting.R |
148, 364, 580, 609 |
Description: This is a well-documented R gotcha. The expression 1:length(x) looks innocuous but silently misbehaves when x has length zero:
x <- numeric(0) # empty vector, length = 0
1:length(x) # 1:0 → c(1, 0) ← NOT what you expect
Instead of producing an empty integer vector, 1:0 produces c(1, 0). The loop body then executes twice — once for i = 1 and once for i = 0 — rather than skipping entirely. This can silently write to invalid indices or operate on non-existent elements without raising an error.
Why it matters: If a GMSE simulation ever produces an empty resource type vector, an empty agent array, or an empty observation record, any loop using this pattern will run twice with incorrect indices rather than being skipped. The code will not crash, but it may silently corrupt array entries at index 0 (which in R assigns to a new element or overwrites internal structure in certain contexts). In practice, bugs introduced this way would manifest as hard-to-debug numerical errors in simulation outputs rather than explicit crashes, making them very difficult to track down.
How to fix: Use seq_along(x) or seq_len(length(x)) instead:
# Instead of:
for(i in 1:length(x)){ ... }
# Use:
for(i in seq_along(x)){ ... }
seq_along(x) safely returns an empty integer vector when x has length 0, so the loop body never executes. This is the idiomatic R pattern and should be used consistently throughout the codebase.
Files: Widespread — every
for(i in 1:length(x))pattern in the codebase.Affected locations:
R/gmse_summary.RR/gmse_apply.RR/plotting.RDescription: This is a well-documented R gotcha. The expression
1:length(x)looks innocuous but silently misbehaves whenxhas length zero:Instead of producing an empty integer vector,
1:0producesc(1, 0). The loop body then executes twice — once fori = 1and once fori = 0— rather than skipping entirely. This can silently write to invalid indices or operate on non-existent elements without raising an error.Why it matters: If a GMSE simulation ever produces an empty resource type vector, an empty agent array, or an empty observation record, any loop using this pattern will run twice with incorrect indices rather than being skipped. The code will not crash, but it may silently corrupt array entries at index 0 (which in R assigns to a new element or overwrites internal structure in certain contexts). In practice, bugs introduced this way would manifest as hard-to-debug numerical errors in simulation outputs rather than explicit crashes, making them very difficult to track down.
How to fix: Use
seq_along(x)orseq_len(length(x))instead:seq_along(x)safely returns an empty integer vector whenxhas length 0, so the loop body never executes. This is the idiomatic R pattern and should be used consistently throughout the codebase.