Skip to content

Docs audit: natural-language constructs that read like valid WFL but don't work (precedence, /, finally, between, error binding) #571

Description

@logbie

While auditing every ```wfl code block in Docs/ (new harness scripts/test_docs_code_blocks.py, see TestPrograms/docs_examples/DOC_CODE_AUDIT.md), several constructs turned up that read like perfectly natural WFL and appear throughout the docs, but do not work on the release interpreter (26.7.9). Most doc failures were plain syntax drift and are being fixed in the docs; the items below are language-side rough edges worth a maintainer decision (implement the feature, or make the docs stop teaching it). All repros verified against target/release/wfl.

High severity

1. Arithmetic binds looser than comparison inside conditions

The most natural conditional a beginner writes fails to type-check:

store y as 3
check if y plus 1 is equal to 4:
    display "yes"
end check

error: Condition must be a boolean expression - Expected Boolean but found Number
It parses as y plus (1 is equal to 4). Affects plus, minus, times, divided by, and %. Workaround: parenthesize the arithmetic, (y plus 1) is equal to 4.

2. of-call binds tighter than arithmetic → breaks recursion

display fibonacci of n minus 1

parses as (fibonacci of n) minus 1, so a recursive argument never decreases (non-termination / type error). Workaround: fibonacci of (n minus 1). Combined with #1, the precedence of of-calls vs. arithmetic vs. comparison needs a coherent, documented ladder.

3. / division operator fails to lex

display 10 / 2

Lexing error at position N: unexpected input /``. +, `-`, `*`, `%` all work as symbols; only `/` does not (presumably because `//` starts a comment). `divided by` works. The operator reference lists `/` as valid.

4. finally is not implemented

The docs described a full try/catch/finally, but there is no finally token/parser branch — finally: is read as an undefined variable. Only cleanup placed after end try works. (Note otherwise: is not a finally: it is a fallback for error types no when clause matched, and never runs on success.)

Medium severity

5. between is unusable outside pattern quantifiers

between is a reserved keyword but only wired into pattern quantifiers. Both of these — used in the docs — fail with Unexpected token in expression: KeywordBetween:

check if x is between 1 and 10:      -- range check
store d as random int between 1 and 6 -- random in range

Real forms today: two comparisons and-ed together; random_int of 1 and 6.

6. repeat N times is not supported

repeat 3 times:
    display "hi"
end repeat

Expected 'while', 'until', 'forever', or ':' after 'repeat' (collides with the times multiply operator). Workaround: count from 1 to 3:.

7. is above / is below are lexed but not parsed

above/below are keywords (lexer comment: // e.g., "is above 100") but the expression parser rejects temperature is above 30 with Unexpected token in expression: KeywordAbove. Only is greater than / is less than work.

8. No word form for modulo, and no text→number conversion

12 modulo 4Variable 'modulo' is not defined (only %). Separately, convert text to number doesn't parse and no to_number/parse builtin exists — yet the type checker's own hint says "Try converting the text to a number using 'convert to number'." Both fight the natural-language / minimize-special-characters principles.

9. Caught-error binding: only implicit error_message works

when error: binds an implicit error_message (single identifier) which works. But the natural binding form when error as e: is a parse error (Expected ':' after error type), and the two-word error message fails (Variable 'message' is not defined).

Lower severity / inference gaps

  • Action/function return-type inference often yields Nothing. define action called double with parameters n: return n times 2 end action then double of 5 minus 1Cannot perform Minus operation on Nothing and Number. Untyped params defeat inference.
  • Type-safety gap: docs promise Number plus Text is a compile error, but display age plus name (25, "Alice") silently prints 25Alice.
  • Action parameters are immutable: change x to x plus 10 on a param → Cannot modify constant 'x'.
  • Zero-arg action reference in a boolean condition is evaluated eagerly (no short-circuit) and type-errors as Function() -> ….
  • list files … as <var> inline binding doesn't parse though store <var> as list files in "." does.
  • Web-server example: the release binary leaves an orphaned server process holding the port after its parent is killed on timeout (Address already in use for later runs).

Filed from a documentation code-examples audit; the docs themselves are being corrected to the working forms in branch claude/docs-code-examples-audit-c9xzl9. Deciding these at the language level (vs. documenting the workarounds) affects WFL's "no-unlearning" natural-language promise, since each of the above is the form a beginner reaches for first.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions