Skip to content

game.eigs: the physics unobserved: comment credits the half that stopped doing anything #37

Description

@InauguralPhysicist

Not a bug — the block is still load-bearing and should stay. The comment is now misleading, and this repo is where the idiom originated, so it is worth getting right.

src/game.eigs:342:

# Physics — no observation needed, pure numeric mutation
unobserved:
    game.current_angle is game.current_angle + CURRENT_ROTATE_RATE * SIM_DT

That framing was accurate when this landed (872c45f, 2026-04-17, "Wrap physics in unobserved blocks — zero-allocation game tick"). Upstream's tree-walking eval.c gated the dict in-place fast path on the block — eval.c:487, AST_DOT_ASSIGN — so game.current_angle is ... really did skip an allocation.

Upstream NaN-boxing B-3a (2026-05-22) then added dict_set_cached_immediate for DMG's register-write hot path: same in-place mutation, no g_unobserved_depth check. The win became unconditional and the gate went away. So of this block's 21 assignments, the 14 dict/index targets now get nothing from it — they are never observed (bookkeeping is gated on the named env path) and are mutated in place regardless.

The block still earns its place through the other half — the 7 named locals, which are exactly what unobserved: helps:

turn is player_turn_rate of game
thrust is player_thrust of game
cx is (cos of game.current_angle) * CURRENT_SPEED * SIM_DT
cy is (sin of game.current_angle) * CURRENT_SPEED * SIM_DT
drag is player_drag of game
drain_rate is 1.0

Plus every function it calls: g_unobserved_depth is global, not lexical, so player_thrust, player_drag and friends all run unobserved too and their internal named assignments are skipped as well. That is likely the larger share.

Why file it

This block is the ancestor of upstream's README example, which distilled it down to only the dict half and shipped that as the headline unobserved demo for two months (EigenScript#655, fixed in EigenScript#658). A reader coming here to see the idiom "in production" reads a comment that points at the inert half. The next person to copy this pattern copies the dead part.

Fix

Reword to credit the named locals and the called functions rather than the dict writes. Something like:

# Physics — the named locals below (turn/thrust/cx/cy/drag/drain_rate) and
# every function called from here run without observer bookkeeping. The
# game.* field writes are along for the ride: dict fields are never observed
# and are mutated in place regardless (upstream dict_set_cached_immediate),
# so the block is not what makes those cheap.

Verified against upstream main: eigenscript --lint src/game.eigs reports no W020 — the new upstream lint for provably-inert blocks correctly leaves this one alone, because it is not inert. Only the comment needs changing.

Metadata

Metadata

Assignees

No one assigned

    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