← Back to path Download .md

Why Verse Fails

beginner 4 lessons · ~100 min · Generated 2026-07-17

Every Verse tutorial shows you code that works — and then you meet the real compiler. This track is different: every lesson is taught FROM real errors, captured from real builds, with the fix and the why. By the end, a wall of red output is a thirty-second repair. The compiler was never fighting you; it was teaching.

Prerequisites

Learning Outcomes

Lesson 1: Failure Is a Feature

Objectives

Read errors 3511 and 3512: failure contexts, <decides>, and why the compiler rejecting your code is the language working.

Quiz

  1. Why does `FirstKey := KeyNames[0]` fail to compile on its own line?
    • A. Arrays must be declared var to be indexed
    • B. Indexing might fail, so it needs a failure context with a plan for that
    • C. KeyNames is immutable so it cannot be read
    • D. Verse requires FirstKey to be declared with a type
  2. What does Script error 3511 tell you?
    • A. The function does not exist
    • B. You used square brackets on a function that always succeeds
    • C. You used parentheses to call a function that might fail — decides calls need []
    • D. The function is missing a return type
  3. What does a <decides> function's body return?
    • A. true or false
    • B. An option value
    • C. Nothing — succeeding or failing IS the answer
    • D. An error code
  4. Which of these is a failure context, per the compiler's own error text?
    • A. The right-hand side of an assignment
    • B. The condition clause of an if
    • C. A Print argument
    • D. A class field default
  5. Why does `IsLocked : logic = State = door_state.Locked` fail?
    • A. logic is not a real Verse type
    • B. Enums can only be compared with case
    • C. = comparison can fail, and a plain assignment is not a failure context
    • D. State must be declared without var
Answer key
  1. B — Array indexing carries the decides effect — the index might not exist — so it may only appear in a failure context like an if condition.
  2. C — Brackets tell the truth about failure: () for calls that always succeed, [] for <decides> calls that might fail.
  3. C — A decides function doesn't return a boolean; its body is the test, and success or failure is the result the caller handles.
  4. B — Error 3512 lists them: the condition clause of an if, the left operand of or, the clause of the logic macro.
  5. C — In Verse, = comparison succeeds-or-fails (it carries decides), so it must sit in a failure context — ask the question in an if instead of storing a flag.

Sources

Lesson 2: The Effects System

Objectives

Function contracts, the silent no_rollback default, and effect transitivity — 3512's second face.

Quiz

  1. What effect does an unannotated Verse function have?
    • A. <transacts>
    • B. <decides>
    • C. no_rollback — its work cannot be undone
    • D. No effect at all
  2. Why do failure contexts only allow rollback-safe work?
    • A. For performance
    • B. A failed attempt is UNDONE as if it never happened — so everything inside must be undoable
    • C. Because devices are slow
    • D. It's a style convention
  3. A pure math helper fails 3512 when called in an if condition. The fix?
    • A. Move the call out of the if
    • B. Annotate the helper <transacts>
    • C. Mark the helper <decides>
    • D. Wrap it in spawn{}
  4. Why can't a function that calls GrantItemIndex be marked <transacts>?
    • A. It can, with the right using
    • B. Granting a real item can't be undone — the native call is no_rollback and your annotation can't change that
    • C. GrantItemIndex is <decides>
    • D. Device methods need <suspends>
  5. What does 'effects are transitive' mean?
    • A. Effects only apply inside classes
    • B. A <transacts> function may only call <transacts>-or-stricter functions — one unannotated callee breaks the chain
    • C. Effects copy to subclasses
    • D. suspends implies decides
Answer key
  1. C — The silent default: a function with no annotation is no_rollback. Pure helpers must opt IN to <transacts>.
  2. B — Failure contexts roll back the failed attempt; no_rollback work can't be un-rung.
  3. B — Rule of thumb: annotate pure helpers <transacts> — a promise a compute-only function can honestly make.
  4. B — You can't promise to undo a granted item. Leave world-touching callers undecorated — the signature then tells the truth.
  5. B — Contracts flow through call chains: a promise-keeper may only call other promise-keepers.

Sources

Lesson 3: One Rule, Four Costumes

Objectives

The allocation myth retired by gate probes: annotate the effect — position never mattered.

Quiz

  1. Is `if (Prices := map{{...}}, Cost := Prices[K]):` legal Verse?
    • A. No — allocation in a condition is always illegal
    • B. Yes — construction is rollback-safe; this compiles with zero errors
    • C. Only if the map is empty
    • D. Only inside OnBegin
  2. A helper returning a map fails 3512 when called in a condition. What's the actual defect?
    • A. Maps can't be returned from functions
    • B. The helper is unannotated, so it defaults to no_rollback
    • C. The condition has too many binders
    • D. Maps require <suspends>
  3. What does hoisting a call out of a condition actually do?
    • A. Fixes the effect contract
    • B. Works incidentally — it moves the unannotated call out of the restricted position without fixing the contract
    • C. Makes the call rollback-safe
    • D. Nothing; hoisted code fails the same way
  4. Which position is restricted like an if condition?
    • A. A case arm
    • B. A for loop's iterable position
    • C. OnBegin's body
    • D. A Print argument
  5. Why is a device call like GrantItemIndex legal inside a case arm?
    • A. case arms are failure contexts with special handling
    • B. A case arm is NOT a failure context — nothing rolls back there, so no_rollback work is at home
    • C. Device calls are exempt from all effect rules
    • D. It isn't legal
Answer key
  1. B — Gate-verified: a map literal directly in the condition binder compiles clean. Allocation was never the crime.
  2. B — The silent default — annotate the pure helper <transacts> and the same call in the same position compiles.
  3. B — Hoisting works by relocation, not repair. Annotate the helper; then place the call wherever reads best.
  4. B — The for-iterable is a restricted position — an unannotated helper there fails the same 3512; annotated, it's legal in place.
  5. B — Knowing where restrictions END matters: case dispatch doesn't undo anything, so world-changing calls belong there freely.

Sources

Lesson 4: Reading the Compiler

Objectives

The error-code field guide + cascade-reading: every string from real builds, every fix thirty seconds.

Quiz

  1. What is the single most common compile failure family in real Verse projects?
    • A. 3512 effects errors
    • B. 3506 unknown identifier — a name the file can't see (usually a missing using)
    • C. 3100 parse errors
    • D. 3581 break placement
  2. What's the fix loop?
    • A. Delete and rewrite the function
    • B. Read the code + quoted term → find the position → apply the family rule → recompile
    • C. Comment out lines until it compiles
    • D. Ask the forum
  3. 3513 'expected an expression that can fail' fires on `if (DoorOpen):` where DoorOpen is logic. Fix?
    • A. Declare DoorOpen as int
    • B. Postfix ? — `if (DoorOpen?):` turns the logic into a failable question
    • C. Wrap it in spawn{}
    • D. Use case instead
  4. You want to stop a `for` early and the compiler says 3581. What's idiomatic?
    • A. Add <breakable> to the for
    • B. Put the walk in its own function and return on the hit (or use loop:)
    • C. break twice
    • D. Use a while loop
  5. A 31xx vErr error means…
    • A. An effects contract broke
    • B. The parser couldn't read the line's SHAPE — look for missing braces or stray tokens
    • C. The file is too long
    • D. A missing using
Answer key
  1. B — By a wide margin: 3506. And the error text usually names the exact using to add.
  2. B — Every error in the guide is a thirty-second repair once read this way.
  3. B — A condition wants a question that can fail; ? makes a logic succeed-if-true, fail-if-false.
  4. B — break is loop-only in Verse; for-early-exit restructures to return-from-function or loop:.
  5. B — 31xx = syntax shape, not semantics: bare `spawn Tick()` needs `spawn{ Tick() }`.

Sources

Generated by Verse Island on 2026-07-17.