Rename arithmetic operators to named functions (add/sub/mul/div/mod/neg) #27

Open
opened 2026-05-21 10:07:21 +02:00 by Brummel · 0 comments
Owner

Goal: full surface consistency. Extend the named-function principle
the operator-routing-eq-ord milestone applied to comparison (==eq,
<lt, …) to the last special-character builtins. After this
milestone, Form-A contains zero symbol-named identifiers.

Today: arithmetic ops are monomorphic Int builtins, parsed as
operators, desugared to (app + a b) in Form-A. Form-A is already
function-application; only the identifier character set is
inconsistent (eq next to %).

Target Form-A:

  • +add
  • -sub (binary)
  • - (unary) → neg
  • *mul
  • /div
  • %mod (semantics TBD in brainstorm — see below)

The same intercept mechanism that ships eq__Int → icmp eq i64 in
crates/ailang-codegen/src/lib.rs::try_emit_primitive_instance_body
applies directly: add__Int → add nsw i64, mul__Int → mul nsw i64,
etc. No new infrastructure needed.

Prose (Form-B) keeps infix. Per #26, prose renders for human
readability. (app add a b) in Form-A renders as a + b in prose;
the rename is invisible to the prose reader. The prose printer's
rewrite rule extends from eq → == to include add → +, mul → *,
etc.

Surface impact (migration scope):

  • All .ail fixtures under examples/ (currently ~60+ touching
    arithmetic)
  • examples/prelude.ail
  • docs/specs/ worked examples
  • design/contracts/ examples
  • crates/ailang-core/src/desugar.rs builtin tables
  • crates/ailang-codegen/src/lib.rs intercept allowlist
  • Prose printer (crates/ailang-prose/) operator-render table
  • Surface lexer (crates/ailang-surface/) — may still accept +
    etc. in Form-A authoring, depending on whether parser strictness is
    part of this milestone or a follow-up

Open questions for the brainstorm:

  1. mod vs rem — C99 % returns sign-of-dividend (rem-semantics);
    Python % returns sign-of-divisor (true mod). Pick one and name
    it correctly. (Today's % is C99 rem-semantics; naming it mod
    would be a semantic lie.) Probably rem is the honest pick.
  2. Unary minus: (app neg x) vs (app sub 0 x). Probably distinct
    neg to avoid an arithmetic identity in the surface.
  3. Should arithmetic eventually route through a future Num class
    (parallel to Eq/Ord), or stay monomorphic builtins? Affects
    whether the milestone touches typechecker class-routing or only
    the rename.
  4. Strict deprecation: does Form-A still parse the symbolic forms
    (with a warning) for one milestone before they error out, or is
    the rename a hard cut at landing?

Trade-off accepted (per user decision 2026-05-21): LLM training
prior favors +/*/% substantially more than ==/< (which the
or-milestone already pushed against). Surface consistency wins per
the or-milestone precedent. An LLM that can write eq can write
add.

Depends on: none structurally; can ship before or after #26.
Coordinate the prose-printer change with #26's infix-rendering work
so both land in one cohesive prose rewrite.

**Goal: full surface consistency.** Extend the named-function principle the operator-routing-eq-ord milestone applied to comparison (`==`→`eq`, `<`→`lt`, …) to the last special-character builtins. After this milestone, Form-A contains zero symbol-named identifiers. **Today:** arithmetic ops are monomorphic Int builtins, parsed as operators, desugared to `(app + a b)` in Form-A. Form-A is already function-application; only the identifier character set is inconsistent (`eq` next to `%`). **Target Form-A:** - `+` → `add` - `-` → `sub` (binary) - `-` (unary) → `neg` - `*` → `mul` - `/` → `div` - `%` → `mod` (semantics TBD in brainstorm — see below) The same intercept mechanism that ships `eq__Int → icmp eq i64` in `crates/ailang-codegen/src/lib.rs::try_emit_primitive_instance_body` applies directly: `add__Int → add nsw i64`, `mul__Int → mul nsw i64`, etc. No new infrastructure needed. **Prose (Form-B) keeps infix.** Per #26, prose renders for human readability. `(app add a b)` in Form-A renders as `a + b` in prose; the rename is invisible to the prose reader. The prose printer's rewrite rule extends from `eq → ==` to include `add → +`, `mul → *`, etc. **Surface impact (migration scope):** - All `.ail` fixtures under `examples/` (currently ~60+ touching arithmetic) - `examples/prelude.ail` - `docs/specs/` worked examples - `design/contracts/` examples - `crates/ailang-core/src/desugar.rs` builtin tables - `crates/ailang-codegen/src/lib.rs` intercept allowlist - Prose printer (`crates/ailang-prose/`) operator-render table - Surface lexer (`crates/ailang-surface/`) — may still accept `+` etc. in Form-A authoring, depending on whether parser strictness is part of this milestone or a follow-up **Open questions for the brainstorm:** 1. `mod` vs `rem` — C99 `%` returns sign-of-dividend (rem-semantics); Python `%` returns sign-of-divisor (true mod). Pick one and name it correctly. (Today's `%` is C99 rem-semantics; naming it `mod` would be a semantic lie.) Probably `rem` is the honest pick. 2. Unary minus: `(app neg x)` vs `(app sub 0 x)`. Probably distinct `neg` to avoid an arithmetic identity in the surface. 3. Should arithmetic eventually route through a future `Num` class (parallel to `Eq`/`Ord`), or stay monomorphic builtins? Affects whether the milestone touches typechecker class-routing or only the rename. 4. Strict deprecation: does Form-A still parse the symbolic forms (with a warning) for one milestone before they error out, or is the rename a hard cut at landing? **Trade-off accepted (per user decision 2026-05-21):** LLM training prior favors `+`/`*`/`%` substantially more than `==`/`<` (which the or-milestone already pushed against). Surface consistency wins per the or-milestone precedent. An LLM that can write `eq` can write `add`. **Depends on:** none structurally; can ship before or after #26. Coordinate the prose-printer change with #26's infix-rendering work so both land in one cohesive prose rewrite.
Brummel added the feature label 2026-05-21 10:07:21 +02:00
Sign in to join this conversation.