03. Values and Expressions
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:
IntBoolNilTextCellsCode
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:
- the current local scope
- enclosing local scopes
- 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 .