Two small features carry more everyday code than most big ones. The first
closes the gap between declaring a name and giving it meaning. The second
is the answer to a question every Pascal newcomer asks in week one —
where is return? — and the answer is better than the thing it
replaces.
The example is InitAndLeave.
A declaration that starts alive
const
Base = 40;
var
answer : int64 := Base + 2; { unit level: constant expressions }
function FirstDivisor(n : int64) : int64;
var
d : int64 := 2; { local: any visible expression }A local initializer chains anything the position can see — the parameter, constants, earlier locals, a call result. A unit-level initializer must be a constant expression, and the compiler explains why in the refusal:
analyzer error 5231: the initializer of program-level variable 'n' must be
a constant expression: program-level state is materialized before the body
runs, so there is no earlier moment for run-time codeNo reader ever meets d without knowing what it starts as; no init-order
puzzle can exist because there is no moment before the constants.
leave: the activation exit
Mica has no return, and the difference is not spelling. A function’s
result is its own name — assigned like a variable, kept until the
activation ends — and leave ends the activation:
FirstDivisor := n; { the prime's answer: itself }
while d * d <= n do
begin
if n mod d = 0 then
begin
FirstDivisor := d;
leave; { the activation ends HERE }
end;
d := d + 1;
end;Two consequences. Result-setting and exiting are separate acts, so “the
answer unless something better turns up” costs one assignment before the
loop instead of a flag. And bare leave inside a loop still exits the
activation, not the loop — one word, one meaning, with every pending
defer running on the way out, which is why
on fail leave could reuse the whole mechanism.
when puts the condition on the exit itself, which turns the guard clause
into one line with no pyramid above the real body:
procedure Report(n : int64);
begin
leave when n = 0;
WriteLn(" first divisor of %lld is %lld", n, FirstDivisor(n));
end;The guard clause
first divisor of 91 is 7
first divisor of 97 is 97Leaving a loop needs the loop’s name
To exit a loop early, name it — and leave <label> when exits it from
any depth, in one line:
search : for row := 1 to 5 do
for col := 1 to 5 do
begin
tries := tries + 1;
found := row * 10 + col;
leave search when row * col = 12;
end;Leaving a labeled loop from inside
product 12 first at row 3 col 4, after 14 triesFourteen tries instead of twenty-five — and no break/break 2/flag
ceremony. A name that names no enclosing loop is refused with the scope
rule attached:
analyzer error 5227: no enclosing loop is named 'hunt': a loop name can
only be targeted from inside the loop it namesnext is the family’s small sibling — skip to the loop’s next round:
for i := 1 to 10 do
begin
if i mod 2 = 0 then
next;
odds := odds + i;
end;Skipping with next
the odd numbers below eleven sum to 25What this does not do
leavecarries no value. The result name already has one; the exit is an exit, not an expression. That separation is what let the failure channel, cancellation, and defer all ride the same machinery.- Bare
leavenever means “exit the loop”. In a deeply nested body that reads surprisingly at first and exactly once — after that, everyleavein any code means one thing. - A deferred statement cannot
leave. Cleanups run inside the exit sequence; an exit inside the exit is refused — defer’s rules hold here unchanged.
Try it
git clone https://gitlab.com/mica-lang/mica-container.git
make -C mica-container/examples/InitAndLeave runRename the label to hunt in the leave line only and meet 5227. Then
move FirstDivisor := n; below the loop and watch the prime rows change —
the assignment-then-leave shape made visible by breaking it.
Next
With maps, bit records and this pair, the retired language tour’s lessons all have focused homes. The series’ remaining ground: the C boundary, and tooling end to end.