Back to Foundry

Array length not cached

crates/lint/docs/cache-array-length.md

1.8.11.7 KB
Original Source

Array length not cached

Severity: Gas ID: cache-array-length

Flags for loop conditions that read a storage dynamic array's .length on every iteration instead of comparing against a cached local length.

What it does

Reports comparison expressions in for loop conditions when either side reads .length from a state dynamic array, such as i < values.length or values.length > i, including comparisons nested inside && / || conditions.

The lint does not report loops that already compare against a local cached length variable. It also skips loops that mutate an array length in the loop body, such as calling push() or pop(), because aliases can make caching the length change the loop semantics.

Fixed-size arrays are excluded because their length is a compile-time constant instead of a repeated dynamic length lookup. This lint currently checks for loops.

Why is this bad?

Reading .length in the loop condition repeats the storage length lookup for every iteration. Caching the length once before entering the loop avoids repeated storage reads and can reduce gas for hot loops.

Example

Bad

solidity
contract C {
    uint256[] values;

    function sum() external view returns (uint256 total) {
        for (uint256 i = 0; i < values.length; ++i) {
            total += values[i];
        }
    }
}

Good

solidity
contract C {
    uint256[] values;

    function sum() external view returns (uint256 total) {
        uint256 length = values.length;
        for (uint256 i = 0; i < length; ++i) {
            total += values[i];
        }
    }
}

Notes

This is a Gas-severity lint and is not applied to test or script files.