argotorg / argotorg/solidity

Stop the war on for loops

Open
#13,308 7 comments 0 reactions 0 assignees View on GitHub
annoys users :cry: must have eventually optimizer
Dominant language
C++
Stars
25.7k
Forks
6.2k
Avg merge
1d 11h
Merged PRs (30d)
21

Description

## Abstract

Add a specific overflow check optimization that will make many for-loop optimizations unnecessary.

## Motivation

Too many people are saying this is bad:

```solidity
for (uint256 mintCounter = 0; mintCounter < quantity; mintCounter++) {
_mint(msg.sender, _assembleTokenID(dropID, mintCounter));
}
```

compared to this:

```solidity
for (uint256 mintCounter = 0; mintCounter < quantity;) {
_mint(msg.sender, _assembleTokenID(dropID, mintCounter));
unchecked{
mintCounter++
}
}
```

## Specification

### Note

For reference, a for-loop like this:

```
for (A; B; C) {D}
```

is implemented like this:

```basic
10 A

100 if !B GOTO 999
110 D
120 C
130 GOTO 100

999 EXIT
```

### New optimization

If inside a single code unit, if:

1. a variable has bit width X,
2. the variable is compared to be less than some quantity with bit width <=X,
3. the variable is not set until step 4 here, then
4. the variable is incremented;

then that incrementation in step 4 need not be safety checked. Or in $\LaTeX$:

$$x < a <= w \implies x+1 <= w$$

### Documentation

People like being fancy, so even if this is implemented, they will still use the `unchecked` "optimization" until it can be clearly explained that it is unnecessary.

So the documentation should be updated to specify that the gas cost of this code:

```solidity
contract C {
event E;
constructor(uint256 count) {
for (uint256 i = 0; i < count; i++) {
emit E(i);
}
}
}
```

shall not exceed that of this code:

```solidity
contract CUnchecked {
event E;
constructor(uint256 count) {
for (uint256 i = 0; i < count;) {
unchecked {
emit E(i);
i++;
}
}
}
}
```

And this can be checked with a test case.

There is precedent in this with JavaScript where the specification requires that implementations implement tail-end recursion optimization.

## Backwards Compatibility

n/a

---

Inspired by the discussion with @FrankNFT-labs at https://github.com/LightArtists/light-smart-contracts/issues/2

Contributor guide

Open the contributing guide

Research direction

Start by locating the compiler's handling of Solidity for-loop increments and the documentation section covering loop gas costs. Use the two constructor examples in the issue as the behavioral comparison, then add a test case showing that the checked and unchecked forms have no greater gas-cost difference after the optimization.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, solidity
Domain
compilers, documentation, testing
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.