← board

NilPy: not s on a string was ALWAYS True (silent wrong branch)

Found 2026-07-20 while adding one-line suites for the uforth drive. The guard clause if not token: return None — uforth's single most common idiom — took the wrong branch for every non-empty string.

s = "abc"
if s: print("s truthy")          # correct
print(bool(s))                   # True — correct
if not s: print("not s -> True") # WRONG: fired for a non-empty string

Root cause

PyParseBoolNot (pyparser.inc) special-cased ordinals (not 5 -> 5 = 0) and booleans, and let everything else fall through to AN_NOT — which is Pascal's BITWISE complement. Applied to a string that complements the string HANDLE, which is never zero, so the result was non-zero and therefore truthy: not s was True for every string, empty or not.

The existing code comment called non-ordinal not "its own question, filed separately" — but no ticket was ever filed for it, so it sat as live silent wrong behaviour rather than a known gap.

Why it hid so well

if s: and bool(s) were both CORRECT — truthiness has a separate, working path, and pylib even has a bool(const s: AnsiString) overload. Only the not route was wrong, so any test that checked string truthiness the obvious way passed. It also fails as a wrong BRANCH, never as a crash or a type error.

Fix

A string is truthy when non-empty, so not s lowers to Length(s) = 0 (AN_CALL with ASTIVal = -Ord(tkLength) compared against 0). Covered by test/test_nilpy_truthiness.npy, diffed against CPython and in the test-nilpy gate.

Still open, deliberately

not <class> and not <variant> still go through AN_NOT unchanged. Python's object truthiness (__bool__/__len__) is a real design question rather than an oversight, and no censused uforth site needs it. If it is picked up, note that pylib already has bool() overloads for TPyList and Variant — the work is selecting the right OVERLOAD from the frontend, which is why this fix used Length directly instead.

Gate

make test-nilpy green, --tier quick GREEN, self-host byte-identical, fpc-check clean relative to HEAD.