Froth, and this site, are pre-alpha. This site is largely OSAI-generated documentation from the Froth repo.

OldFroth put the data stack in the center of the public language. Current Froth does not. The runtime still has internal machinery, but the language you write is organized around values, expressions, names, and calls.

That shift is not cosmetic. It changes how you read code.

3 + 4

This is an expression. It evaluates to 7. Operators are ordinary parts of the expression grammar, not postfix stack words. Binary operators have equal precedence and associate left to right, so use parentheses when grouping matters:

(3 + 4) * 2
3 + (4 * 2)

Froth does not reward guessing precedence. Group the expression you mean.

The Value Set

The core value classes are deliberately small:

  • Int
  • Bool
  • Nil
  • Text
  • Cells
  • Code

Everything user-facing is either a value or a place that holds one. There are no raw pointers, general foreign handles, or implementation-private control objects in the ordinary language.

Names Hold The Conversation Together

At top level, a name refers to a stable slot:

speed is 75
speed is 120

That is a rebind, not a fresh variable floating in space. The top-level slot named speed is the same slot before and after the second line. What changed is the value currently stored there.

That matters for live work. If one piece of code calls pulse, and you later rebind pulse, callers that resolve through that top-level slot see the new behavior.

to pulse with pin [
  gpio.high: pin;
  ms: 75;
  gpio.low: pin
]

pulse: LED_BUILTIN

to pulse with pin [
  gpio.high: pin;
  ms: 20;
  gpio.low: pin
]

The name is stable. The value changed. The image remains inspectable.

Calls Read Like Calls

Foreign bindings and Froth definitions use the same call surface:

gpio.write: LED_BUILTIN, 1
ms: 100
blink: LED_BUILTIN, 3, 75

The callee appears before the colon. Arguments follow after the colon, separated by commas. A zero-argument call still uses the colon when you are asking for the code to run:

matrix.init:
grid.show:

Without the call, a name is a value lookup. That distinction is why Code can be passed around like any other value.

Lookup Order

When Froth sees a name, it searches:

  1. the current local scope
  2. enclosing local scopes
  3. top-level slots

A local can shadow a top-level name:

speed is 75

demo is fn [
  here speed is 10;
  speed
]

Inside demo, speed means the local. Outside it, speed still means the top-level slot.

The old stack chapter taught how to keep track of invisible intermediate values. In current Froth, the equivalent discipline is simpler: name the state you intend to keep, group expressions that need grouping, and inspect the live image when you are not sure what a name currently holds.

Next: Words and definitions .