← board

for x in obj: doesn't fall back to __getitem__/__len__ for a custom container

Found by proactive CPython-diff sweeping.

class Box:
    def __init__(self, items):
        self.items = items
    def __getitem__(self, idx):
        return self.items[idx]
    def __setitem__(self, idx, val):
        self.items[idx] = val
    def __len__(self):
        return len(self.items)

b = Box([1,2,3])
print(b[0])       # works: 1
b[0] = 99         # works
print(len(b))     # works: 3
for x in b:       # fails
    print(x)

b[idx]/b[idx] = v/len(b) (via __getitem__/__setitem__/__len__) already all work correctly. Only iterating a custom container with for fails:

pascal26:16: error: Nil Python: pylib (count) not loaded

CPython supports iterating ANY object that implements __getitem__ (starting from index 0, stopping on IndexError) even without a full __iter__/__next__ — the "old-style iteration protocol" fallback. NilPy's for desugars to a counted loop assuming a known container type (list/dict/str/etc.) and has no path for a bare user class, even one that otherwise fully implements the item-access protocol.

Scope note

Likely related to the broader, already-tracked generator/iterator-protocol gap (feature-generators-yield, feature-nilpy-yield-outside-a-for-loop, and the full __iter__/__next__ STOP-iteration protocol, which is a much bigger feature) — but this specific fallback (iterate via __getitem__ alone, no explicit iterator object) is narrower and could plausibly land independently of the general generator/iterator machinery: it's "counted loop calling obj[i] until __getitem__ would raise IndexError," which is close in shape to how NilPy already desugars for x in some_list:.

Not attempted this pass — needs its own investigation into whether it's cheap to add as a special for desugar case (detect a class with __getitem__ but no static list/dict/str type) versus properly belonging to the larger iterator-protocol feature.

Gate

A .npy case iterating a class that implements only __getitem__/__len__ (no __iter__), diffed against CPython, gated in test-nilpy + --tier quick + self-host byte-identical.