Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Other Loops

The Quick Tour shows foreach for iteration. Final also has indefinite loops that are not driven by an iterator. This page covers those, plus break and continue.

Like all control-flow blocks, these words are compile-only — use them inside : … ;.

FormKindNotes
forever … /foreverinfinitePrefer this over legacy begin … again; supports continue
begin … while … repeatpretestBody runs zero or more times
begin … untilpost-testBody runs at least once; exit when condition is truthy
begin … againlegacy infinitePrefer forever; no continue

Infinite: forever … /forever

No parameters. Loop until break, a fault, or an interactive Break (Ctrl-B in final).

> // ( n:i -- )
: tickN
  forever
    dup 0 <= if drop break then
    dup $ sp
    1 -
  /forever
  nl
;
3 tickN

3 2 1

An empty forever … /forever spins forever — use Ctrl-B to stop it in the TUI.

Pretest: begin … while … repeat

Words between begin and while run each attempt; while consumes a Truthy flag. Truthy → run the body through repeat and branch back to begin. Falsy → exit after while (skip the body).

> // ( n:i -- )
: drain
  begin
    dup while
      dup $ sp
      1 -
  repeat
  drop nl
;
3 drain

3 2 1

If the first test is already falsy, the body never runs:

> // ( -- )
: never
  0
  begin
    dup while
      "should not print\n" $
  repeat
  drop
;
never

Post-test: begin … until

The body runs, then until consumes a Truthy flag. Falsy → loop back to begin; truthy → exit. So the body always runs at least once.

> // ( n:i -- )
: blastoff
  begin
    dup $ sp
    1 -
    dup 0 == until
  drop nl
;
3 blastoff

3 2 1

Legacy infinite: begin … again

Same idea as forever, but older spelling. Prefer forever … /forever in new code — again does not support continue.

> // ( n:i -- )
: tickAgain
  begin
    dup 0 <= if drop break then
    dup $ sp
    1 -
  again
  nl
;
3 tickAgain

3 2 1

break

Exit the innermost enclosing loop among:

  • foreach … /foreach
  • forever … /forever
  • begin … until
  • begin … while … repeat
  • legacy begin … again

Typical pattern: test inside the loop, then if break then.

> // ( -- )
: findThree
  1 10 range
  foreach
    i 3 == if break then
    i $ sp
  /foreach
  nl
;
findThree

1 2

When i is 3, break exits before the print, so only 1 2 appear.

continue

Skip the rest of the current iteration. Allowed only in:

  • foreach … /foreach
  • forever … /forever

Not in until or while … repeat.

> // ( -- )
: oddsOnly
  1 6 range
  foreach
    i 2 % 0 == if continue then
    i $ sp
  /foreach
  nl
;
oddsOnly

1 3 5

Inside forever, continue jumps back to the top of the forever body (here: skip printing 2):

> // ( -- )
: demoSkip
  3
  forever
    dup 0 < if drop break then
    dup 2 == if 1 - continue then
    dup $ sp
    1 -
  /forever
  nl
;
demoSkip

3 1 0

Both break and continue may sit inside an if / else / then — they still apply to the containing loop, not to the conditional.

To affect an outer loop, set a flag or sentinel in the inner loop and test it in the outer loop after /foreach or the matching closer.