<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>sysl</title>
  <link href="https://sysl.sh/feed.xml" rel="self"/>
  <link href="https://sysl.sh/"/>
  <id>https://sysl.sh/feed.xml</id>
  <updated>2026-08-16T01:26:07.924728867Z</updated>
  <author><name>Ed Maxedon</name></author>
  <entry>
    <title>Verification</title>
    <link href="https://sysl.sh/reference/verification/"/>
    <id>https://sysl.sh/reference/verification/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Quantifiers, loop invariants, termination measures, `@pure`, `@reads`/`@writes`, `@ghost`, and `sysl prove` — the clauses that say what a program means, and the prover that reads them.</summary>
    <content type="html">&lt;p&gt;&lt;a href=&quot;/tour/contracts/&quot;&gt;Contracts&lt;/a&gt; give sysl &lt;code&gt;require&lt;/code&gt;, &lt;code&gt;ensure&lt;/code&gt; and &lt;code&gt;invariant&lt;/code&gt;, and every one of them is
a branch and a trap. This page is the other half: the vocabulary a &lt;em&gt;specification&lt;/em&gt; needs that an
executable condition does not supply on its own, and the backend that discharges the result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One clause means one thing.&lt;/strong&gt; The prover and the running program read the same sentence. There is
no proof-only build, no specification subset the compiler declines to execute, and a check the prover
proves redundant is still compiled — a program whose emitted code depended on whether a prover was
available, and on how long it was given, is one nobody could reason about. The single exception is
&lt;a href=&quot;#ghost-what-costs-nothing-to-say&quot;&gt;ghost code&lt;/a&gt;, and it is legible in the source rather than in a
flag.&lt;/p&gt;
&lt;h2 id=&quot;for-all-and-for-some&quot;&gt;&lt;code&gt;for all&lt;/code&gt; and &lt;code&gt;for some&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A quantifier over an integer range, universal and existential. It is an ordinary &lt;code&gt;bool&lt;/code&gt;, usable
wherever one is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; a[i] % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; some k &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; a[k] &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; some k &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; a[k] &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;all&lt;/code&gt; and &lt;code&gt;some&lt;/code&gt; stay ordinary identifiers — they are read as keywords only directly after &lt;code&gt;for&lt;/code&gt;, and
only when a name follows. So a loop over a variable called &lt;code&gt;all&lt;/code&gt; is still a loop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(all)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0
1
2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The separator is &lt;code&gt;do&lt;/code&gt;, the word every loop header already uses. The predicate extends as far to the
right as an expression can, exactly as a closure’s body does, so &lt;code&gt;for all i in r do P(i) &amp;amp;&amp;amp; Q(i)&lt;/code&gt;
quantifies over the conjunction. Written as the second arm of a chain, a quantifier is parenthesized:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] == &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; &amp;amp;&amp;amp; (&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; a[i] &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An empty range takes each quantifier’s identity.&lt;/strong&gt; A conjunction over nothing is true and a
disjunction over nothing is false — these are not conventions, and getting them the other way round
breaks every proof that reasons about the first iteration of anything. A range whose bounds are the
wrong way round is empty too, which is what &lt;code&gt;for all i in 0..&amp;lt;n - 1&lt;/code&gt; needs when &lt;code&gt;n&lt;/code&gt; is zero:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; some i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
false
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both forms short-circuit: &lt;code&gt;for all&lt;/code&gt; stops at the first counterexample, &lt;code&gt;for some&lt;/code&gt; at the first
witness. That is observable, because a predicate may trap, so it is specified rather than left to the
emitter.&lt;/p&gt;
&lt;h2 id=&quot;invariant-and-variant-on-a-loop&quot;&gt;&lt;code&gt;invariant&lt;/code&gt; and &lt;code&gt;variant&lt;/code&gt; on a loop&lt;/h2&gt;
&lt;p&gt;Both are written as the leading statements of a loop’s body, in the position &lt;code&gt;require&lt;/code&gt; and &lt;code&gt;ensure&lt;/code&gt;
take at the top of a function. Written as statements rather than as slots in each loop’s header, one
rule serves all five loop forms:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum_to&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; n
        &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; i &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; i &amp;lt;= n
        variant n - i
        s += i
        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    s

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum_to&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;invariant&lt;/code&gt; is checked on every entry to the body&lt;/strong&gt; — on arrival at the loop, and again before each
subsequent iteration. It is not checked on the way out: that is where the clause is written, and a
clause that also ran on exit would be checking something the loop is no longer doing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;variant&lt;/code&gt; is a live termination check.&lt;/strong&gt; The measure is taken at the top of each iteration and
compared against the previous one; a run that fails to decrease traps. So a loop that stops making
progress stops, rather than running forever:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a loop that stops decreasing stops&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, should_trap)
&lt;span class=&quot;hl-function&quot;&gt;spins&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
        variant &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; - i
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; i == &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; i -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The measure is not required to be non-negative. A strictly decreasing integer unbounded below still
fails to prove termination, and that failure belongs to the prover — making it a runtime trap would
refuse programs that terminate for a reason the clause does not capture.&lt;/p&gt;
&lt;p&gt;Both words are contextual, so a value may still be called either:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; variant = &lt;span class=&quot;hl-number&quot;&gt;35&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; + variant

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A clause written after ordinary work is not an invariant, and is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; i &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    i&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an &apos;invariant&apos; belongs at the head of a loop&apos;s body
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;variant-on-a-function&quot;&gt;&lt;code&gt;variant&lt;/code&gt; on a function&lt;/h2&gt;
&lt;p&gt;The same word in a function’s contract block declares what decreases at a recursive call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; b &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    variant b
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; b == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; a
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(b, a % b)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;48&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A function’s &lt;code&gt;variant&lt;/code&gt; may read only its parameters&lt;/strong&gt;, and that restriction is what makes the check
local. At a direct self-call the compiler has both the current parameter values and the arguments
about to replace them, so it evaluates the measure twice — once as it stands, once with the arguments
in the parameters’ own slots — and traps when the second is not less than the first. No hidden
argument travels with the call, and nothing is kept between calls.&lt;/p&gt;
&lt;p&gt;Scoping is what enforces the restriction: the clause is analyzed before the body, in a scope holding
the parameters alone, so a name from the body is simply undefined there.&lt;/p&gt;
&lt;p&gt;The check happens &lt;em&gt;before&lt;/em&gt; the call, so unlike an &lt;code&gt;ensure&lt;/code&gt; it survives the tail-call transform and a
&lt;code&gt;@tailrec&lt;/code&gt; function may carry one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tailrec&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;walk&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, acc: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    variant n
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; acc
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;walk&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, acc + n)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;walk&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The check reaches direct self-calls only. Mutual recursion between two functions with measures is a
proof obligation for &lt;code&gt;sysl prove&lt;/code&gt; and is not checked at runtime — there is no call site at which both
halves of the measure are in hand.&lt;/p&gt;
&lt;h2 id=&quot;pure&quot;&gt;&lt;code&gt;@pure&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;An annotation, checked by the compiler, refused on violation. A caller of a pure function can observe
nothing about the call but its result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = x * x

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;fact&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; n &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; n * &lt;span class=&quot;hl-function&quot;&gt;fact&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;fact&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;49 120
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What it may do:&lt;/strong&gt; read its parameters and any &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;val&lt;/code&gt;; declare and mutate its own locals;
call other pure functions; recurse; use every control-flow form; &lt;strong&gt;allocate&lt;/strong&gt;; and &lt;strong&gt;trap&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it may not do:&lt;/strong&gt; call a function that is not pure, including any &lt;code&gt;extern&lt;/code&gt;; write through a
&lt;code&gt;*T&lt;/code&gt;, into a &lt;code&gt;&amp;amp;T&lt;/code&gt;‘s field, or into any storage it did not create; perform I/O; contain an &lt;code&gt;asm&lt;/code&gt; block;
call through a closure, or dispatch through a trait object.&lt;/p&gt;
&lt;p&gt;A write is examined through its &lt;em&gt;path&lt;/em&gt;, not its root — so storage the call made is the call’s,
however deep the indexing goes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(a: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
        t += b[i]

    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(xs))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;108
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A pure function may allocate&lt;/strong&gt;, which is a deliberate departure from other languages’ purity
checks. A caller cannot observe an object that did not exist when the call began, and banning
allocation would put every string operation out of reach. The question allocation raises is a real
one and sysl answers it elsewhere — &lt;code&gt;no alloc&lt;/code&gt; answers it for a whole module, at the point of
allocation. Two annotations for two questions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;shout&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = s + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;shout&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hi!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Writing through a reference the function was handed is refused, since that is what a caller sees:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
    &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;@pure&apos; function writes through a reference to storage it did not create
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So is I/O, which is the same rule reaching a call rather than a store:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pure&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)
    x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;which is not marked &apos;@pure&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Purity is not inferred.&lt;/strong&gt; A function is pure because it says so — inference would let an unrelated
edit to a leaf break a caller three levels up with no annotation anywhere naming the promise. Nothing
in the standard library is annotated yet, so a pure function today reaches the language and other
pure functions the program wrote.&lt;/p&gt;
&lt;h2 id=&quot;reads-and-writes-what-a-call-may-touch&quot;&gt;&lt;code&gt;@reads&lt;/code&gt; and &lt;code&gt;@writes&lt;/code&gt; — what a call may touch&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@pure&lt;/code&gt; says a call touches no module storage at all. Most functions worth reasoning about are not
that, and the looser form says &lt;em&gt;which&lt;/em&gt; storage they touch:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;reads&lt;/span&gt;(limit)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;writes&lt;/span&gt;(count)
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; count &amp;lt; limit &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(count)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A frame names module storage, so these are &lt;code&gt;static var&lt;/code&gt; — the entry file’s spelling for it. A &lt;code&gt;var&lt;/code&gt;
in a module of its own is the same storage and is named the same way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A frame is what makes a call something other than an eraser.&lt;/strong&gt; Given &lt;code&gt;f()&lt;/code&gt; with nothing written
down, everything a prover knew about module state after the call is &lt;code&gt;true&lt;/code&gt; — any variable might have
changed. The annotation is the only thing that stops that, which is why it matters more than the
convenience of writing it down suggests.&lt;/p&gt;
&lt;p&gt;The compiler holds an annotated function to three rules. &lt;strong&gt;In the body&lt;/strong&gt;, a read of a variable needs
it in &lt;code&gt;@reads&lt;/code&gt; or &lt;code&gt;@writes&lt;/code&gt;, and a write needs it in &lt;code&gt;@writes&lt;/code&gt;. &lt;strong&gt;At a call&lt;/strong&gt;, the callee’s frame
must fit inside the caller’s. And an annotated function may call only annotated or &lt;code&gt;@pure&lt;/code&gt; functions —
not through a value, not through a trait object, and with no &lt;code&gt;asm&lt;/code&gt; block — because each of those is a
call site with no declaration to consult.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@writes&lt;/code&gt; permits reading.&lt;/strong&gt; &lt;code&gt;count += 1&lt;/code&gt; is a read and a write of one variable, and a form that
common should not have to be declared twice:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;writes&lt;/span&gt;(count)
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
    count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(count)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Writing any part of a variable is writing the variable.&lt;/strong&gt; After &lt;code&gt;buf[i] = b&lt;/code&gt; the storage holds
something different, which is the only question a prover is asking — so an array reached by index
belongs under &lt;code&gt;@writes&lt;/code&gt;, not &lt;code&gt;@reads&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; buf: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pos: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;reads&lt;/span&gt;(buf)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;writes&lt;/span&gt;(pos)
&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    buf[pos] = b
    pos += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;65&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a function with a frame writes &apos;buf&apos;, which its &apos;@writes&apos; does not name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Writing no frame is not the same as writing an empty one.&lt;/strong&gt; A function with no annotation has
effects nobody has written down and may call and be called by anything, exactly as before frames
existed; &lt;code&gt;@reads()&lt;/code&gt; &lt;code&gt;@writes()&lt;/code&gt; is the positive claim that it touches nothing. That difference is
what lets the discipline start at the leaves and climb at whatever pace its author sets, rather than
arriving as a flag day. &lt;code&gt;@pure&lt;/code&gt; is &lt;code&gt;@reads()&lt;/code&gt; &lt;code&gt;@writes()&lt;/code&gt; plus the further bans above, so writing a
frame beside it is refused as saying one thing twice.&lt;/p&gt;
&lt;h2 id=&quot;ghost-what-costs-nothing-to-say&quot;&gt;&lt;code&gt;@ghost&lt;/code&gt; — what costs nothing to say&lt;/h2&gt;
&lt;p&gt;Everything above executes, and that has a cost in exactly one place: a specification is often more
expensive than the code it specifies. &lt;code&gt;invariant is_sorted(a, i)&lt;/code&gt; is the right invariant for an
insertion sort’s outer loop, it is O(n) where the body is O(n), and checking it every iteration turns
an O(n²) sort into O(n³).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@ghost&lt;/code&gt; marks a declaration that exists for the specification alone. It is erased before codegen and
costs nothing at run time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;ghost&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;is_sorted&lt;/span&gt;(a: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; all i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; a[i] &amp;lt;= a[i + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;insertion&lt;/span&gt;(a: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;is_sorted&lt;/span&gt;(a, n)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; n
        &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;is_sorted&lt;/span&gt;(a, i)
        variant n - i
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; j = i

        &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; j &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; a[j - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] &amp;gt; a[j]
            variant j
            &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = a[j - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]

            a[j - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = a[j]
            a[j] = t
            j -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;insertion&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
1 2 5 7 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two rules make erasing it sound:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Nothing executable may call a ghost function.&lt;/strong&gt; If it could, erasing the declaration would
change what the program computes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A clause that calls one is a clause that does not run.&lt;/strong&gt; Given the first it &lt;em&gt;cannot&lt;/em&gt; run — the
callee is not there — so the only question was whether to allow such a clause at all.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The second is the one exception to “a clause means one thing”, and it is acceptable because it is
&lt;strong&gt;visible in the source&lt;/strong&gt;: a reader asking whether a clause executes reads the names in it. What sysl
refuses is a &lt;em&gt;switch&lt;/em&gt;, where one program has two meanings depending on how it was built.&lt;/p&gt;
&lt;p&gt;An ordinary clause beside a ghost one is untouched, and still traps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;ghost&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;positive&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; n &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;positive&lt;/span&gt;(n)
    n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling a ghost function from code that runs is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;ghost&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;positive&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;positive&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is &apos;@ghost&apos;, so it exists for the specification and is not there when the program runs
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A ghost function’s own body is ordinary code and may read real state freely — that is the whole point
of an &lt;code&gt;is_sorted&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;sysl-prove&quot;&gt;&lt;code&gt;sysl prove&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sysl prove &amp;lt;file&amp;gt;&lt;/code&gt; translates a module to &lt;a href=&quot;https://www.why3.org/&quot;&gt;WhyML&lt;/a&gt;, the input language of the
Why3 platform, and discharges the resulting goals with whichever provers Why3 is configured with.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ sysl prove gcd.sysl
Goal gcd&apos;vc.
Prover result is: Valid (0.01s, 165 steps).

every goal was discharged
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--emit-whyml&lt;/code&gt; prints the translation instead of proving it, which is what to reach for when a goal
will not go through.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A proof is not a build.&lt;/strong&gt; Nothing is emitted and nothing about &lt;code&gt;sysl build&lt;/code&gt; changes. A module that
fails to prove still compiles and still runs, with every check this page describes. What the prover
buys is finding out before the program runs rather than at the trap.&lt;/p&gt;
&lt;h3 id=&quot;integer-overflow-is-a-proof-obligation&quot;&gt;Integer overflow is a proof obligation&lt;/h3&gt;
&lt;p&gt;sysl’s plain integer arithmetic wraps; WhyML’s &lt;code&gt;int&lt;/code&gt; is the mathematical integers, which do not.
Translating &lt;code&gt;a + b&lt;/code&gt; to &lt;code&gt;a + b&lt;/code&gt; would prove theorems about a language sysl is not — silently, which is
the worst kind of wrong. So in code every arithmetic operation goes through a checked wrapper whose
precondition is that the true result is representable:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let add_i32 (a b: int) : int
  requires { -2147483648 &amp;lt;= a + b &amp;lt;= 2147483647 }
  ensures  { result = a + b }
= a + b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A program that stays in range gets the mathematical model, which is exact for it. One that might not
gets a failed goal naming the operation — so &lt;code&gt;n * 2&lt;/code&gt; for an &lt;code&gt;n&lt;/code&gt; known only to be non-negative does
not discharge, and the same function with &lt;code&gt;require n &amp;lt;= 1000&lt;/code&gt; does. &lt;code&gt;--overflow ignore&lt;/code&gt; drops the
obligations for somebody reasoning about the rest of a function first.&lt;/p&gt;
&lt;p&gt;Every integer parameter carries its own range as a precondition, which is not an extra demand on the
caller: it is the fact that the argument had the type it was declared with.&lt;/p&gt;
&lt;h3 id=&quot;terms-and-programs&quot;&gt;Terms and programs&lt;/h3&gt;
&lt;p&gt;WhyML separates &lt;em&gt;terms&lt;/em&gt;, which are mathematics and may appear in a &lt;code&gt;requires&lt;/code&gt;, from &lt;em&gt;programs&lt;/em&gt;, which
have state and may not. &lt;strong&gt;&lt;code&gt;@ghost&lt;/code&gt; is what decides which world a function lands in&lt;/strong&gt; — a ghost
function becomes a &lt;code&gt;predicate&lt;/code&gt;, and every other function becomes a program. So a contract that calls
an ordinary function is refused, with the sentence that says to mark it.&lt;/p&gt;
&lt;p&gt;That also means a ghost function’s body must be one expression: a specification is mathematics, so it
may not declare a variable or run a loop.&lt;/p&gt;
&lt;h3 id=&quot;what-is-translated&quot;&gt;What is translated&lt;/h3&gt;
&lt;p&gt;The scalar fragment: functions whose parameters, locals and result are integers and booleans;
arithmetic and comparison; &lt;code&gt;if&lt;/code&gt;; &lt;code&gt;while&lt;/code&gt;; local variables and assignment; &lt;code&gt;require&lt;/code&gt;, &lt;code&gt;ensure&lt;/code&gt;,
&lt;code&gt;result&lt;/code&gt;, &lt;code&gt;old&lt;/code&gt;, both quantifiers, loop &lt;code&gt;invariant&lt;/code&gt; and &lt;code&gt;variant&lt;/code&gt;, function &lt;code&gt;variant&lt;/code&gt;, and &lt;code&gt;@ghost&lt;/code&gt;
declarations.&lt;/p&gt;
&lt;p&gt;Anything else is refused &lt;strong&gt;by name&lt;/strong&gt; — &lt;em&gt;“the proof backend does not translate an array or a slice”&lt;/em&gt; —
so that a gap in the translator reads as a gap in the translator, and not as a program the prover
disliked. Arrays are the largest absence.&lt;/p&gt;
&lt;h3 id=&quot;installing-why3&quot;&gt;Installing Why3&lt;/h3&gt;
&lt;p&gt;Why3 installs through opam and has no Homebrew formula:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;$ opam install why3 alt-ergo
$ why3 config detect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A shell that has not run &lt;code&gt;eval $(opam env)&lt;/code&gt; will not see one that is installed. Z3 works as the
prover too, and Why3 finds it once &lt;code&gt;why3 config detect&lt;/code&gt; has run.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Vectors</title>
    <link href="https://sysl.sh/reference/vectors/"/>
    <id>https://sysl.sh/reference/vectors/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`&lt;N&gt;T` is an array that computes lane-wise — one instruction for N additions, one kernel for every register width, and it still compiles where there is no vector unit at all.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;&amp;lt;N&amp;gt;T&lt;/code&gt; holds N lanes of &lt;code&gt;T&lt;/code&gt; — the same values an &lt;code&gt;[N]T&lt;/code&gt; holds, in the same order — with one
difference: its operators work on every lane at once.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c = a + b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], c[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11 44
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;+&lt;/code&gt; is one machine instruction computing four additions. The two type constructors differ by one
bracket pair because a vector &lt;strong&gt;is&lt;/strong&gt; an array that computes lane-wise, and the spelling says so:
&lt;code&gt;[4]f32&lt;/code&gt; is storage, &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; is a register.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You never have to ask whether a machine can run this.&lt;/strong&gt; A vector wider than the hardware becomes
several registers, and one on a machine with no vector unit at all becomes ordinary scalar
operations — so &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; compiles for a Cortex-M0 exactly as it compiles for an Apple M-series, and
the only thing that changes is how fast it goes. The question a program asks is how &lt;em&gt;wide&lt;/em&gt; to go
where it cares about speed, never whether it may write one.&lt;/p&gt;
&lt;h2 id=&quot;writing-one-down&quot;&gt;Writing one down&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A literal&lt;/strong&gt; fills the lanes, and it has to fill all of them: the lane count is part of the type, so
there is no equivalent of a slice dropping its length.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], v[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], v.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 4 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A scalar broadcasts&lt;/strong&gt; — the &lt;em&gt;splat&lt;/em&gt;, and the commonest thing any vector code does. Write the scalar
and it goes into every lane, at a binding, at an operator, at a return, anywhere a vector is wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; zero: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; ones: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = v * &lt;span class=&quot;hl-number&quot;&gt;0.5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(zero[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], ones[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(ones)[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 1 0.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A declaration with no initializer&lt;/strong&gt; starts every lane at the lane type’s zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lane is read by a constant index.&lt;/strong&gt; This is the one subscript in sysl that is not checked while
the program runs, and the reason is that there is nothing to check against: a vector has no address,
and an out-of-range lane read has no defined answer at the machine level rather than trapping. So the
index has to be a literal or a &lt;code&gt;const&lt;/code&gt;, and it is checked where it is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&amp;lt;4&amp;gt;f32 has lanes 0 to 3, and this is 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need a computed index, you want the values in an array — whose checked subscript already
answers.&lt;/p&gt;
&lt;h2 id=&quot;what-the-operators-do&quot;&gt;What the operators do&lt;/h2&gt;
&lt;p&gt;A vector has exactly the operators its &lt;strong&gt;lane&lt;/strong&gt; has, applied to every lane. Both sides must be the
same vector, or one side a scalar that broadcasts:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;lanes&lt;/th&gt;&lt;th&gt;operators&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;an integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; &lt;code&gt;^&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;, and unary &lt;code&gt;-&lt;/code&gt; &lt;code&gt;~&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a float&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;/&lt;/code&gt;, and unary &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bool&lt;/code&gt; (a mask)&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;|&lt;/code&gt; &lt;code&gt;^&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Integer &lt;code&gt;/&lt;/code&gt; and &lt;code&gt;%&lt;/code&gt; are refused&lt;/strong&gt;, and it is worth knowing why rather than reading it as an
omission. Scalar integer division traps on a zero divisor and on the one signed overflow; a register
traps as a whole or not at all, so a vector would either drop the check or trap for lanes that were
perfectly fine. No processor sysl targets has an integer vector divide anyway, so the loop you write
instead is what the hardware was going to do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b = a / a&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;/&apos; is not defined on &amp;lt;4&amp;gt;int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no promotion, exactly as there is none between scalars. Two different widths, or two
different lane types, are two different types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got &amp;lt;4&amp;gt;f32 and &amp;lt;8&amp;gt;f32
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;masks-and-the-lane-wise-if&quot;&gt;Masks, and the lane-wise &lt;code&gt;if&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A comparison between vectors yields a &lt;strong&gt;mask&lt;/strong&gt; — a &lt;code&gt;&amp;lt;N&amp;gt;bool&lt;/code&gt;. It is an ordinary value: bind it, combine
it, reduce it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; small = a &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(small.&lt;span class=&quot;hl-function&quot;&gt;any&lt;/span&gt;(), small.&lt;span class=&quot;hl-function&quot;&gt;all&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;select&lt;/code&gt; is how a mask chooses&lt;/strong&gt;, and it is a method rather than a keyword because it cannot be
&lt;code&gt;if&lt;/code&gt;. An &lt;code&gt;if&lt;/code&gt; branches — it evaluates one side or the other — and a register has no way to take one
branch in two lanes and the other in the remaining two. So both sides are computed and the mask picks
between the results, lane by lane:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; lo = (a &amp;lt; b).&lt;span class=&quot;hl-function&quot;&gt;select&lt;/span&gt;(a, b)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; clamped = (a &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;select&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, a)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(lo[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], lo[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], clamped[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], clamped[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 4 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Either side of a &lt;code&gt;select&lt;/code&gt; may be a scalar, which broadcasts — &lt;code&gt;(v &amp;gt; hi).select(hi, v)&lt;/code&gt; is what
clamping looks like and needs no construction written around the bound.&lt;/p&gt;
&lt;p&gt;Two masks combine with the bitwise operators, and &lt;strong&gt;not&lt;/strong&gt; with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;. That is not an oversight: &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;
short-circuits, and there is no such thing as short-circuiting per lane.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; inside = (a &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &amp;amp; (a &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(inside.&lt;span class=&quot;hl-function&quot;&gt;any&lt;/span&gt;(), inside.&lt;span class=&quot;hl-function&quot;&gt;all&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For the same reason &lt;strong&gt;a comparison chain has no lane-wise form&lt;/strong&gt;. &lt;code&gt;1 &amp;lt; a &amp;lt; 4&lt;/code&gt; joins its two links with
&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, so it is refused rather than quietly turned into an &lt;code&gt;&amp;amp;&lt;/code&gt; that would look like the scalar spelling
and mean something different:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; m = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &amp;lt; a &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;compare two vectors at a time and combine the masks with &apos;&amp;amp;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reductions&quot;&gt;Reductions&lt;/h2&gt;
&lt;p&gt;A reduction collapses a vector to one scalar. &lt;code&gt;sum&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; are a numeric vector’s; &lt;code&gt;any&lt;/code&gt; and
&lt;code&gt;all&lt;/code&gt; are a mask’s.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;dot&lt;/span&gt;(a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, b: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = (a * b).&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; w: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(), v.&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(), v.&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;dot&lt;/span&gt;(v, w))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9.5 1 4 23
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A float sum is computed as a &lt;strong&gt;tree&lt;/strong&gt; rather than left to right, which is what makes it worth an
instruction instead of a loop — so it may differ in the last bit from adding the lanes yourself in
order. An integer sum wraps at the lane width, exactly as scalar integer arithmetic does.&lt;/p&gt;
&lt;h2 id=&quot;reaching-memory&quot;&gt;Reaching memory&lt;/h2&gt;
&lt;p&gt;A vector holds the lanes a kernel computes with; an &lt;a href=&quot;/reference/arrays/&quot;&gt;array or a slice&lt;/a&gt; holds the
data a program has. Two methods move a run between them, and they belong to the array or the slice
rather than to the vector — what the move needs is an address and a length, and a vector has neither.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, v * &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], v[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], out[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], out[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 6 30 60
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;xs.load(i)&lt;/code&gt; reads the run of lanes starting at element &lt;code&gt;i&lt;/code&gt;; &lt;code&gt;out.store(i, v)&lt;/code&gt; writes one back. The
store needs a slice or an array it may write, so a &lt;code&gt;[]const T&lt;/code&gt; is refused exactly as &lt;code&gt;xs[i] = v&lt;/code&gt;
would be.&lt;/p&gt;
&lt;p&gt;These are two ordinary words, so &lt;strong&gt;a &lt;code&gt;load&lt;/code&gt; or &lt;code&gt;store&lt;/code&gt; you have declared yourself wins&lt;/strong&gt;: an &lt;code&gt;impl&lt;/code&gt;
block for a slice answers before the compiler’s does, and only a receiver with no member of that
name reaches these. &lt;code&gt;sysl.sync.Atomic&lt;/code&gt; has had a &lt;code&gt;load&lt;/code&gt; and a &lt;code&gt;store&lt;/code&gt; of its own since long before
vectors existed, and they still mean what they meant.&lt;/p&gt;
&lt;h3 id=&quot;where-the-width-comes-from&quot;&gt;Where the width comes from&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A load takes its width from whatever receives the value.&lt;/strong&gt; A slice has whatever length it has, so
it cannot say — and guessing would be the one mistake that silently takes the wrong run. A binding’s
annotation says it, and so do a parameter and a declared result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;grab&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; annotated: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; declared: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;grab&lt;/span&gt;(xs[..])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(annotated[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)), declared[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 2 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An operand of an operator is such a place too&lt;/strong&gt;, so a load standing beside a vector reads its lane
count off it. There are three tiers, which is &lt;code&gt;01&lt;/code&gt;‘s literal rule with one more step: an operand
carrying a type of its own is read first, a load is read at what that one said, and a bare literal is
read last at whatever the two of them settled.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; by: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) * by + &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(out[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], out[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11 41
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What is not such a place is one where any width would do.&lt;/strong&gt; A store takes whatever it is handed, so
every width type-checks and there is genuinely nothing to infer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, out: []&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;)
    out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;how many lanes it takes is the vector type&apos;s to say
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Say it on a binding there, which is one line and reads better in a kernel anyway.&lt;/p&gt;
&lt;h3 id=&quot;what-the-run-promises&quot;&gt;What the run promises&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;It is bounds-checked, and checked as a whole run.&lt;/strong&gt; &lt;code&gt;xs.load(3)&lt;/code&gt; on a five-element array traps
even though element 3 exists, because elements 3 through 6 do not. This is the only vector operation
with a run-time test: everything else is a register operation that cannot fail, and a vector is not
a hole through which a program reaches past the end of an array.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A partial run at the end traps too, and the scalar tail is yours to write.&lt;/strong&gt; An array whose length
is not a multiple of the width ends with fewer elements left than there are lanes; the kernel below
is what that looks like.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The alignment claimed is the element’s.&lt;/strong&gt; A &lt;code&gt;[]f32&lt;/code&gt; promises four bytes and says nothing about
where a run begins, so a vector’s own alignment would be a claim the type does not support. Every
machine sysl targets has an unaligned vector load costing what the aligned one costs on aligned
data, so the honest number is also the free one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt; elements are refused rather than quietly widened.&lt;/strong&gt; One access per element is not one
access, and a single instruction cannot promise per-lane ordering. &lt;code&gt;volatile &amp;lt;4&amp;gt;u32&lt;/code&gt; is the spelling
that means something, and it qualifies the whole register.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(regs: []volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = regs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

    v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the qualifier cannot be kept
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;*T&lt;/code&gt; is refused for a different reason: it carries no length, so there is nothing to check the run
against. Take a slice of the elements first.&lt;/p&gt;
&lt;h2 id=&quot;one-kernel-every-width&quot;&gt;One kernel, every width&lt;/h2&gt;
&lt;p&gt;This is what the feature is for, and it needs nothing of its own: a lane count is a
&lt;a href=&quot;/reference/generics/&quot;&gt;value parameter&lt;/a&gt;, so it binds from the argument the way an array’s length does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](v: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, by: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = v * by

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; four: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; eight: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(four, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(eight, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], b[&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;], a.len, b.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 24 4 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neither call writes a width. One body is compiled twice, and the two hold different instructions —
four lanes wide and eight. The mask inside a generic kernel follows the same width, so a comparison
in there is a &lt;code&gt;&amp;lt;W&amp;gt;bool&lt;/code&gt; and the &lt;code&gt;select&lt;/code&gt; chooses at whatever W turned out to be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;clamp_low&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](v: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, lo: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = (v &amp;lt; lo).&lt;span class=&quot;hl-function&quot;&gt;select&lt;/span&gt;(lo, v)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; four: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; two: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp_low&lt;/span&gt;(four, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], &lt;span class=&quot;hl-function&quot;&gt;clamp_low&lt;/span&gt;(two, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For comparison, the C answer to the same problem is to write the kernel once per instruction set
behind &lt;code&gt;#ifdef&lt;/code&gt; — Box2D’s contact solver carries four copies of itself, and more than half of that
file is those copies.&lt;/p&gt;
&lt;h3 id=&quot;a-kernel-over-an-array&quot;&gt;A kernel over an array&lt;/h3&gt;
&lt;p&gt;Put the two halves together and the loop a real kernel runs is one body too — the loads, the
arithmetic and the store all take their width from &lt;code&gt;W&lt;/code&gt;, and the scalar tail picks up whatever the
last run could not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, out: []&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, by: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i + &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt; &amp;lt;= xs.len
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = xs.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)

        out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(i, v * by)
        i += &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; xs.len
        out[i] = xs[i] * by[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; src: [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; four: [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; eight: [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; by4: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; by8: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(src[..], four[..], by4)
&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(src[..], eight[..], by8)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(four[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], four[&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;], eight[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], eight[&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 30 3 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ten elements is not a multiple of either width, so both instantiations take the tail — and the two
answers agree, which is what says one body serves both registers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;by&lt;/code&gt; is a vector rather than an &lt;code&gt;f32&lt;/code&gt;, and that is where &lt;code&gt;W&lt;/code&gt; enters.&lt;/strong&gt; A written type argument at a
call is refused, so a kernel whose every parameter is a slice has no way to be told its width. This
is rarely felt, because a SIMD kernel’s constants are broadcast across the lanes anyway — but it is
worth knowing before a signature is designed around it.&lt;/p&gt;
&lt;h2 id=&quot;what-a-vector-does-not-have-yet&quot;&gt;What a vector does not have yet&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Shuffles and swizzles.&lt;/strong&gt; There is no way to rearrange lanes in one step. A gather is a loop that
writes the elements into a scratch array and one &lt;code&gt;load&lt;/code&gt; to pick the whole run up — correct
everywhere, and still not the single instruction a shuffle would be. This is the reason the section
above is a stronger claim about arithmetic than about loading: a gather is what changes between
hand-written SIMD variants, and it is the half that does not generalise over a width.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A masked load or store.&lt;/strong&gt; A run that would reach past the end traps rather than reading the lanes
that exist and leaving the rest alone. Write the scalar tail, which is what the kernel above does
and what C’s SIMD code does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A place in a C signature.&lt;/strong&gt; A vector may not cross to a C function in either direction. Which
register it would arrive in differs by target and by which instruction-set extensions the other side
was compiled with, and guessing would produce a call that links and corrupts its arguments rather than
one that fails to link. Pass the lanes through memory — a &lt;code&gt;*f32&lt;/code&gt; and a count, which is what C’s own
SIMD-taking functions take:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;process_lanes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;process&lt;/span&gt;(v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;how a vector reaches a C function differs by target
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;lanes&quot;&gt;Lanes&lt;/h2&gt;
&lt;p&gt;A lane is a scalar: an integer, a float, &lt;code&gt;bool&lt;/code&gt; or &lt;code&gt;char&lt;/code&gt;. An aggregate cannot be one — there is no
such thing as a vector of structs — and neither can a &lt;code&gt;volatile&lt;/code&gt; type, since per-lane access ordering
is not something a single load can give. &lt;code&gt;volatile &amp;lt;4&amp;gt;u32&lt;/code&gt; is the spelling that means something, and
it qualifies the whole register.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a vector&apos;s lanes are scalars
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;constrained&lt;/strong&gt; lane is fine, and computes at its base exactly as a scalar of that subtype does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; w = v + v

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], w[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 8
&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <title>Values and bindings</title>
    <link href="https://sysl.sh/tour/values/"/>
    <id>https://sysl.sh/tour/values/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Three ways to name a value, a scalar family with no surprises in it, and why nothing widens on its own.</summary>
    <content type="html">&lt;h2 id=&quot;naming-a-value&quot;&gt;Naming a value&lt;/h2&gt;
&lt;p&gt;Three keywords, differing in what may happen to the thing afterwards:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;            &lt;span class=&quot;hl-comment&quot;&gt;// storage that may change&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;      &lt;span class=&quot;hl-comment&quot;&gt;// storage that may not&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; step: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;      &lt;span class=&quot;hl-comment&quot;&gt;// not storage at all — a value known while compiling&lt;/span&gt;

count = count + step
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, count, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, limit)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;count: 5 of 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;var&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt; are the pair most languages have. &lt;code&gt;const&lt;/code&gt; is the different one: it is not a variable
that happens to be fixed, it is a value the compiler substitutes wherever the name appears, so there
is nothing at run time to read. That is why it insists on its type being written and on having a
value — a &lt;code&gt;const&lt;/code&gt; with either missing is refused rather than inferred, because a name with no
storage and no value is nothing at all.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;limit&lt;/code&gt; writes its type for a reason worth knowing early, because it is the first place the file’s
top level behaves differently from the inside of a function. These statements are at &lt;strong&gt;module
level&lt;/strong&gt;, and a module-level &lt;code&gt;val&lt;/code&gt; is part of the module’s surface — something another file can see —
so its type is stated rather than inferred from whatever happens to be on the right today. The same
&lt;code&gt;val limit = 10&lt;/code&gt; inside a function infers happily, because a local is nobody else’s business.&lt;/p&gt;
&lt;p&gt;A module-level &lt;code&gt;val&lt;/code&gt; &lt;strong&gt;may&lt;/strong&gt; hold a value the program had to build — a reference, a slice, a string
put together while running. Storage that exists for the whole run is never let go of, so the count it
takes is never given back, which is what a static is. What the value is decides only &lt;em&gt;when&lt;/em&gt; the
storage gets filled: numbers, characters, booleans, string literals and tables of them are complete
before the program starts, and anything else is built by a prologue that runs before the first
statement.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;print&lt;/code&gt; takes any number of arguments, renders each one, and puts a space between them. It comes from
&lt;code&gt;sysl&lt;/code&gt;, the standard module — the one module a file may name without importing it.&lt;/p&gt;
&lt;h2 id=&quot;the-scalar-types&quot;&gt;The scalar types&lt;/h2&gt;
&lt;p&gt;Integers are an open family: &lt;code&gt;i8&lt;/code&gt;, &lt;code&gt;i16&lt;/code&gt;, &lt;code&gt;i32&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt; and the unsigned &lt;code&gt;u8&lt;/code&gt; … &lt;code&gt;u64&lt;/code&gt;, with &lt;code&gt;isize&lt;/code&gt;
and &lt;code&gt;usize&lt;/code&gt; for the pointer-width pair. The common ones also have friendly names, and those are what
ordinary code uses:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;friendly&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;i32&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u8&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;short&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;i16&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;uint&lt;/code&gt;, &lt;code&gt;ushort&lt;/code&gt;, &lt;code&gt;ulong&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u32&lt;/code&gt;, &lt;code&gt;u16&lt;/code&gt;, &lt;code&gt;u64&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;real&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;f64&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Floats are a closed set — &lt;code&gt;f32&lt;/code&gt; and &lt;code&gt;f64&lt;/code&gt; — because IEEE 754 defines those and not an open family.
&lt;code&gt;real&lt;/code&gt; is &lt;code&gt;f64&lt;/code&gt;, and it is the width arithmetic reaches for unless a program says otherwise.&lt;/p&gt;
&lt;p&gt;Then &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, and &lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;every-width-is-its-own-type&quot;&gt;Every width is its own type&lt;/h2&gt;
&lt;p&gt;This is the part that catches people arriving from C. A width is a &lt;em&gt;type&lt;/em&gt;, not a hint, and no value
changes width on its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide: &lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;18446744073709551615&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;byte:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, small + &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;, small &amp;gt;&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;u64 max:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, wide)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;byte: 44 25
u64 max: 18446744073709551615
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;small + 100&lt;/code&gt; is &lt;code&gt;byte&lt;/code&gt; arithmetic, so it wraps at 256 and gives 44. It does not quietly become an
&lt;code&gt;int&lt;/code&gt; because the answer would not fit — the type said &lt;code&gt;byte&lt;/code&gt;, and &lt;code&gt;byte&lt;/code&gt; is what the arithmetic
is. An unsuffixed literal like &lt;code&gt;100&lt;/code&gt; takes the type of what is around it, which is what lets that
line be written without a suffix on every number.&lt;/p&gt;
&lt;h3 id=&quot;the-family-is-open-and-that-is-not-a-figure-of-speech&quot;&gt;The family is open, and that is not a figure of speech&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;i8&lt;/code&gt; through &lt;code&gt;i64&lt;/code&gt; are the widths with familiar names, not the widths that exist. &lt;code&gt;iN&lt;/code&gt; and &lt;code&gt;uN&lt;/code&gt; are an
&lt;strong&gt;open family parameterized by a bit width&lt;/strong&gt;, so &lt;code&gt;u12&lt;/code&gt;, &lt;code&gt;i5&lt;/code&gt; and &lt;code&gt;u256&lt;/code&gt; are types you may write, and
each is its own type with its own arithmetic — a &lt;code&gt;u12&lt;/code&gt; wraps at 4096 because that is what twelve bits
hold:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pixel&lt;/span&gt;
    red:   u5
    green: u6
    blue:  u5
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pixel&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Pixel&lt;/span&gt;(31u5, 40u6, 17u5)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter: u12 = &lt;span class=&quot;hl-number&quot;&gt;4000&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;wraps at 4096:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, counter + 100u12)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;and divides:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, counter / 7u12)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;packed:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(p.red), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(p.green), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(p.blue))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;wraps at 4096: 4
and divides: 571
packed: 31 40 17
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the reason the rule above is worth stating as “a width is a type” rather than “there are eight
integer types”. A 16-bit colour pixel really is a 5-bit field, a 6-bit field and another 5-bit field,
and writing it that way gets the wrapping and the range checking for free instead of hand-masking
them out of a &lt;code&gt;u16&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Storage rounds up to whole bytes and an alignment the machine has — a &lt;code&gt;u12&lt;/code&gt; occupies two bytes — so a
narrow width buys correct arithmetic rather than tight packing. The
&lt;a href=&quot;/reference/types/&quot;&gt;reference&lt;/a&gt; has the ceiling and the two costs at extreme widths.&lt;/p&gt;
&lt;p&gt;Ask for a wider type and the compiler will not do it silently:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = small
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(wide)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;cannot initialize &apos;wide&apos;: declared int but the value is byte
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fix is to say so, and every conversion is written with call syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;widened:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(small))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;truncated:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.9&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;divided:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;) / &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;code point:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;A&apos;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;widened: 200
truncated: 3
divided: 3.5
code point: 65
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;int(3.9)&lt;/code&gt; truncates rather than rounds, and &lt;code&gt;f32(7) / f32(2)&lt;/code&gt; is float division because both
operands are floats — writing &lt;code&gt;7 / 2&lt;/code&gt; would have been integer division giving 3. Which one you get
follows from the types, and the types are written down.&lt;/p&gt;
&lt;h2 id=&quot;characters-are-not-small-integers&quot;&gt;Characters are not small integers&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;char&lt;/code&gt; is one Unicode scalar value. It compares and prints, and it does not do arithmetic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; letter = &lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;char:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, letter, &lt;span class=&quot;hl-string&quot;&gt;&apos;a&apos;&lt;/span&gt; &amp;lt;= letter, &lt;span class=&quot;hl-type&quot;&gt;char&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9731&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;char: é true ☃
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ordering is defined, so &lt;code&gt;&apos;a&apos; &amp;lt;= letter&lt;/code&gt; answers. Adding &lt;code&gt;1&lt;/code&gt; to it is not, because “the next scalar
value” is rarely what a program that wrote &lt;code&gt;letter + 1&lt;/code&gt; actually meant. When the code point &lt;em&gt;is&lt;/em&gt;
what you want, &lt;code&gt;u32(letter)&lt;/code&gt; says so and &lt;code&gt;char(9731)&lt;/code&gt; goes back the other way.&lt;/p&gt;
&lt;h2 id=&quot;assignment-is-an-expression&quot;&gt;Assignment is an expression&lt;/h2&gt;
&lt;p&gt;It yields the value assigned, which is what lets a chain work and a condition read normally:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

a = b = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;both:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;both: 7 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A binding takes a comma list too, so two names can be introduced, or swapped, in one line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; lo, hi = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x, y = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

    x, y = y, x
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;range:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, lo, hi, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;swapped:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, x, y)

&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;range: 1 10 swapped: 4 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The right-hand side is evaluated before anything is stored, so &lt;code&gt;x, y = y, x&lt;/code&gt; is a swap and needs no
temporary.&lt;/p&gt;
&lt;p&gt;This one is inside a function rather than at the top level, and it has to be. A binding that names
several things has nowhere to write a type, and a module-level binding is required to have one — so
the comma form is a local’s convenience, and the compiler says exactly that if you try it at module
level.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/control-flow/&quot;&gt;control flow&lt;/a&gt;, where the same “it yields a value” idea turns out to
cover &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;match&lt;/code&gt; and the loops as well.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Types</title>
    <link href="https://sysl.sh/reference/types/"/>
    <id>https://sysl.sh/reference/types/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Every type the language has — the open integer families, the closed float set, and the aggregates built on them.</summary>
    <content type="html">&lt;p&gt;sysl’s types fall into four groups: &lt;strong&gt;scalars&lt;/strong&gt; (numbers, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;), the built-in &lt;strong&gt;&lt;code&gt;string&lt;/code&gt;&lt;/strong&gt;,
the &lt;strong&gt;aggregates&lt;/strong&gt; you build (arrays, slices, structs, enums), and the &lt;strong&gt;modes&lt;/strong&gt; that decide where a
value lives (&lt;code&gt;T&lt;/code&gt;, &lt;code&gt;&amp;amp;T&lt;/code&gt;, &lt;code&gt;*T&lt;/code&gt;). This page covers the first three. The modes have a
&lt;a href=&quot;/reference/memory/&quot;&gt;page of their own&lt;/a&gt;, because they are about storage rather than shape.&lt;/p&gt;
&lt;p&gt;There is no implicit conversion anywhere in the language. Every width change, signedness change, and
float/integer crossing is written as a cast, and a cast that could lose information is written and
seen.&lt;/p&gt;
&lt;h2 id=&quot;integers-are-an-open-family&quot;&gt;Integers are an open family&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;iN&lt;/code&gt; and &lt;code&gt;uN&lt;/code&gt; are not a fixed set of four sizes. They are an &lt;strong&gt;open family parameterized by an
arbitrary bit width&lt;/strong&gt;: &lt;code&gt;i5&lt;/code&gt;, &lt;code&gt;u3&lt;/code&gt;, &lt;code&gt;u12&lt;/code&gt;, &lt;code&gt;i128&lt;/code&gt; are all types you may write, and none of them needed
the compiler to have heard of them. LLVM supports integers of any width natively, so this is a
capability of the target rather than something sysl emulates.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: u3 = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; odd: i5 = -&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide: u12 = &lt;span class=&quot;hl-number&quot;&gt;4000&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(small, odd, wide)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 -7 4000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That openness is the reason the &lt;code&gt;iN&lt;/code&gt; spelling exists at all. If the integers were only four sizes,
carrying both &lt;code&gt;iN&lt;/code&gt; names &lt;em&gt;and&lt;/em&gt; C-style names would be two spellings for every type and no benefit.
Instead there are two layers, each earning its place: &lt;code&gt;iN&lt;/code&gt;/&lt;code&gt;uN&lt;/code&gt; is the general mechanism, and a short
list of &lt;strong&gt;aliases&lt;/strong&gt; covers the common widths.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;alias&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;alias&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;byte&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;short&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;i16&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ushort&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u16&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;i32&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;uint&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;i64&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ulong&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;u64&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;real&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;f64&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;C’s “how wide is &lt;code&gt;long&lt;/code&gt;?” problem — the usual reason to distrust names like these — &lt;strong&gt;does not apply&lt;/strong&gt;,
because each width is pinned &lt;em&gt;by definition&lt;/em&gt;. &lt;code&gt;long&lt;/code&gt; is exactly &lt;code&gt;i64&lt;/code&gt;, on every target, always.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But that is an anti-ambiguity guarantee, not an ABI promise&lt;/strong&gt;, and the difference matters at a
foreign boundary. On a 64-bit host every alias happens to match its C namesake, which is what makes
them safe in &lt;code&gt;extern&lt;/code&gt; code there. On a 32-bit target C’s &lt;code&gt;long&lt;/code&gt; is 32 bits while sysl’s is still
exactly 64 — so &lt;strong&gt;precise FFI should use the explicit-width names&lt;/strong&gt;, which match C’s &lt;code&gt;int32_t&lt;/code&gt; and
&lt;code&gt;int64_t&lt;/code&gt; on every target. Note also that &lt;code&gt;i8&lt;/code&gt; has no alias: there is no settled C-style name for a
signed byte worth adopting.&lt;/p&gt;
&lt;h3 id=&quot;arithmetic-wraps&quot;&gt;Arithmetic wraps&lt;/h3&gt;
&lt;p&gt;Integer arithmetic wraps at the &lt;strong&gt;declared&lt;/strong&gt; width, and this is defined behaviour rather than a
checked error. &lt;code&gt;i5&lt;/code&gt; wraps mod 2⁵ exactly as &lt;code&gt;i32&lt;/code&gt; wraps mod 2³².&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;250&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(small + &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Overflow is therefore &lt;strong&gt;not&lt;/strong&gt; a trap source. See &lt;a href=&quot;/reference/errors/&quot;&gt;errors and traps&lt;/a&gt; for what is.&lt;/p&gt;
&lt;h3 id=&quot;storage-is-not-n-8&quot;&gt;Storage is not &lt;code&gt;N / 8&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;An integer’s alignment rounds up to the smallest width the target names, and its stride rounds up to
that alignment. A &lt;code&gt;u12&lt;/code&gt; occupies &lt;strong&gt;two&lt;/strong&gt; bytes aligned to two; a &lt;code&gt;u96&lt;/code&gt; occupies sixteen aligned to
sixteen. This is LLVM’s rule, and it matters anywhere a width is stated rather than derived.&lt;/p&gt;
&lt;h3 id=&quot;where-the-width-stops&quot;&gt;Where the width stops&lt;/h3&gt;
&lt;p&gt;Up to 64 bits everything is a machine instruction. Past that the arithmetic is still native — the
back end expands a wide multiply or divide inline, with no runtime routine behind it — and decimal
rendering becomes the language’s own job, since C’s &lt;code&gt;printf&lt;/code&gt; has no length modifier that wide. So a
value past 64 bits renders through a digit loop and is refused a &lt;code&gt;%d&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The ceiling is LLVM’s own &lt;strong&gt;2²³ − 1&lt;/strong&gt;, and a wider width is a diagnostic naming it. That is a
statement about the toolchain, not about the design.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide: u256 = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt;
    wide = wide * 2u256
    i = i + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(wide)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1606938044258990275541962092341162602522202993782792835301376
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two costs are worth knowing before reaching for an extreme width, because neither is guarded against:
the digit buffer is stack space proportional to the width, so a width near the ceiling overflows the
frame, and sizing it evaluates 2^N at compile time. Nothing reaches either without asking for it by
name.&lt;/p&gt;
&lt;h3 id=&quot;the-narrowest-widths&quot;&gt;The narrowest widths&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;N ≥ 1&lt;/code&gt; has no exception at its low end. &lt;code&gt;u1&lt;/code&gt; is a single binary digit. &lt;code&gt;i1&lt;/code&gt; holds &lt;code&gt;{-1, 0}&lt;/code&gt; — one bit
of two’s complement, where the only bit &lt;em&gt;is&lt;/em&gt; the sign bit. It is degenerate but entirely consistent,
and nothing special-cases it: &lt;code&gt;abs&lt;/code&gt; at &lt;code&gt;i1&lt;/code&gt; answers &lt;code&gt;-1&lt;/code&gt; because &lt;code&gt;-1&lt;/code&gt; is that width’s most negative
value, exactly as &lt;code&gt;abs&lt;/code&gt; at any width answers its own minimum, and &lt;code&gt;signum&lt;/code&gt; never returns &lt;code&gt;+1&lt;/code&gt; because
no value of the type is positive. If you want a bit, write &lt;code&gt;u1&lt;/code&gt; or &lt;code&gt;bool&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;floating-point-is-a-closed-set&quot;&gt;Floating point is a closed set&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;fN&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; open — only the IEEE widths exist, because there is no meaningful &lt;code&gt;f37&lt;/code&gt;. &lt;code&gt;f32&lt;/code&gt; and
&lt;code&gt;f64&lt;/code&gt; are the two the back end supports today.&lt;/p&gt;
&lt;p&gt;Only the default width gets an alias, and it is deliberately named &lt;code&gt;real&lt;/code&gt; rather than &lt;code&gt;float&lt;/code&gt;, because
&lt;code&gt;float&lt;/code&gt; means 32-bit to every C, C++, Rust and Java programmer and &lt;code&gt;real&lt;/code&gt; promises nothing it does not
keep.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2.25&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a + &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, b / &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2.5 1.125
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A float renders in the shortest form that round-trips, so a value with no fractional part prints
without one.&lt;/p&gt;
&lt;h2 id=&quot;usize-and-isize&quot;&gt;&lt;code&gt;usize&lt;/code&gt; and &lt;code&gt;isize&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Pointer-width integers, and they are &lt;strong&gt;distinct types&lt;/strong&gt; from every &lt;code&gt;uN&lt;/code&gt; — not aliases for &lt;code&gt;u64&lt;/code&gt;. That
is required by the target scope: aliasing &lt;code&gt;usize&lt;/code&gt; to &lt;code&gt;u64&lt;/code&gt; would be correct only if every target were
64-bit, and a 32-bit embedded target is squarely in scope.&lt;/p&gt;
&lt;p&gt;A length, an index, and &lt;code&gt;sizeof&lt;/code&gt; are all &lt;code&gt;usize&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = xs.len

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n, xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 20
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;bool&quot;&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;, and nothing coerces to it. &lt;code&gt;if x = 0&lt;/code&gt; is a &lt;strong&gt;type error&lt;/strong&gt; rather than a subtle
bug, because &lt;code&gt;if&lt;/code&gt; requires a &lt;code&gt;bool&lt;/code&gt; and an assignment yields what was assigned. There is no
integer-as-condition rule to memorize.&lt;/p&gt;
&lt;h2 id=&quot;char&quot;&gt;&lt;code&gt;char&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;One &lt;strong&gt;Unicode scalar value&lt;/strong&gt; — a codepoint up to &lt;code&gt;0x10FFFF&lt;/code&gt;, excluding the surrogate range. It is its
own type, aliased to neither &lt;code&gt;u8&lt;/code&gt; nor &lt;code&gt;u32&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Keeping it distinct is what lets “a character” and “a byte” stay different ideas, which a language
with a UTF-8 &lt;code&gt;string&lt;/code&gt; has to do. Conversion to &lt;code&gt;u32&lt;/code&gt; is total and written &lt;code&gt;u32(c)&lt;/code&gt;; conversion &lt;em&gt;from&lt;/em&gt;
&lt;code&gt;u32&lt;/code&gt; is partial, and has both a checked form that traps and a fallible form that returns an &lt;code&gt;Option&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;unit-and-never&quot;&gt;&lt;code&gt;unit&lt;/code&gt; and &lt;code&gt;never&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;unit&lt;/code&gt; is the type with exactly one value — what a function that returns nothing returns. It is a real
type, so it composes: a &lt;code&gt;Fn() -&amp;gt; unit&lt;/code&gt; needs no special case in the callable machinery.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;never&lt;/code&gt; is the type with &lt;strong&gt;no&lt;/strong&gt; values, and it is what an expression that does not finish has. A call
to &lt;code&gt;exit&lt;/code&gt; has type &lt;code&gt;never&lt;/code&gt;, as does a &lt;code&gt;return&lt;/code&gt; or a &lt;code&gt;break&lt;/code&gt; considered as an expression. Because there
are no values of it, &lt;code&gt;never&lt;/code&gt; is a subtype of everything — which is what lets a &lt;code&gt;match&lt;/code&gt; arm that aborts
sit beside arms that produce an &lt;code&gt;int&lt;/code&gt; without the arms disagreeing.&lt;/p&gt;
&lt;h2 id=&quot;string&quot;&gt;&lt;code&gt;string&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A validated UTF-8 string, three words wide. It is immutable, indexing it by byte position gives
bytes, iterating it gives &lt;code&gt;char&lt;/code&gt;s, and &lt;code&gt;+&lt;/code&gt; concatenates but will not accept a non-string operand.
&lt;a href=&quot;/reference/strings/&quot;&gt;Strings&lt;/a&gt; is the full account — the representation, the validity guarantee, and
every form that makes new bytes — and the operations that live in the library are under
&lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fixed-arrays-and-slices&quot;&gt;Fixed arrays and slices&lt;/h2&gt;
&lt;p&gt;Two sequence types where many languages have one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[N]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;fixed array&lt;/strong&gt;: &lt;code&gt;N&lt;/code&gt; elements, a value, no header, length known while compiling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;slice&lt;/strong&gt;: a view of elements someone else owns — &lt;code&gt;{ owner, pointer, length }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]const T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a slice that may be read and not written&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;An array &lt;strong&gt;is&lt;/strong&gt; its elements, so copying one copies all of them and passing one by value passes the
whole thing. A slice &lt;strong&gt;names&lt;/strong&gt; elements that live somewhere else, and copying a slice copies the
three-word header rather than the data.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a

b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a[..]
v[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;88&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], a[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 88 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The disagreement in that program is the whole distinction: writing through &lt;code&gt;b&lt;/code&gt; did not touch &lt;code&gt;a&lt;/code&gt;
because &lt;code&gt;b&lt;/code&gt; is a copy, and writing through &lt;code&gt;v&lt;/code&gt; did because &lt;code&gt;v&lt;/code&gt; is a view.&lt;/p&gt;
&lt;p&gt;Both carry a length, so &lt;strong&gt;every index is checked&lt;/strong&gt;. &lt;a href=&quot;/reference/arrays/&quot;&gt;Arrays and slices&lt;/a&gt; is the
full account — writing one down, storage sized while running, the indexing and slicing rules, and
what a view keeps alive.&lt;/p&gt;
&lt;h2 id=&quot;vectors&quot;&gt;Vectors&lt;/h2&gt;
&lt;p&gt;A fourth sequence shape, and the one that is not storage at all.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;lt;N&amp;gt;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;vector&lt;/strong&gt;: N lanes of &lt;code&gt;T&lt;/code&gt; in a register, whose operators work on every lane at once&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It holds the same values an &lt;code&gt;[N]T&lt;/code&gt; holds, in the same order — the two type constructors differ by one
bracket pair because a vector &lt;em&gt;is&lt;/em&gt; an array that computes lane-wise:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((a + b)[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], (a * &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;)[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], (a * b).&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;44 2 300
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;+&lt;/code&gt; is one instruction doing four additions, and the &lt;code&gt;2.0&lt;/code&gt; broadcasts into every lane. A lane is
read by a &lt;strong&gt;constant&lt;/strong&gt; index, which is the one subscript in the language not checked while the program
runs — a register has no address to check against. A run of an array or a slice moves into a vector
and back with &lt;code&gt;xs.load(i)&lt;/code&gt; and &lt;code&gt;xs.store(i, v)&lt;/code&gt;, which &lt;em&gt;are&lt;/em&gt; checked, because those have addresses.&lt;/p&gt;
&lt;p&gt;A machine with no vector unit is not a special case: the back end turns a vector into as many
registers as it needs, or into ordinary scalar operations, so &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; compiles everywhere sysl
compiles. &lt;a href=&quot;/reference/vectors/&quot;&gt;Vectors&lt;/a&gt; is the full account — masks and &lt;code&gt;select&lt;/code&gt;, the reductions, and
writing one kernel that is compiled for more than one register width.&lt;/p&gt;
&lt;h2 id=&quot;structs&quot;&gt;Structs&lt;/h2&gt;
&lt;p&gt;A named product type. Fields are declared one per line, and a struct is a &lt;strong&gt;value&lt;/strong&gt; — assigning one
copies it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = p

q.x = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.x, q.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Structs may carry methods, an &lt;code&gt;invariant&lt;/code&gt;, and a visibility modifier per field. A struct may also be
declared &lt;code&gt;opaque&lt;/code&gt;, which withholds its layout from everyone outside its own module — a different axis
from visibility, covered under &lt;a href=&quot;/tour/modules/&quot;&gt;modules&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;enums&quot;&gt;Enums&lt;/h2&gt;
&lt;p&gt;Two shapes under one keyword. A &lt;strong&gt;simple&lt;/strong&gt; enum is a set of named discriminants with an underlying
integer type; a &lt;strong&gt;data&lt;/strong&gt; enum gives variants payloads, making it a sum type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r)  -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3.14159&lt;/span&gt; * r * r
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w, h) -&amp;gt; w * h

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 3.14159 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Option[T]&lt;/code&gt; and &lt;code&gt;Result[T, E]&lt;/code&gt; are ordinary data enums declared in the standard library, with no
compiler privileges — which is why you can write your own and have it work identically.&lt;/p&gt;
&lt;h3 id=&quot;a-variant-belongs-to-its-enum&quot;&gt;A variant belongs to its enum&lt;/h3&gt;
&lt;p&gt;Two enums in one module may each name a variant &lt;code&gt;Failed&lt;/code&gt;, and neither has to be renamed. &lt;strong&gt;What a
bare name means is settled where it is used, by the type expected there&lt;/strong&gt; — an argument, an annotated
binding, a &lt;code&gt;return&lt;/code&gt; and a field all supply one, so the short form is what you normally write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(side: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Hole&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Slot&lt;/span&gt;(len: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r)    -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; * r * r
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(side) -&amp;gt; side * side

&lt;span class=&quot;hl-function&quot;&gt;depth&lt;/span&gt;(h: &lt;span class=&quot;hl-type&quot;&gt;Hole&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = h &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; r
    &lt;span class=&quot;hl-function&quot;&gt;Slot&lt;/span&gt;(len) -&amp;gt; len

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s), &lt;span class=&quot;hl-function&quot;&gt;depth&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where two enums answer and nothing says which, that is a diagnostic rather than a quiet choice — a
construction that picked the first-declared enum would be a line whose meaning changed when somebody
added an unrelated enum above it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(side: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Hole&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Slot&lt;/span&gt;(len: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Circle&apos; is a variant of &apos;Shape&apos; and &apos;Hole&apos;, and nothing here says which — qualify it, as &apos;Shape.Circle&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Shape.Circle(1)&lt;/code&gt; is what that line wants. The qualified form works at a construction exactly as it
&lt;a href=&quot;/reference/patterns/#the-bare-name-rule&quot;&gt;works in a pattern&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is Rust’s arrangement — a variant is namespaced under its enum — without Rust’s use site, where
&lt;code&gt;Link::Failed&lt;/code&gt; is required everywhere unless a scope opts into &lt;code&gt;use Link::*&lt;/code&gt;. A variant still may not
share a name with a constant, a &lt;code&gt;val&lt;/code&gt;, a module &lt;code&gt;var&lt;/code&gt; or an &lt;code&gt;extern&lt;/code&gt; variable: two variants of a name
are told apart by the enum they belong to, and a variant and a constant have nothing to be told apart
&lt;em&gt;by&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;type-aliases&quot;&gt;Type aliases&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;type Name = Existing&lt;/code&gt; introduces a second spelling for a type, interchangeable with the first. It
creates &lt;strong&gt;no&lt;/strong&gt; new type and no checking: an alias is for shortening a name that has grown long, not
for distinguishing two uses of the same representation.&lt;/p&gt;
&lt;p&gt;When you want a genuinely distinct type — one the compiler will not let you confuse with its base —
that is a &lt;strong&gt;constrained type&lt;/strong&gt;, written with &lt;code&gt;new&lt;/code&gt;, and it is covered under
&lt;a href=&quot;/tour/contracts/&quot;&gt;contracts&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;function-types&quot;&gt;Function types&lt;/h2&gt;
&lt;p&gt;A callable’s type is written with &lt;code&gt;Fn&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Fn&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(n -&amp;gt; n * &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;21
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A named function used where a callable is expected is the capture-free case of the same thing — there
is no separate “function pointer” concept to learn. A raw C function pointer, for a foreign boundary,
is spelled &lt;code&gt;*extern(A) -&amp;gt; R&lt;/code&gt; and is covered under the &lt;a href=&quot;/reference/ffi/&quot;&gt;foreign interface&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;a-parameter-passed-by-name&quot;&gt;A parameter passed by name&lt;/h3&gt;
&lt;p&gt;A parameter written with the arrow and &lt;strong&gt;nothing on its left&lt;/strong&gt; takes an expression the call does not
evaluate, and the body evaluates at each use:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; built: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    built += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(on: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;, m: -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; on &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m)

&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(built)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;message()&lt;/code&gt; ran once, not twice: the first call never evaluated its argument. That is the form’s
whole purpose — an argument a callee may not want should cost nothing to offer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each use is an evaluation&lt;/strong&gt;, because each use is a call — so a body that names the parameter twice
runs the argument twice. A body wanting one evaluation binds it to a &lt;code&gt;val&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;It costs nothing at runtime. &lt;code&gt;x: -&amp;gt; T&lt;/code&gt; has the type &lt;code&gt;Fn() -&amp;gt; T&lt;/code&gt;, so it lowers to a bounded type
parameter exactly as the ordinary bare arrow does — one specialized copy per call site, called
directly, with no allocation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;x: () -&amp;gt; T&lt;/code&gt; is the neighbouring form and keeps its meaning.&lt;/strong&gt; Same type, different call site:
there the caller constructs the callable and the body calls it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(f: () -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() + &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(() -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
  <entry>
    <title>Traits and generics</title>
    <link href="https://sysl.sh/tour/traits/"/>
    <id>https://sysl.sh/tour/traits/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>One mechanism for polymorphism, two ways to spend it — a bound for static dispatch, a sigil for dynamic.</summary>
    <content type="html">&lt;p&gt;sysl has &lt;strong&gt;one&lt;/strong&gt; polymorphism mechanism, and it is called &lt;code&gt;trait&lt;/code&gt;. A type takes part in a trait only
through an explicit &lt;code&gt;impl Trait for Type&lt;/code&gt;; there is no structural conformance, so a type never
satisfies a trait by coincidence of method names.&lt;/p&gt;
&lt;p&gt;What varies is not the mechanism but how you spell the parameter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[T: Trait]&lt;/code&gt; — a &lt;strong&gt;bound&lt;/strong&gt; on a generic. Monomorphized, direct calls, no indirection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;amp;Trait&lt;/code&gt; / &lt;code&gt;*Trait&lt;/code&gt; — a &lt;strong&gt;trait object&lt;/strong&gt;. One copy of the code, dispatched through a table.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Same trait, two strategies, and no &lt;code&gt;dyn&lt;/code&gt; keyword: the memory-mode sigil already says everything one
would.&lt;/p&gt;
&lt;h2 id=&quot;a-trait-and-an-implementation&quot;&gt;A trait, and an implementation&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tag

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mimi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, mimi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A member written as a bare signature is one an implementation must supply. One written &lt;strong&gt;with a
body&lt;/strong&gt; is a default that every &lt;code&gt;impl&lt;/code&gt; inherits unless it writes its own.&lt;/p&gt;
&lt;p&gt;Defaults are what let a trait &lt;em&gt;grow&lt;/em&gt;: adding a member with a default does not break the
implementations that already exist, which is the difference between a trait a library can evolve and
one frozen at its first release.&lt;/p&gt;
&lt;p&gt;A default’s body may assume of its receiver exactly what its own trait declares, and nothing more.
That is not a restriction bolted on — it is what a default is, since the body has to serve every
implementing type and the trait is all they have in common. It is checked once, at the trait, even
when nothing implements the trait at all.&lt;/p&gt;
&lt;h2 id=&quot;any-type-may-carry-an-impl&quot;&gt;Any type may carry an &lt;code&gt;impl&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Including the built-ins, which is not a convenience but a requirement — a &lt;code&gt;Show&lt;/code&gt; that cannot cover
&lt;code&gt;int&lt;/code&gt; is a &lt;code&gt;Show&lt;/code&gt; no library can be written against:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;int &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(), &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;int 5 yes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where an &lt;code&gt;impl&lt;/code&gt; may &lt;em&gt;live&lt;/em&gt; is the one restriction: in the module that declares the trait, or in one
that declares a type named in the subject. That is Rust’s orphan rule, and it costs nothing —
retrofitting still works, because &lt;code&gt;impl MyTrait for TheirType&lt;/code&gt; lives with &lt;code&gt;MyTrait&lt;/code&gt;. What it buys is
that resolving a bound inspects only the modules a use site already depends on, with no global search
and no dependency edge the source does not show.&lt;/p&gt;
&lt;h2 id=&quot;generics-and-what-an-unbounded-parameter-may-do&quot;&gt;Generics, and what an unbounded parameter may do&lt;/h2&gt;
&lt;p&gt;A type parameter list in square brackets makes a function, struct or enum generic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;]
    first: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;
    second: &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;swapped&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.second, &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.first)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = p.&lt;span class=&quot;hl-function&quot;&gt;swapped&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.first, p.second, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, q.first, q.second)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 one / one 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Pair&lt;/code&gt; asks nothing of &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, and it does not need to. With no bound, a parameter may be
&lt;strong&gt;copied, assigned, passed, returned, and stored&lt;/strong&gt; — which is exactly what a container does.&lt;/p&gt;
&lt;p&gt;That baseline is bigger here than in Rust, and the memory chapter is why: every sysl value is
copyable, since assignment copies and copying a value holding a &lt;code&gt;&amp;amp;T&lt;/code&gt; retains it. So there is &lt;strong&gt;no
&lt;code&gt;Copy&lt;/code&gt; bound to write, ever&lt;/strong&gt;. “Hold and hand along any &lt;code&gt;T&lt;/code&gt;“ is free and unmarked.&lt;/p&gt;
&lt;p&gt;Type arguments are inferred, and from two directions — from the arguments (&lt;code&gt;Pair(1, &amp;quot;one&amp;quot;)&lt;/code&gt; gives
&lt;code&gt;A = int, B = string&lt;/code&gt;) and from the expected type, for the cases the arguments cannot settle. A
parameter that neither direction determines is an error asking for an annotation, never a silent
default.&lt;/p&gt;
&lt;h2 id=&quot;a-bound-is-a-trait&quot;&gt;A bound is a trait&lt;/h2&gt;
&lt;p&gt;What an unbounded &lt;code&gt;T&lt;/code&gt; may &lt;strong&gt;not&lt;/strong&gt; do is anything that assumes structure: no operator, no method call,
no field access, no subscript. Each of those is a capability some types have and others do not, so
each needs a bound that guarantees it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + x.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;() + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(n))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;#7&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here is the whole payoff. Drop the bound and the error lands on &lt;strong&gt;the definition that is wrong&lt;/strong&gt;,
not on some caller three files away that instantiated it with the wrong type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;show&apos; needs &apos;T: Show&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diagnostic names the bound to write, which is its whole job. That is definition-checked generics — the Swift/Kotlin/Scala consensus, and the opposite of a C++
template, whose errors arrive at instantiation wearing the callee’s insides.&lt;/p&gt;
&lt;p&gt;Multiple bounds join with &lt;code&gt;+&lt;/code&gt;: &lt;code&gt;[T: Ord + Hash]&lt;/code&gt; asks for both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A field is the one exception, and it proves the rule.&lt;/strong&gt; Every other unlicensed use names the bound
that would allow it, because that is the diagnostic’s whole job. A field names none — a trait promises
&lt;em&gt;behaviour&lt;/em&gt; and a field is &lt;em&gt;layout&lt;/em&gt;, so no bound could ever supply one. Reaching a value’s data
through a generic means going through a member the bound declares, which is also what lets two types
satisfy one bound while storing the value differently.&lt;/p&gt;
&lt;h2 id=&quot;operators-are-trait-methods&quot;&gt;Operators are trait methods&lt;/h2&gt;
&lt;p&gt;Which is why a bound is all it takes to write arithmetic over a parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = a + b
&lt;span class=&quot;hl-function&quot;&gt;biggest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; a &amp;lt; b &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; a

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.25&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;biggest&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;biggest&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;apple&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pear&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 3.75
9 pear
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; is &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt; is &lt;code&gt;Ord&lt;/code&gt;, &lt;code&gt;==&lt;/code&gt; is &lt;code&gt;Eq&lt;/code&gt;. Nothing about generics is special-cased for operators; an
operator on a &lt;code&gt;T&lt;/code&gt; simply requires the bound that supplies it, the same as a method call does.&lt;/p&gt;
&lt;p&gt;A type’s own parameters carry bounds too, in the same brackets and meaning the same thing — and that
is where a type says what it assumes. &lt;code&gt;struct SortedList[T: Ord]&lt;/code&gt; holds every application of the type
to the promise, and lets its members be checked at their definitions rather than at each use.&lt;/p&gt;
&lt;p&gt;A bound is declared &lt;strong&gt;once&lt;/strong&gt;, at the type, and is in force everywhere its parameters appear: a
member’s signature and body, a field’s type, a variant’s payload. It is not restated per member.&lt;/p&gt;
&lt;h2 id=&quot;monomorphization&quot;&gt;Monomorphization&lt;/h2&gt;
&lt;p&gt;Each distinct set of type arguments produces its own specialized function or aggregate. &lt;code&gt;sum&lt;/code&gt; called
at &lt;code&gt;int&lt;/code&gt; and at &lt;code&gt;real&lt;/code&gt; emits two functions; &lt;code&gt;Pair[int, string]&lt;/code&gt; and &lt;code&gt;Pair[int, int]&lt;/code&gt; are two layouts.&lt;/p&gt;
&lt;p&gt;That is what lets bounds be checked once at the definition and still lower to direct, inlinable code
with no dictionary passed at run time. The cost is code size, which is the standard trade and the
right default for a systems language — with the dynamic path below available whenever one copy is
what you actually want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Variance does not arise.&lt;/strong&gt; Variance is about when &lt;code&gt;G[A]&lt;/code&gt; may stand in for &lt;code&gt;G[B]&lt;/code&gt;, which needs a
subtyping relation to be interesting, and sysl has none among concrete types. &lt;code&gt;Box[Cat]&lt;/code&gt; and
&lt;code&gt;Box[Animal]&lt;/code&gt; are simply unrelated. That deletes a whole category of design difficulty, and it should
stay deleted: polymorphism over a set of types is a bound or a trait object, never a covariant
container.&lt;/p&gt;
&lt;h2 id=&quot;trait-objects&quot;&gt;Trait objects&lt;/h2&gt;
&lt;p&gt;When the set of types is open or genuinely heterogeneous, monomorphizing is impossible or wasteful.
A trait object is a &lt;strong&gt;fat pointer&lt;/strong&gt; — two words, the method table for the type it forgot, and the
value itself:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    side: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.side * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.side

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(shapes: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; shapes &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t += s.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;()

    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; shapes: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&amp;amp;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = [&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;total:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(shapes))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;total: 37
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sigil says who owns the second word, and nothing else changes between the two. &lt;code&gt;&amp;amp;Shape&lt;/code&gt; is an
ARC-owned object — the data word is the reference-counted box the value sits in, and letting go of it
needs no more knowledge of the payload than letting go of any &lt;code&gt;&amp;amp;T&lt;/code&gt; does. &lt;code&gt;*Shape&lt;/code&gt; is a raw fat
pointer, unmanaged like every &lt;code&gt;*T&lt;/code&gt;, and it is what a kernel passes around when there is no allocator.&lt;/p&gt;
&lt;p&gt;Erasure is a &lt;strong&gt;coercion&lt;/strong&gt;, applied wherever an object type is expected — an argument, a declared
variable, an array element, a struct field. Above, each &lt;code&gt;Rect(3, 4)&lt;/code&gt; is constructed, boxed because a
&lt;code&gt;&amp;amp;Shape&lt;/code&gt; was expected, and then erased, which is the ordinary “write the construction and it is
allocated” rule with one more step. Because the coercion applies per branch, an &lt;code&gt;if&lt;/code&gt; or a &lt;code&gt;match&lt;/code&gt;
whose arms are different concrete types meets at one trait object — which is the point of having
them.&lt;/p&gt;
&lt;p&gt;What an object offers is the trait’s methods and nothing else. No dereference, no fields, no
comparison, and no way back to the concrete type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But the two halves of this page’s opening meet at a bound.&lt;/strong&gt; An object carries a table of the
trait’s members, which is exactly what a bound asks for — so a &lt;code&gt;[T: Shape]&lt;/code&gt; function takes a &lt;code&gt;&amp;amp;Shape&lt;/code&gt;
as readily as it takes a &lt;code&gt;Rect&lt;/code&gt;, with an indirect call where the other gets a direct one. The choice
between static and dynamic is about what the &lt;em&gt;caller&lt;/em&gt; holds, not about which functions it can reach,
and a library written against bounds is not closed to a program that erased.&lt;/p&gt;
&lt;h3 id=&quot;object-safety&quot;&gt;Object safety&lt;/h3&gt;
&lt;p&gt;Erasure forgets the type, so a member may promise nothing that depends on knowing it. A trait can be
made into an object when every member has a receiver and mentions &lt;code&gt;Self&lt;/code&gt; nowhere but there.&lt;/p&gt;
&lt;p&gt;That second rule excludes &lt;strong&gt;every trait in the operator catalogue&lt;/strong&gt; — &lt;code&gt;add(self, rhs: Self) -&amp;gt; Self&lt;/code&gt;
first among them — and that is the right answer rather than a limitation. An operator over two values
of one type is a question about types known while compiling, so those traits are for bounds.&lt;/p&gt;
&lt;h2 id=&quot;a-trait-may-require-another&quot;&gt;A trait may require another&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;trait Reader: Fallible&lt;/code&gt; says that implementing &lt;code&gt;Reader&lt;/code&gt; obliges implementing &lt;code&gt;Fallible&lt;/code&gt; too. The
requirement is checked &lt;strong&gt;at the &lt;code&gt;impl&lt;/code&gt;&lt;/strong&gt;, not at the bound — so &lt;code&gt;[T: Reader]&lt;/code&gt; gets both traits’
members without having to name both, and a type that forgot one is told at its own declaration rather
than at somebody’s call.&lt;/p&gt;
&lt;p&gt;Where the required trait’s members all have defaults, satisfying it is one line with no block under
it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Source&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(), c.&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(), c.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the shape the standard library’s byte surface uses: &lt;code&gt;Reader&lt;/code&gt; and &lt;code&gt;Writer&lt;/code&gt; each require
&lt;code&gt;Fallible&lt;/code&gt;, so a type that is &lt;strong&gt;both&lt;/strong&gt; carries one &lt;code&gt;failed&lt;/code&gt; rather than two that nothing at a call
site could tell apart.&lt;/p&gt;
&lt;h2 id=&quot;a-trait-may-take-type-arguments&quot;&gt;A trait may take type arguments&lt;/h2&gt;
&lt;p&gt;Every trait so far has been a property of one type — a &lt;code&gt;Cat&lt;/code&gt; greets, a &lt;code&gt;Rect&lt;/code&gt; has an area. A trait
with &lt;strong&gt;parameters&lt;/strong&gt; says something about a &lt;em&gt;relation&lt;/em&gt; between types instead: what a sink accepts,
what a conversion converts from, what an iterator yields.&lt;/p&gt;
&lt;p&gt;The arguments are written in the same place wherever the trait is named — &lt;code&gt;impl Sink[int] for Buffer&lt;/code&gt;,
a bound &lt;code&gt;[X: Sink[int]]&lt;/code&gt;, an object &lt;code&gt;&amp;amp;Sink[int]&lt;/code&gt; — and they mean the same thing in each. What that
buys is the rule underneath: &lt;strong&gt;a type implements a parameterized trait once at each argument list&lt;/strong&gt;,
so two implementations on one type are ordinary rather than a conflict:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;From&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;from&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;
    tenths: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Temp&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;From&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;from&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;(x * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;From&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;from&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(x * &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;from&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Temp&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;from&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21.5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.tenths, b.tenths)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;210 215
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Temp&lt;/code&gt; has two members called &lt;code&gt;from&lt;/code&gt;, and what says which a call means is the &lt;strong&gt;argument list&lt;/strong&gt;. The
resolution is &lt;em&gt;determined&lt;/em&gt;, not preferred: a call is answered by the one implementation whose
parameters match the types the arguments have, and nothing ranks two candidates — so a call matching
none of them is reported rather than resolved to the nearest.&lt;/p&gt;
&lt;p&gt;Which is exactly why the arguments have to appear where they can be &lt;em&gt;seen&lt;/em&gt; at a call. A trait
parameter that shows up only in a &lt;strong&gt;return&lt;/strong&gt; type leaves the call with nothing to select on:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Into&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;into&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reading&lt;/span&gt;
    raw: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Reading&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Into&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reading&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;into&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.raw) / &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Into&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reading&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;into&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;raw &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.raw)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;Reading&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;215&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; celsius: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = r.&lt;span class=&quot;hl-function&quot;&gt;into&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(celsius)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;into&apos; comes from 2 implementations of one trait on Reading, and the arguments do not say which was meant
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust answers that one with turbofish and inference from the expected type. sysl’s own written type
arguments do not reach it: &lt;code&gt;x.into[Celsius]()&lt;/code&gt; would name a &lt;strong&gt;member’s own&lt;/strong&gt; parameters, and what is
ambiguous here belongs to the implementation rather than to &lt;code&gt;into&lt;/code&gt;. Writing the conversion as
&lt;code&gt;From[T]&lt;/code&gt; — where the thing being converted is an argument — is the shape that needs no such
machinery at all.&lt;/p&gt;
&lt;p&gt;This is also the mechanism the &lt;a href=&quot;/tour/errors/&quot;&gt;error handling&lt;/a&gt; chapter points at. A &lt;code&gt;?&lt;/code&gt; that converts
a callee’s error into the caller’s needs an &lt;code&gt;AppError&lt;/code&gt; that is &lt;code&gt;From[IoError]&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt;
&lt;code&gt;From[ParseError]&lt;/code&gt;, and those are two argument lists rather than two implementations of one thing.&lt;/p&gt;
&lt;h2 id=&quot;implementing-display&quot;&gt;Implementing &lt;code&gt;Display&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The trait worth writing first, because it is what &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;str&lt;/code&gt; reach:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) =
        &lt;span class=&quot;hl-function&quot;&gt;display_pad&lt;/span&gt;((&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.x) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.y) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).bytes, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;as text:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(p), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;padded:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%10s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;(3, 4)
as text: (3, 4) padded:     (3, 4)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the shape of the signature: a value renders itself &lt;strong&gt;into a &lt;code&gt;*Writer&lt;/code&gt;&lt;/strong&gt; rather than returning a
string. That is what makes rendering allocation-free — a program in a kernel supplies its own sink
with an ordinary &lt;code&gt;impl&lt;/code&gt; — and &lt;code&gt;str(x)&lt;/code&gt; is then the same rendering aimed at a buffer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Writer&lt;/code&gt; is the first trait the language itself forms objects of, and &lt;code&gt;display_pad&lt;/code&gt; is where every
implementation ends up: it applies the &lt;code&gt;FormatSpec&lt;/code&gt; to the finished bytes, which is why the parts are
gathered before anything is padded. A specifier describes the field the &lt;em&gt;whole&lt;/em&gt; value occupies, so
&lt;code&gt;%10s&lt;/code&gt; on a point pads the point and not its first number.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/modules/&quot;&gt;modules and the standard library&lt;/a&gt; — how a program is split up, and what comes
in the box.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Traits</title>
    <link href="https://sysl.sh/reference/traits/"/>
    <id>https://sysl.sh/reference/traits/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The one polymorphism mechanism — declaring, implementing, coherence, required traits, and trait objects.</summary>
    <content type="html">&lt;p&gt;sysl has &lt;strong&gt;one&lt;/strong&gt; polymorphism mechanism, and it is the &lt;code&gt;trait&lt;/code&gt;. It is &lt;strong&gt;nominal&lt;/strong&gt;: a type
participates in a trait only through an explicit &lt;code&gt;impl Trait for Type&lt;/code&gt;, and never by coincidence of
method names. From that one mechanism come both dispatch strategies — static, through a
&lt;a href=&quot;/reference/generics/&quot;&gt;generic bound&lt;/a&gt;, and dynamic, through a trait object.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cat&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tag

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, ada
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things are on display. A trait’s member is either a &lt;strong&gt;bare signature&lt;/strong&gt;, which an implementation
must supply, or a signature &lt;strong&gt;with a body&lt;/strong&gt;, which is a default every implementation inherits unless
it writes its own. And an implementation’s members become the type’s own, so &lt;code&gt;c.greet()&lt;/code&gt; is called
exactly as an inherent method is.&lt;/p&gt;
&lt;h2 id=&quot;declaring-a-trait&quot;&gt;Declaring a trait&lt;/h2&gt;
&lt;p&gt;A trait’s members are the three kinds a type’s members are, declared the same way and distinguished
the same way:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;member&lt;/th&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;reached as&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;method&lt;/td&gt;&lt;td&gt;&lt;code&gt;area(self) -&amp;gt; int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;x.area()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;property&lt;/td&gt;&lt;td&gt;&lt;code&gt;size -&amp;gt; int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;x.size&lt;/code&gt;, with no parentheses&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;associated function&lt;/td&gt;&lt;td&gt;&lt;code&gt;zero() -&amp;gt; Self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;T.zero()&lt;/code&gt;, through the type&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A property is asked for by dropping the body from its declaration form&lt;/strong&gt;, and supplied by an
implementation writing that body:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sized&lt;/span&gt;
    size -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sized&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;
    size -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.size)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing about a property’s dispatch differs from a method’s: it has a receiver, it simply never
spells one, so it takes a table slot beside the methods and a bound licenses reading it exactly as
one licenses calling them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which kind a member is has to match between the trait and the implementation&lt;/strong&gt;, and that is a real
check rather than a formality — a property and an associated function both have no receiver to
compare, so &lt;code&gt;size(self) -&amp;gt; int&lt;/code&gt; would otherwise quietly stand in for &lt;code&gt;size -&amp;gt; int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Self&lt;/code&gt; is the implementing type&lt;/strong&gt;, written wherever a signature has to name it. Inside a generic
&lt;code&gt;impl&lt;/code&gt; it is the subject applied to that block’s parameters, so &lt;code&gt;-&amp;gt; Self&lt;/code&gt; and &lt;code&gt;-&amp;gt; Box[T]&lt;/code&gt; are the one
signature conformance compares.&lt;/p&gt;
&lt;h3 id=&quot;a-default-may-assume-exactly-what-its-own-trait-declares&quot;&gt;A default may assume exactly what its own trait declares&lt;/h3&gt;
&lt;p&gt;That is not a restriction bolted on; it is what a default &lt;em&gt;is&lt;/em&gt;, since the body must serve every
implementing type and the trait is all they have in common. So &lt;strong&gt;a default’s body is checked once, at
the trait&lt;/strong&gt;, as the generic function it is — one type parameter, &lt;code&gt;Self&lt;/code&gt;, bounded by the trait. A
default calling a member the trait does not declare is reported at the trait, on its own line, &lt;strong&gt;even
when nothing implements the trait at all.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It may not read a &lt;strong&gt;field&lt;/strong&gt; of its receiver either. A bound promises behaviour and a field is layout,
so no bound could ever license one — see &lt;a href=&quot;/reference/generics/&quot;&gt;generics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What a default buys beyond convenience is that &lt;strong&gt;a trait can grow&lt;/strong&gt;: adding a member with a default
does not break the implementations that already exist, which is the difference between a trait a
library can evolve and one frozen at its first release.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trait whose every member has a default leaves nothing to write&lt;/strong&gt;, so the block is optional and
the opt-in is the point of writing it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Amp&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The body a program runs is a &lt;strong&gt;copy per implementing type&lt;/strong&gt;, materialized under that type’s own name.
That is monomorphization with &lt;code&gt;Self&lt;/code&gt; for the parameter, so everything downstream — an ordinary call, a
table slot, the escape summary — finds a function that exists and needs to know nothing about where it
came from.&lt;/p&gt;
&lt;h3 id=&quot;replacing-a-default-says-override&quot;&gt;Replacing a default says &lt;code&gt;override&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;An implementation may write the member itself instead of taking the trait’s body, and when it does it
says so — replacing a default is the same act as &lt;a href=&quot;#override-when-the-overlap-is-deliberate&quot;&gt;replacing an implementation&lt;/a&gt;,
and takes the same keyword:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Amp&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leave it off and the member is refused, because the reader of an &lt;code&gt;impl&lt;/code&gt; block wants to know which of
its members are replacing something and which are supplying what the trait asked for — a question
that otherwise means opening the trait to find out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Amp&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Amp&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;volume&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;trait &apos;Loud&apos; supplies a body for method &apos;volume&apos;, so writing one here replaces it — say &apos;override volume&apos;, or leave the member out to keep the trait&apos;s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;And it is refused where nothing is replaced.&lt;/strong&gt; A member answering a bare requirement — the ordinary
case, and every member of most &lt;code&gt;impl&lt;/code&gt; blocks — supplies what the trait asked for rather than
replacing a body, so the keyword would be saying something untrue:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sized&lt;/span&gt;
    size -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sized&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; size -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;trait &apos;Sized&apos; declares property &apos;size&apos; without a body, so this member supplies what the trait asked for rather than replacing anything — &apos;override&apos; says a body was replaced
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rule costs almost nothing, because an implementation content with a default writes no member at
all — across the whole of sysl’s own library, guides and examples, exactly two members replace one.&lt;/p&gt;
&lt;h2 id=&quot;conformance-is-explicit-always&quot;&gt;Conformance is explicit, always&lt;/h2&gt;
&lt;p&gt;A type that happens to have a member of the right name and shape does &lt;strong&gt;not&lt;/strong&gt; satisfy a trait. There
is no structural conformance, and the &lt;code&gt;impl&lt;/code&gt; is what documents the intent:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;announce&apos; requires its type parameter &apos;T&apos; to implement &apos;Named&apos;, but P does not
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nominal is the consensus among the languages sysl takes from — Swift protocols, Kotlin interfaces,
and Scala traits are all nominal — and it kills &lt;em&gt;accidental conformance&lt;/em&gt;, where a type satisfies a
promise purely because two names collided.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Retrofitting is preserved.&lt;/strong&gt; You may &lt;code&gt;impl&lt;/code&gt; your trait for a type you do not own; you just do it
explicitly rather than by implicit structural match.&lt;/p&gt;
&lt;h2 id=&quot;the-two-dispatch-strategies&quot;&gt;The two dispatch strategies&lt;/h2&gt;
&lt;p&gt;A trait is used two ways, and this is the pivot a programmer faces every time polymorphism comes up.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;[T: Trait]&lt;/code&gt; — static&lt;/th&gt;&lt;th&gt;&lt;code&gt;&amp;amp;Trait&lt;/code&gt; / &lt;code&gt;*Trait&lt;/code&gt; — dynamic&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;what happens&lt;/td&gt;&lt;td&gt;one specialized copy per concrete &lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one copy of the code, dispatched through a table&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the call&lt;/td&gt;&lt;td&gt;direct, inlinable&lt;/td&gt;&lt;td&gt;indirect, not inlined&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the value&lt;/td&gt;&lt;td&gt;by value, no indirection&lt;/td&gt;&lt;td&gt;behind a fat pointer, always&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the set of types&lt;/td&gt;&lt;td&gt;fixed at compile time&lt;/td&gt;&lt;td&gt;open&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;cost&lt;/td&gt;&lt;td&gt;code size&lt;/td&gt;&lt;td&gt;one indirect call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;reach for it when&lt;/td&gt;&lt;td&gt;the type is known — the overwhelming majority&lt;/td&gt;&lt;td&gt;the collection is heterogeneous, or the boundary is a plugin&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Static&lt;/strong&gt; is the default:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Dog&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cat&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dog &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cat &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rex&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;dog rex cat ada
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Dynamic&lt;/strong&gt; is the escape hatch for genuine runtime heterogeneity:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    s: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Square&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.s * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.s

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; shapes: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&amp;amp;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = [&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(shapes[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;].&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(), shapes[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;].&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same trait, two strategies, chosen by &lt;strong&gt;how you spell the parameter&lt;/strong&gt; — a bound for static, a
sigil-carried trait object for dynamic. There is no &lt;code&gt;dyn&lt;/code&gt; keyword either way, because the sigil
already says everything one would.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The two are not separate worlds.&lt;/strong&gt; A trait object satisfies a bound on the trait it dispatches
through, so &lt;code&gt;announce&lt;/code&gt; above takes a &lt;code&gt;&amp;amp;Named&lt;/code&gt; as readily as it takes a &lt;code&gt;Dog&lt;/code&gt; — the table it carries
holds exactly the members the bound names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Dog&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dog &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rex&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Dog&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rex&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(d))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;dog rex dog rex
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So the table above is about what the &lt;strong&gt;caller&lt;/strong&gt; holds, not about which functions it can reach. A
library written against bounds is open to a program that erased, and needs no second signature
written the other way. See &lt;a href=&quot;/reference/generics/&quot;&gt;generics&lt;/a&gt; for what the rule rests on — an object
type is a concrete type, so nothing about monomorphization changes to allow it.&lt;/p&gt;
&lt;h2 id=&quot;any-type-may-carry-an-impl&quot;&gt;Any type may carry an &lt;code&gt;impl&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;impl Show for int&lt;/code&gt; is as ordinary as &lt;code&gt;impl Show for Point&lt;/code&gt;, and &lt;code&gt;impl Show for []int&lt;/code&gt; is as ordinary
as either. This is not a convenience: a trait that cannot cover &lt;code&gt;int&lt;/code&gt; is a trait no library can be
written against, and the library’s own &lt;code&gt;Display&lt;/code&gt; is the first thing that needs it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Double&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Double&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt; * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(), (&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every type has one owner key&lt;/strong&gt; its members are filed under: a struct or an enum by the name it was
declared with, everything else by its one canonical name. So &lt;code&gt;impl Show for int&lt;/code&gt; and
&lt;code&gt;impl Show for i32&lt;/code&gt; are the single implementation they are rather than two, and two spellings of one
type collide as the duplicate they are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;impl&lt;/code&gt;‘s subject is a type reference, not an identifier&lt;/strong&gt;, so the types with no name of their own
carry an implementation exactly as the named ones do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Total&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Total&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An array’s length is part of its type&lt;/strong&gt;, so &lt;code&gt;[2]int&lt;/code&gt; and &lt;code&gt;[3]int&lt;/code&gt; are two types and may implement
the same trait differently.&lt;/p&gt;
&lt;p&gt;Two subjects are refused, each because an implementation for it would be about nothing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a memory mode&lt;/strong&gt; — &lt;code&gt;*Point&lt;/code&gt;, &lt;code&gt;&amp;amp;Point&lt;/code&gt;. A mode is a way of &lt;em&gt;holding&lt;/em&gt; a &lt;code&gt;Point&lt;/code&gt; rather than a type
beside it, and a member call already sees through one level of &lt;code&gt;*&lt;/code&gt; or &lt;code&gt;&amp;amp;&lt;/code&gt; to find the receiver’s
members, so an &lt;code&gt;impl&lt;/code&gt; for the mode would register members nothing could reach;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a trait object&lt;/strong&gt; — &lt;code&gt;*Show&lt;/code&gt;. An &lt;code&gt;impl&lt;/code&gt; says how one particular type behaves, and which type it
holds is precisely what an erased value has forgotten.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;*P&apos; is a way of holding a P rather than a type of its own — write the &apos;impl&apos; for P
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A compiler-provided member is out of reach for the same reason a field is.&lt;/strong&gt; &lt;code&gt;len&lt;/code&gt; on a slice or an
array, and &lt;code&gt;bytes&lt;/code&gt; on a string, are reached ahead of the member table rather than through it, so an
&lt;code&gt;impl&lt;/code&gt; declaring one would register a member no reader could find.&lt;/p&gt;
&lt;h3 id=&quot;where-an-impl-may-live&quot;&gt;Where an &lt;code&gt;impl&lt;/code&gt; may live&lt;/h3&gt;
&lt;p&gt;An &lt;code&gt;impl&lt;/code&gt; is &lt;strong&gt;unnamed&lt;/strong&gt; — nothing at a use site says which one to apply — so resolving &lt;code&gt;T: Show&lt;/code&gt; or
&lt;code&gt;5.show()&lt;/code&gt; means &lt;em&gt;searching&lt;/em&gt; for an implementation. Once a program is more than one module, that
search needs a bound, or it would range over every module in the program, which is exactly the
property that makes separate compilation impossible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;impl Trait for Type&lt;/code&gt; may appear only in the module that declares &lt;code&gt;Trait&lt;/code&gt;, or in one that
declares a type named in &lt;code&gt;Type&lt;/code&gt;.&lt;/strong&gt; Resolving a bound therefore inspects only the modules a use site
already depends on in order to write the trait and the type down. No global search, and no dependency
edge the source does not show.&lt;/p&gt;
&lt;p&gt;This is Rust’s orphan rule, and it costs nothing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;retrofitting still works&lt;/strong&gt; — &lt;code&gt;impl MyTrait for TheirType&lt;/code&gt; lives with &lt;code&gt;MyTrait&lt;/code&gt;, and the trait’s
module licenses it;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;impl Show for int&lt;/code&gt; still works&lt;/strong&gt; — a built-in has no module of its own, so its owner key belongs
to the library, and every &lt;code&gt;impl&lt;/code&gt; on one is licensed by its trait’s module instead;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a composed type is the module’s when anything named in it is&lt;/strong&gt; — &lt;code&gt;override impl Display for []Point&lt;/code&gt; is licensed by &lt;code&gt;Point&lt;/code&gt;, while a block for &lt;code&gt;[]int&lt;/code&gt; names nothing outside the library and
has no home. (It says &lt;code&gt;override&lt;/code&gt; because the library implements &lt;code&gt;Display&lt;/code&gt; for every slice; the two
rules are separate, and a slice of your own struct needs both — coherence to have a home, and
&lt;a href=&quot;#override-when-the-overlap-is-deliberate&quot;&gt;&lt;code&gt;override&lt;/code&gt;&lt;/a&gt; to outrank the block already covering it);&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a type parameter is not a local type&lt;/strong&gt;, so &lt;code&gt;impl[T: Display] Display for []T&lt;/code&gt; is refused however
its bound is written. Making every printable slice printable is the library’s job.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What the rule forbids is the case with no home: &lt;strong&gt;a foreign trait implemented for a foreign type&lt;/strong&gt;,
where two unrelated modules could each supply a different implementation and no rule picks one.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;impl&lt;/code&gt; is part of its module’s public surface. Adding, removing, or changing one is an interface
change visible to everything downstream — the same reasoning that puts implicit-resolution schemes
out of scope. See &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;an-impl-covers-a-generic-type-as-a-whole&quot;&gt;An &lt;code&gt;impl&lt;/code&gt; covers a generic type as a whole&lt;/h2&gt;
&lt;p&gt;A block may declare &lt;strong&gt;type parameters of its own&lt;/strong&gt;, written directly after the keyword:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;box of &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.v)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;box of 41
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is one implementation for &lt;strong&gt;every&lt;/strong&gt; &lt;code&gt;Box&lt;/code&gt;, and its members are monomorphized per receiver
exactly as a generic type’s own members are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Its subject must be the type applied to the block’s parameters and nothing else&lt;/strong&gt; — each argument
one parameter, each parameter used once, all of them spoken for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Box&apos; is generic, so an &apos;impl&apos; for it covers every instantiation at once — write &apos;impl[T] Show2 for Box[T]&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A generic type has &lt;strong&gt;one key for all of its instantiations&lt;/strong&gt;, so an implementation for &lt;em&gt;some&lt;/em&gt; of them
would be a second implementation for a key that holds one. Overlapping implementations, and the
specialization rule that would be needed to pick between them, are deliberately not in the language.&lt;/p&gt;
&lt;p&gt;The parameters are matched to the arguments &lt;strong&gt;by position in the subject&lt;/strong&gt;, not by the order they were
declared in, so &lt;code&gt;impl[X, Y] Show for Pair[Y, X]&lt;/code&gt; reads as it looks.&lt;/p&gt;
&lt;h3 id=&quot;conditional-conformance&quot;&gt;Conditional conformance&lt;/h3&gt;
&lt;p&gt;A bound on the block is what makes the conformance conditional. In the &lt;code&gt;Box&lt;/code&gt; example above, a
&lt;code&gt;Box[T]&lt;/code&gt; implements &lt;code&gt;Show&lt;/code&gt; &lt;strong&gt;precisely when&lt;/strong&gt; &lt;code&gt;T&lt;/code&gt; implements &lt;code&gt;Display&lt;/code&gt; — so &lt;code&gt;Box[int]&lt;/code&gt; does and a
&lt;code&gt;Box&lt;/code&gt; of something unprintable does not.&lt;/p&gt;
&lt;p&gt;That question is asked one step in and &lt;strong&gt;composes&lt;/strong&gt;: under &lt;code&gt;impl[T: Show] Show for Box[T]&lt;/code&gt;, a
&lt;code&gt;Box[Box[int]]&lt;/code&gt; conforms exactly when &lt;code&gt;Box[int]&lt;/code&gt; does, which is what makes a conditional
implementation usable on nested types at all.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Show&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.v.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;bbi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything that asks whether a type conforms asks it the same way — a generic function’s bound, an
erasure to a trait object, &lt;code&gt;print&lt;/code&gt; reaching for a &lt;code&gt;Display&lt;/code&gt; — so an instantiation that fails the
condition is refused at each of them while its siblings are not.&lt;/p&gt;
&lt;p&gt;What the bounds buy beyond deciding conformance is that &lt;strong&gt;the members become checkable at their
definition&lt;/strong&gt;: a block states what it assumes, so its bodies are walked once against those bounds
alone, and a method calling something no bound licenses is reported on its own line with nothing
instantiated.&lt;/p&gt;
&lt;h3 id=&quot;a-shape-is-covered-the-same-way&quot;&gt;A shape is covered the same way&lt;/h3&gt;
&lt;p&gt;A composed type has no name to be generic over, but it has a &lt;strong&gt;shape&lt;/strong&gt;, and a block with type
parameters may match that instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Count&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.len

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs.&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything above holds unchanged: the subject is the shape applied to the block’s parameters and
nothing else, so &lt;code&gt;impl[T] Count for [][]T&lt;/code&gt; is refused because the element is a shape rather than a
parameter, and so is a fixed element:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Count&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Count&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;int&apos; fixes the element type, and an &apos;impl&apos; with type parameters covers every slice — write one of the block&apos;s own parameters here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things are the shape’s own. &lt;strong&gt;A composed type is filed under the whole of itself&lt;/strong&gt; — &lt;code&gt;[]int&lt;/code&gt;,
not &lt;code&gt;[]&lt;/code&gt; — so a shape needs a key the types it covers do not have, and dropping the arguments is what
makes one; a lookup finding nothing under the type’s own key falls back to it. And because an
&lt;strong&gt;array’s length is not something a parameter can stand for&lt;/strong&gt;, the length stays part of the shape:
&lt;code&gt;[2]T&lt;/code&gt; and &lt;code&gt;[3]T&lt;/code&gt; are two shapes, each covering every element type at its own length.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;string&lt;/code&gt; is not covered by &lt;code&gt;[]T&lt;/code&gt;.&lt;/strong&gt; It is a view of bytes that are valid UTF-8, and that invariant
is the whole difference between it and a &lt;code&gt;[]u8&lt;/code&gt; — a block written for every slice has said nothing
about it. &lt;code&gt;&amp;quot;hi&amp;quot;.bytes&lt;/code&gt; is a &lt;code&gt;[]u8&lt;/code&gt; and is covered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A shape and a written-out type overlap, and an unmarked overlap is refused.&lt;/strong&gt; Both blocks would say
how a &lt;code&gt;[]int&lt;/code&gt; renders, so whichever is written second is refused and the diagnostic names the one
already there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;[]int&apos; already implements &apos;Show2&apos;, and this &apos;impl&apos; would implement it for every slice — including that one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the default and it is worth keeping: two blocks that overlap are usually a mistake — a
duplicate written by accident, or one put in the wrong module — and refusing them is how that gets
found.&lt;/p&gt;
&lt;h3 id=&quot;override-when-the-overlap-is-deliberate&quot;&gt;&lt;code&gt;override&lt;/code&gt; — when the overlap is deliberate&lt;/h3&gt;
&lt;p&gt;An implementation may say &lt;strong&gt;&lt;code&gt;override&lt;/code&gt;&lt;/strong&gt;, and then it wins:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ss: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs.&lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(), ss.&lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The keyword goes on the overriding side, not the overridden one.&lt;/strong&gt; That is the whole of the design,
and it is the opposite of C#’s &lt;code&gt;virtual&lt;/code&gt;/&lt;code&gt;override&lt;/code&gt; pair and of Rust’s unstable &lt;code&gt;default&lt;/code&gt;: both of
those make the general implementation grant permission in advance, and a library author cannot know
which of their implementations somebody will need to replace. Intent is something the writer of the
override has and the writer of the original does not.&lt;/p&gt;
&lt;p&gt;It grants no permission, so what it buys is the diagnostic. An unmarked second implementation is
still refused exactly as above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The overriding side is always a type written out in full.&lt;/strong&gt; A shape is one key and so is a generic
type’s name, and the blocks that would sit &lt;em&gt;under&lt;/em&gt; those are already refused — &lt;code&gt;impl[T] Show2 for [][]T&lt;/code&gt; matches a shape’s argument by its shape, and &lt;code&gt;impl Show2 for Box[int]&lt;/code&gt; fixes one instantiation
of a block covering every instantiation. So there is nothing below either of them to be more specific
than, and marking one says so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;override&apos; says this block replaces a more general one, and &apos;[]T&apos; is the general kind — an implementation for a shape or for a generic type covers every type it matches at once, so there is nothing below it. The override is written on the block for one type spelled out in full
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;override&lt;/code&gt; that overrides nothing is refused&lt;/strong&gt;, which is the check in the other direction and
the one that earns its keep later: a library drops or narrows the implementation a program was
overriding, and without this the override silently becomes the only one while still claiming to
replace something.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Show2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;show2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;[]int&apos; says &apos;override&apos;, but nothing else implements &apos;Show2&apos; for it — an override replaces an implementation that covers the type more generally, and there is none to replace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What keeps this sound is coherence rather than the keyword.&lt;/strong&gt; The hazard a rule like this usually
brings is two method tables for one type — a &lt;code&gt;[]Point&lt;/code&gt; erased to a &lt;code&gt;*Show2&lt;/code&gt; picking one
implementation at one site and the other elsewhere. An &lt;code&gt;impl&lt;/code&gt; may live only in the module declaring
the trait or in one declaring a type named in the subject, so a program cannot write
&lt;code&gt;impl[T] Display for []T&lt;/code&gt; at all — &lt;code&gt;[]T&lt;/code&gt; names no type of its own. &lt;strong&gt;The only override anybody can
write across a module boundary is one that names their own type&lt;/strong&gt;, so there is exactly one per type
and it lives with that type; and any site that can write &lt;code&gt;[]Point&lt;/code&gt; down already depends on the module
declaring &lt;code&gt;Point&lt;/code&gt;. One type, one table.&lt;/p&gt;
&lt;p&gt;The cost that remains, stated plainly: a library can no longer rely on its own implementations. What
&lt;code&gt;override&lt;/code&gt; buys is that every such site is greppable rather than invisible.&lt;/p&gt;
&lt;h2 id=&quot;a-trait-may-take-type-parameters&quot;&gt;A trait may take type parameters&lt;/h2&gt;
&lt;p&gt;A trait declares parameters in the same bracketed list every other generic declaration writes, and an
implementation says which arguments it supplies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buffer&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Buffer&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buffer&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += x

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Buffer&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), b.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Sink&lt;/code&gt; is not one promise but a family of them: &lt;code&gt;Sink[int]&lt;/code&gt; and &lt;code&gt;Sink[string]&lt;/code&gt; say different things,
and which one a &lt;code&gt;Buffer&lt;/code&gt; makes is the implementation’s to state. That is what a trait needs before it
can describe a &lt;strong&gt;relation between two types&lt;/strong&gt; rather than a property of one — what a sink accepts,
what a conversion converts from, what an iterator yields.&lt;/p&gt;
&lt;p&gt;The arguments are written in the same place in all three positions a trait is named, and mean the same
thing in each:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;position&lt;/th&gt;&lt;th&gt;written&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a bound&lt;/td&gt;&lt;td&gt;&lt;code&gt;f[X: Sink[int]](x: X)&lt;/code&gt;, and the body’s &lt;code&gt;x.put(…)&lt;/code&gt; then takes an &lt;code&gt;int&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an implementation&lt;/td&gt;&lt;td&gt;&lt;code&gt;impl Sink[int] for Buffer&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a trait object&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;Sink[int]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A trait’s own parameters carry bounds too — &lt;code&gt;trait Get[T: Show]&lt;/code&gt; — and everything applying the trait
supplies them, exactly as everything applying a bounded struct does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A parameter may carry a default&lt;/strong&gt;, and &lt;code&gt;Self&lt;/code&gt; is the case the feature exists for:
&lt;code&gt;trait Scale[R = Self]&lt;/code&gt; is the operand type, usually the implementing type, so &lt;code&gt;impl Scale for P&lt;/code&gt; is
the &lt;code&gt;impl Scale[P] for P&lt;/code&gt; it reads as and &lt;code&gt;[T: Scale]&lt;/code&gt; asks for &lt;code&gt;Scale[T]&lt;/code&gt;. See
&lt;a href=&quot;/reference/generics/&quot;&gt;generics&lt;/a&gt; for how defaults are filled.&lt;/p&gt;
&lt;h3 id=&quot;one-implementation-per-argument-list&quot;&gt;One implementation per argument list&lt;/h3&gt;
&lt;p&gt;A type may implement a trait &lt;strong&gt;once at each argument list&lt;/strong&gt;, and the argument list is what tells two
implementations apart:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Buf&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tag + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; int&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tag + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; string&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), b.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;b int b string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A second &lt;code&gt;impl Sink[int] for Buf&lt;/code&gt; beside those is refused — that one is already there.&lt;/p&gt;
&lt;p&gt;This is the one place the “a trait’s members become the type’s, and a type’s members are one
namespace” rule is qualified, and the qualification is narrow. A &lt;code&gt;Celsius&lt;/code&gt; with both blocks has two
members called &lt;code&gt;from&lt;/code&gt;, and what says which a use means is the &lt;strong&gt;argument list&lt;/strong&gt;, which every way of
reaching one already carries: an operator carries its pair of operands, a bound names the arguments, a
trait object is formed at written arguments, and a named call passes values whose types are the
arguments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The resolution is determined, not preferred.&lt;/strong&gt; Nothing ranks two candidates: a call is answered by
the one implementation whose parameters are the types the arguments have, and a call answering to none
of them or to more than one is reported rather than resolved. So &lt;code&gt;c.mul(2)&lt;/code&gt; where the candidates take
a &lt;code&gt;Complex&lt;/code&gt; and a &lt;code&gt;real&lt;/code&gt; is refused — an integer literal is neither, and picking the nearest would be
the specialization rule this language does not have.&lt;/p&gt;
&lt;p&gt;Two limits fall out of “several implementations are told apart inside one namespace”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a property has no arguments&lt;/strong&gt;, so two implementations both supplying one leave nothing to select
with, and reading it is refused;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a shape and a type of that shape&lt;/strong&gt; are filed under two different owner keys, and a member lookup
takes one or the other and never both — so a second implementation split across that boundary would
be one no call could reach.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A generic block may write its own parameter as a trait argument&lt;/strong&gt; — &lt;code&gt;impl[T] Index[usize, T] for Buf[T]&lt;/code&gt; says a &lt;code&gt;Buf[int]&lt;/code&gt; implements &lt;code&gt;Index[usize, int]&lt;/code&gt; and nothing else. That is what lets a
container carry the type of what it holds in the trait it implements, without an associated type to
derive it from.&lt;/p&gt;
&lt;h2 id=&quot;a-trait-may-require-another-trait&quot;&gt;A trait may require another trait&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;trait Word: Add + BitXor&lt;/code&gt; — written after the name, with the same &lt;code&gt;:&lt;/code&gt; and the same &lt;code&gt;+&lt;/code&gt; a bound uses,
because it asks the same thing of the implementing type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, ada
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A required trait is a promise the &lt;strong&gt;trait&lt;/strong&gt; makes rather than one each declaration repeats. &lt;code&gt;[T: Greet]&lt;/code&gt;
then licenses &lt;code&gt;label&lt;/code&gt;; a &lt;strong&gt;default body&lt;/strong&gt; in &lt;code&gt;Greet&lt;/code&gt; may use it, since what a default may assume is
exactly what its trait promises; and a &lt;code&gt;&amp;amp;Greet&lt;/code&gt; object carries the required trait’s members in its
table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The requirement is checked at the &lt;code&gt;impl&lt;/code&gt;, not at the bound&lt;/strong&gt;, and the diagnostic belongs on the
declaration that cannot keep its word:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Named&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Greet&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Greet&apos; requires &apos;Named&apos;, so &apos;P&apos; has to implement that too — write &apos;impl Named for P&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Checking at the &lt;code&gt;impl&lt;/code&gt; is also what keeps conformance a plain lookup: by the time anything asks
whether a type implements a required trait, an implementation of it is already registered. The
question is held until every &lt;code&gt;impl&lt;/code&gt; has been seen, since the block supplying a required trait may be
written below the one that needs it.&lt;/p&gt;
&lt;h3 id=&quot;the-table-carries-the-required-trait-s-slots&quot;&gt;The table carries the required trait’s slots&lt;/h3&gt;
&lt;p&gt;A trait’s members are the required traits’ members, depth-first with each trait taken once, followed
by its own. Both the table and the call sites indexing into it are laid out from that one list, so &lt;strong&gt;a
required trait’s method is one indirect call&lt;/strong&gt;, exactly like the trait’s own. The alternative — a word
in the table pointing at the required trait’s own table — costs a second load on every such call and
buys one thing sysl does not have: an upcast.&lt;/p&gt;
&lt;p&gt;So &lt;strong&gt;a &lt;code&gt;&amp;amp;Sub&lt;/code&gt; cannot become a &lt;code&gt;&amp;amp;Super&lt;/code&gt;&lt;/strong&gt;, and that is the price of the choice rather than an oversight.
Nothing is unwritable for want of it: what a program does with a required trait is call its members,
which works.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The diamond needs no rule of its own.&lt;/strong&gt; &lt;code&gt;D: A + C&lt;/code&gt; with both &lt;code&gt;A: B&lt;/code&gt; and &lt;code&gt;C: B&lt;/code&gt; carries &lt;code&gt;B&lt;/code&gt;‘s members
once, because the walk takes each trait the first time it reaches it. What &lt;em&gt;is&lt;/em&gt; refused is two traits
in one closure declaring a member of the same name — and the reason is the &lt;strong&gt;table&lt;/strong&gt;, not the
namespace. Two unrelated traits may each name a member of one type, because a call says which by
naming the trait; two traits inside one requirement closure are laid out as one table, and a call
through a &lt;code&gt;&amp;amp;Sub&lt;/code&gt; has already forgotten everything that could have said which slot it meant.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;L&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;len2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;len2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Both&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;L&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;R&apos; and &apos;L&apos; both declare &apos;len2&apos;, and a trait&apos;s members become the implementing type&apos;s — so &apos;Both&apos; cannot require both
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A trait may not require itself&lt;/strong&gt;, directly or around a cycle:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loop&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Loop&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;step&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;trait &apos;Loop&apos; requires itself, through Loop -&amp;gt; Loop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two rules close the section. A trait may not require one that &lt;strong&gt;reaches less far&lt;/strong&gt; than it does, since
implementing the trait means implementing the required one — a requirement the implementer cannot name
leaves the trait unimplementable from outside. And &lt;code&gt;Self&lt;/code&gt; in a requirement’s arguments is the type
implementing the requiring trait, so &lt;code&gt;trait Vector: Scale[Self]&lt;/code&gt; asks that whatever implements &lt;code&gt;Vector&lt;/code&gt;
can be scaled by its own type — which is the same requirement &lt;code&gt;trait Vector: Scale&lt;/code&gt; writes when
&lt;code&gt;Scale&lt;/code&gt; defaults its parameter to &lt;code&gt;Self&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;trait-objects&quot;&gt;Trait objects&lt;/h2&gt;
&lt;p&gt;A trait object is a &lt;strong&gt;fat pointer&lt;/strong&gt; — two words, the method table for the type it forgot and the value
itself:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{ ptr vtable, ptr data }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The sigil says who owns the second word, and nothing else changes between the two:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;the data word is&lt;/th&gt;&lt;th&gt;who frees it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*Trait&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the value’s own address&lt;/td&gt;&lt;td&gt;nobody — raw and unmanaged, like every &lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;Trait&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the reference-counted &lt;strong&gt;box&lt;/strong&gt; the value sits in&lt;/td&gt;&lt;td&gt;ARC, exactly as for the &lt;code&gt;&amp;amp;T&lt;/code&gt; it was erased from&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;*T&lt;/code&gt; and &lt;code&gt;&amp;amp;T&lt;/code&gt; on a &lt;em&gt;concrete&lt;/em&gt; type are thin pointers; on a &lt;em&gt;trait&lt;/em&gt; they are fat. The trait-ness makes
them fat, and that is why there is no &lt;code&gt;dyn&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The table is per (trait, type, sigil)&lt;/strong&gt;, two flavours rather than one because the data word means
different things: an entry has to reach a receiver, and from a box that is one step further in than
from a bare value. Where the data word already &lt;em&gt;is&lt;/em&gt; the receiver an implementation declared, the entry
names that implementation itself; otherwise it names a small adapter that steps over the box header,
loads the value, or both. So the common case costs one indirect call and nothing else.&lt;/p&gt;
&lt;h3 id=&quot;object-safety&quot;&gt;Object safety&lt;/h3&gt;
&lt;p&gt;Erasure forgets the type, so a member may promise nothing that depends on knowing it. A trait may be
made into an object when every member:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;has a receiver.&lt;/strong&gt; An associated function has nothing to dispatch on. A property does have one — by
value, and unwritten — so a trait asking for a property is as safe to erase as one asking for a
method.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mentions &lt;code&gt;Self&lt;/code&gt; nowhere but that receiver.&lt;/strong&gt; A second &lt;code&gt;Self&lt;/code&gt; would have to be the &lt;em&gt;same&lt;/em&gt; forgotten
type as the first, which is exactly the fact an object no longer carries, and a &lt;code&gt;Self&lt;/code&gt; result has no
size to hand back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;does not take &lt;code&gt;&amp;amp;self&lt;/code&gt;, for a &lt;code&gt;*Trait&lt;/code&gt; only.&lt;/strong&gt; &lt;code&gt;&amp;amp;self&lt;/code&gt; asks for its receiver inside a box, and a raw
object points straight at a value. A &lt;code&gt;&amp;amp;Trait&lt;/code&gt; carries one, so it accepts such a member.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;takes no &lt;code&gt;...&lt;/code&gt;.&lt;/strong&gt; A call to a variadic names the callee’s &lt;em&gt;whole&lt;/em&gt; function type, because that is
how it says where the declared parameters stop and the tail begins, and a slot in a table is one word
and names none.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.v * k)

&lt;span class=&quot;hl-function&quot;&gt;grow&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;scale&apos; of &apos;Scale&apos; mentions &apos;Self&apos; away from its receiver, and an erased value has forgotten which type that is — so there is no &apos;&amp;amp;Scale&apos; to form
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The middle rule excludes &lt;strong&gt;every trait in the operator catalog&lt;/strong&gt; — &lt;code&gt;add(self, rhs: Self) -&amp;gt; Self&lt;/code&gt;
first among them — and that is the right answer rather than a limitation: those traits describe an
operator over two values of one type, which is a question about types known at compile time. They are
for bounds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trait that requires an unerasable one is unerasable itself&lt;/strong&gt;, and the diagnostic names the trait
the offending member came from. A &lt;strong&gt;built-in&lt;/strong&gt; that satisfies a requirement by the compiler’s rule
cannot be erased through it either — a table holds function pointers, and a scalar’s &lt;code&gt;add&lt;/code&gt; is an
instruction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What that bites is the operator catalog at written arguments&lt;/strong&gt;, and only that. &lt;code&gt;Add[int, int]&lt;/code&gt;
declares &lt;code&gt;add(self, rhs: int) -&amp;gt; int&lt;/code&gt; — no &lt;code&gt;Self&lt;/code&gt; anywhere — so it is a formable object type, and an
&lt;code&gt;int&lt;/code&gt; belongs to it by the compiler’s rule; &lt;code&gt;&amp;amp;Add[int, int] = 3&lt;/code&gt; is therefore refused, and the
diagnostic says why rather than reporting a plain mismatch.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Display&lt;/code&gt; and &lt;code&gt;Hash&lt;/code&gt; are not among them&lt;/strong&gt;: every built-in reaches both through an &lt;code&gt;impl&lt;/code&gt;, so a
&lt;code&gt;*Display&lt;/code&gt; carries an &lt;code&gt;int&lt;/code&gt;, a &lt;code&gt;u256&lt;/code&gt;, a &lt;code&gt;string&lt;/code&gt; or a float alike, a &lt;code&gt;&amp;amp;Hash&lt;/code&gt; carries anything that
hashes, and a heterogeneous array of either is ordinary code. The rest of the catalog — &lt;code&gt;Eq&lt;/code&gt;, &lt;code&gt;Ord&lt;/code&gt;,
&lt;code&gt;Bits&lt;/code&gt;, &lt;code&gt;Signed&lt;/code&gt; — names &lt;code&gt;Self&lt;/code&gt; away from the receiver, so object safety refuses the &lt;em&gt;type&lt;/em&gt; before a
value gets that far.&lt;/p&gt;
&lt;h3 id=&quot;forming-and-using-one&quot;&gt;Forming and using one&lt;/h3&gt;
&lt;p&gt;Erasure is a &lt;strong&gt;coercion&lt;/strong&gt;, applied wherever a trait-object type is expected: at an argument, a declared
variable, an assignment, a returned value, an array element, a struct field. &lt;code&gt;&amp;amp;r&lt;/code&gt; erases to &lt;code&gt;*Shape&lt;/code&gt;;
a &lt;code&gt;&amp;amp;Rect&lt;/code&gt; erases to &lt;code&gt;&amp;amp;Shape&lt;/code&gt;; and a plain &lt;code&gt;Rect(3, 4)&lt;/code&gt; where a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; is expected is boxed and then
erased, which is the ordinary “write the construction and it is allocated” rule with one more step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;*Trait&lt;/code&gt; will not take a bare value.&lt;/strong&gt; A raw pointer needs an address, and taking one of a
temporary silently is how a program acquires a dangling pointer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a *Shape points at a value, so it needs an address — write &apos;&amp;amp;&apos; in front of the Rect to take one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the coercion applies &lt;strong&gt;per branch&lt;/strong&gt;, an &lt;code&gt;if&lt;/code&gt; or a &lt;code&gt;match&lt;/code&gt; whose arms are different concrete
types meets at one trait object, which is the point of having them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    s: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Square&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.s * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.s

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; wide &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What an object offers is the trait’s members and nothing else&lt;/strong&gt;: no dereference, no fields, no
comparison.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.w)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &amp;amp;Shape has no fields, and trait &apos;Shape&apos; declares no &apos;w&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A call is checked against the &lt;strong&gt;trait’s&lt;/strong&gt; signature, which stands in for every implementation because
conformance is exact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An object keeps one trait and what that trait requires.&lt;/strong&gt; A bound may name several traits because a
bound is a list; a trait-object type names one because it is a type. So a value implementing &lt;code&gt;Shape&lt;/code&gt;
&lt;em&gt;and&lt;/em&gt; &lt;code&gt;Display&lt;/code&gt; keeps only the first when it becomes a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; — unless &lt;code&gt;Shape&lt;/code&gt; &lt;strong&gt;requires&lt;/strong&gt;
&lt;code&gt;Display&lt;/code&gt;, which is what makes the difference between the object being printable and not. A
multi-trait object type (&lt;code&gt;&amp;amp;(Shape + Display)&lt;/code&gt;) would be a second way to say the same thing and a worse
one, since it puts at every use a fact that belongs on the trait.&lt;/p&gt;
&lt;h3 id=&quot;the-two-sigils-do-not-convert&quot;&gt;The two sigils do not convert&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;*Trait&lt;/code&gt; and &lt;code&gt;&amp;amp;Trait&lt;/code&gt; are two types and neither is accepted for the other.&lt;/p&gt;
&lt;p&gt;In the direction that would matter — lending a counted object to something that only wants to ask it
questions — this is sharper than it is for plain references, which have a spelling for it: &lt;code&gt;&amp;amp;*r&lt;/code&gt; is the
address of the place &lt;code&gt;*r&lt;/code&gt;, so a &lt;code&gt;&amp;amp;T&lt;/code&gt; reaches a function written against &lt;code&gt;*T&lt;/code&gt; with the crossing into the
unsafe tier written down at the call. An object has no dereference, so &lt;code&gt;&amp;amp;*o&lt;/code&gt; says nothing, and a
function that only reads a shape has to exist once per sigil. That is recorded as a gap rather than
settled; what is missing is a spelling, and any spelling must keep the crossing greppable.&lt;/p&gt;
&lt;p&gt;The other direction stays refused for a stronger reason: a raw object points at a value with no count
to take a share of, so accepting one where a counted object is wanted would be &lt;strong&gt;inventing ownership&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;an-object-cannot-be-erased-a-second-time&quot;&gt;An object cannot be erased a second time&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;trait Shape: Display&lt;/code&gt; puts &lt;code&gt;Display&lt;/code&gt;‘s slots in a &lt;code&gt;&amp;amp;Shape&lt;/code&gt;‘s table, and a &lt;code&gt;[T: Display]&lt;/code&gt; bound is
satisfied by the object — but a &lt;code&gt;&amp;amp;Display&lt;/code&gt; is not, and the difference is worth being exact about. A
bound asks what may be &lt;strong&gt;called&lt;/strong&gt; through the value, and the table answers it. Forming an object asks
what may be &lt;strong&gt;assembled&lt;/strong&gt; from the value’s type, and a table is laid out from a type’s
implementations, which an object has none of.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;display_pad&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a rect&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; = o&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &amp;amp;Shape has forgotten which type it holds, so there is nothing for a &amp;amp;sysl.Display to be built from
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Display&lt;/code&gt;‘s members really are in that table — they are laid out inline, so that a required trait’s
method stays the one indirect call the trait’s own methods are. What is missing is a &lt;em&gt;name&lt;/em&gt; for that
run of slots. This is the upcast flattening gives up, and it is the reason it is worth giving up:
every call through a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; costs one indirection instead of two.&lt;/p&gt;
&lt;h3 id=&quot;there-is-no-way-back-to-the-type&quot;&gt;There is no way back to the type&lt;/h3&gt;
&lt;p&gt;An object cannot be asked what it forgot. There is no cast and no test, and the spelling a reader
reaches for first is not one either — a type is not a pattern, so &lt;code&gt;s is Rect&lt;/code&gt; reads &lt;code&gt;Rect&lt;/code&gt; as an
ordinary binding, which matches anything:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this pattern matches every &amp;amp;Shape, so the test is always true — take the value apart with &apos;match&apos;, or bind it with &apos;var&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This is a decision, not an omission.&lt;/strong&gt; A downcast is the one operation that makes erasure a lie:
every other rule here says an object offers the trait’s members and nothing else, and a type test
would say that it also secretly offers its identity, which is what the table pointer is and what the
type deliberately stops promising. Languages that offer it need a whole parallel mechanism to do so,
and that mechanism is the honest price rather than a small addition to this one.&lt;/p&gt;
&lt;p&gt;The cost is real and worth writing down beside the decision. A program that wants to count the circles
in a catalogue has to be told, so it declares a &lt;code&gt;kind&lt;/code&gt; property every implementation answers with a
constant — a hand-maintained copy of exactly the fact the object’s first word already is.&lt;/p&gt;
&lt;h2 id=&quot;reaching-a-trait-s-members-without-a-value&quot;&gt;Reaching a trait’s members without a value&lt;/h2&gt;
&lt;p&gt;A trait may declare a member with &lt;strong&gt;no receiver&lt;/strong&gt; — an associated function — reached through the
&lt;em&gt;type&lt;/em&gt; rather than through a value of one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Zero&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Zero&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Zero&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;T.bits()&lt;/code&gt; inside a generic body, &lt;code&gt;Self.bits()&lt;/code&gt; inside a member’s, and &lt;code&gt;u32.bits()&lt;/code&gt; from anywhere are
the same member reached through three spellings of its type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A built-in may carry one.&lt;/strong&gt; Through a bound the name is the &lt;em&gt;parameter&lt;/em&gt;, which every type has
whether or not it has one of its own — so &lt;code&gt;impl Word for u32&lt;/code&gt; may declare &lt;code&gt;bits()&lt;/code&gt;, and &lt;code&gt;impl Float for real&lt;/code&gt; declares the zero, the one, the epsilon, and the two values no literal spells. What stays
refused is the case the rule was really about: a &lt;strong&gt;composed&lt;/strong&gt; type has no name at all, so an &lt;code&gt;impl&lt;/code&gt; for
&lt;code&gt;[]int&lt;/code&gt; still refuses a member with no receiver.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is static dispatch only, and nothing was added to keep it that way.&lt;/strong&gt; Object safety already
excludes a member with no receiver, because a table slot is selected &lt;em&gt;by&lt;/em&gt; the receiver and there is
nothing here to select with. A trait declaring one is usable as a bound and not as an object, exactly
as one that mentions &lt;code&gt;Self&lt;/code&gt; twice already is.&lt;/p&gt;
&lt;p&gt;One gap the mechanism makes visible: a routine can be entirely &lt;em&gt;about&lt;/em&gt; a type and mention it nowhere in
its signature, and such a function cannot be called, because inference reads the binding and a call
cannot write its type arguments. &lt;code&gt;describe[T: Word]() -&amp;gt; string&lt;/code&gt; is well-formed and unreachable.
Taking a value of &lt;code&gt;T&lt;/code&gt; is the workaround.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/generics/&quot;&gt;generics&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The time module</title>
    <link href="https://sysl.sh/library/time/"/>
    <id>https://sysl.sh/library/time/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.time` — `Instant` and `Duration` kept apart, the proleptic Gregorian calendar, `LocalDate`/`LocalTime`/`LocalDateTime`, the ISO 8601 renderers and the parsers that read them back.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.time&lt;/code&gt; is arithmetic on dates and lengths of time. It is three files and seven types, and almost
everything worth saying about it is a &lt;strong&gt;distinction the type system holds for you&lt;/strong&gt; — a point on the
timeline is not a length of one, and a reading on a wall clock is neither. Every library that blurs
those has the same class of bug in it, and the blur is what the types here refuse.&lt;/p&gt;
&lt;p&gt;It requires no capability: every name below is reachable on a target with no operating system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; launch = &lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; meeting = &lt;span class=&quot;hl-function&quot;&gt;datetime_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(launch), &lt;span class=&quot;hl-function&quot;&gt;weekday_name&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;weekday&lt;/span&gt;(launch)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;datetime_text&lt;/span&gt;(meeting))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;day_of_year&lt;/span&gt;(launch), &lt;span class=&quot;hl-function&quot;&gt;leap_year&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-03-08 Sunday
2026-03-08 09:30
67 false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-two-quantities&quot;&gt;The two quantities&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;// A point on the timeline, counted from 1970-01-01T00:00:00Z.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;
    us: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// A length of timeline, with no place on it.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Duration&lt;/span&gt;
    us: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// How far a zone&apos;s wall clock is set from UTC, in whole minutes.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;
    minutes: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Both are counts of microseconds, and that is the one representation choice worth arguing about.&lt;/strong&gt; A
&lt;code&gt;long&lt;/code&gt; of nanoseconds runs out in 1678–2262 — close enough to today to look fine in every test and
fail on a birth date. A &lt;code&gt;long&lt;/code&gt; of microseconds reaches ±292,000 years. Nothing here needs to resolve
a nanosecond, and &lt;strong&gt;a range that quietly ends is a worse defect than a precision that never begins&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Offset&lt;/code&gt; is minutes rather than hours because India is at +05:30 and Nepal at +05:45, and a library
that assumes whole hours works everywhere its author has lived.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; epoch = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; later = epoch + &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;50i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_days&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;since&lt;/span&gt;(later, epoch)), &lt;span class=&quot;hl-function&quot;&gt;odd_hours&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;since&lt;/span&gt;(later, epoch)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;since&lt;/span&gt;(epoch, later)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(epoch &amp;lt; later, later == epoch + &lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2i64&lt;/span&gt;) + &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2i64&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(-&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3i64&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3i64&lt;/span&gt;) * &lt;span class=&quot;hl-number&quot;&gt;4i64&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 2
-50
true true
-3 12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Which operations exist is the whole design.&lt;/strong&gt; An instant may be compared with an instant,
subtracted from one, and moved by a duration. Two instants may not be added, because the sum of two
points on a timeline is not a point on it — and asking for one says so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;since&lt;/span&gt;(a + b, a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; between sysl.time.Instant and sysl.time.Instant needs &apos;sysl.Add&apos; — it implements &apos;sysl.Add[sysl.time.Duration]&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That diagnostic is exact about what went wrong: &lt;code&gt;Instant&lt;/code&gt; &lt;em&gt;does&lt;/em&gt; implement &lt;code&gt;Add&lt;/code&gt;, at &lt;code&gt;Duration&lt;/code&gt;, and
this call asked for it at &lt;code&gt;Instant&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-difference-of-two-instants-is-the-operator&quot;&gt;The difference of two instants is the operator&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a + &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(b - a))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(a - b))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
-3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Two rows of &lt;code&gt;Sub&lt;/code&gt; sit on &lt;code&gt;Instant&lt;/code&gt;, and the type of the right operand is the whole of what selects
between them.&lt;/strong&gt; Subtracting a &lt;code&gt;Duration&lt;/code&gt; lands further along the timeline and answers an &lt;code&gt;Instant&lt;/code&gt;;
subtracting an &lt;code&gt;Instant&lt;/code&gt; measures across it and answers a &lt;code&gt;Duration&lt;/code&gt;. An operator trait carries its
result as &lt;code&gt;Out&lt;/code&gt; as well as its operand as &lt;code&gt;Rhs&lt;/code&gt;, which is what lets one type do both — the same
mechanism &lt;a href=&quot;/reference/expressions/&quot;&gt;&lt;code&gt;Mul&lt;/code&gt; uses&lt;/a&gt; to give a vector space four products.&lt;/p&gt;
&lt;p&gt;This section used to be this module’s report against the language: the most frequently written
operation in any date-time library could not be spelled with its own operator, because &lt;code&gt;Sub&lt;/code&gt;‘s result
was fixed to the type on the left. That is what &lt;code&gt;Out&lt;/code&gt; answered, and the gap it describes is closed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;since(later, earlier)&lt;/code&gt; is still here and is the same subtraction under a name that says which end is
which — &lt;code&gt;later - earlier&lt;/code&gt; is right and &lt;code&gt;earlier - later&lt;/code&gt; is just as easy to write, as the second line
above shows.&lt;/p&gt;
&lt;h3 id=&quot;reading-a-duration-back&quot;&gt;Reading a duration back&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;50i64&lt;/span&gt;) + &lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7i64&lt;/span&gt;) + &lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;30i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_days&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;odd_hours&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;odd_minutes&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;odd_seconds&lt;/span&gt;(d))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;whole_minutes&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;whole_seconds&lt;/span&gt;(d))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;90i64&lt;/span&gt;) == &lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1i64&lt;/span&gt;) + &lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;30i64&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_minutes&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1i64&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 2 7 30
50 3007 180450
true
1440
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Two families, and the difference between them is the whole reason both exist.&lt;/strong&gt; &lt;code&gt;whole_hours&lt;/code&gt; is
the duration &lt;em&gt;in&lt;/em&gt; hours — fifty of them. &lt;code&gt;odd_hours&lt;/code&gt; is the hours &lt;em&gt;left over&lt;/em&gt; after the whole days —
two. A caller stating a length to somebody who has to check it wants the first row; a caller
formatting one wants the second, and getting them confused is how &lt;code&gt;2 days, 50 hours&lt;/code&gt; gets printed.&lt;/p&gt;
&lt;p&gt;Both truncate toward zero, so a negative duration reads as a negative count of each part rather than
borrowing across them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;days(1)&lt;/code&gt; is a length of exactly 24 hours, and it is not “a day”.&lt;/strong&gt; A day that a zone’s clocks move
through is 23 or 25 hours long, so a calendar day is not a fixed length of timeline at all. That
question belongs to the civil types below, which is why &lt;code&gt;plus_days&lt;/code&gt; is theirs and not a &lt;code&gt;Duration&lt;/code&gt;‘s.&lt;/p&gt;
&lt;h3 id=&quot;below-the-second&quot;&gt;Below the second&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;millis&lt;/code&gt; and &lt;code&gt;micros&lt;/code&gt; construct, &lt;code&gt;whole_millis&lt;/code&gt; and &lt;code&gt;whole_micros&lt;/code&gt; read back. The representation is
microseconds, so those are the shortest lengths this module can name — and they are the two an
embedded program reaches for, since a blink loop wants 120 milliseconds and &lt;code&gt;seconds(1)&lt;/code&gt; is not it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;millis&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;120i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_millis&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;whole_micros&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;whole_seconds&lt;/span&gt;(d))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_micros&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;micros&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7i64&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;120 120000 0
7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All three numbers on that first row are true of one length: it is a hundred and twenty milliseconds,
and it is no seconds at all.&lt;/p&gt;
&lt;p&gt;Scaling reads one way round only:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_seconds&lt;/span&gt;(d * &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2i64&lt;/span&gt; * d))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;*&apos; needs matching types, got long and sysl.time.Duration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;d * 3&lt;/code&gt; is what is written instead, and the count is an ordinary literal — a bare number beside a
duration takes the &lt;code&gt;long&lt;/code&gt; the one &lt;code&gt;impl Mul&lt;/code&gt; names rather than the &lt;code&gt;int&lt;/code&gt; a literal with nothing to
take would fall back to. An operator’s implementation is written for the type on its &lt;strong&gt;left&lt;/strong&gt;, and
nothing may be written for &lt;code&gt;long&lt;/code&gt;, so the commutativity a reader expects of multiplication is not
something this module could have supplied.&lt;/p&gt;
&lt;h3 id=&quot;writing-a-duration-number-first&quot;&gt;Writing a duration number-first&lt;/h3&gt;
&lt;p&gt;Every unit is also a property on any integer, so a length can be written the way a datasheet writes
one — the number, then the unit:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;property&lt;/th&gt;&lt;th&gt;the constructor it mirrors&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.us&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;micros(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.ms&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;millis(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;seconds(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.minutes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;minutes(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.hours&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;hours(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;5.days&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;days(5)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_millis&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;250&lt;/span&gt;.ms), &lt;span class=&quot;hl-function&quot;&gt;whole_micros&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;250&lt;/span&gt;.ms))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;.hours + &lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;.minutes), &lt;span class=&quot;hl-function&quot;&gt;odd_minutes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;.hours + &lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;.minutes))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_millis&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;250&lt;/span&gt;.ms * &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;250 250000
3 30
1000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The short units are symbols and the long ones are words&lt;/strong&gt;, which is a split about where each is
used rather than a compromise. A timeout, a poll interval and a debounce are the sub-second end, they
are written constantly, and &lt;code&gt;ms&lt;/code&gt; is the spelling every datasheet already uses — &lt;code&gt;sleep(5.ms)&lt;/code&gt; and
&lt;code&gt;join(ssid, pw, auth, 20.s)&lt;/code&gt; say at a glance what &lt;code&gt;millis(5)&lt;/code&gt; and &lt;code&gt;seconds(20)&lt;/code&gt; say a moment later.
At the other end the number is small and the line is not dense, so &lt;code&gt;30.days&lt;/code&gt; costs nothing and says
more than &lt;code&gt;30.d&lt;/code&gt; would.&lt;/p&gt;
&lt;p&gt;There is deliberately no &lt;code&gt;5.min&lt;/code&gt;: it would sit beside &lt;code&gt;sysl.math&lt;/code&gt;‘s &lt;code&gt;min(a, b)&lt;/code&gt; and the type-level
&lt;code&gt;int::Min&lt;/code&gt;, meaning something different in each position.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The constructors stay, and the two spellings are not a duplication.&lt;/strong&gt; A duration built from a
&lt;em&gt;computed&lt;/em&gt; value reads better as &lt;code&gt;millis(n)&lt;/code&gt; than as &lt;code&gt;n.millis&lt;/code&gt;, and the free functions are what most
code that takes a length as an argument is written against.&lt;/p&gt;
&lt;p&gt;The properties are one blanket implementation over the whole integer family, so a receiver narrower
than the representation widens on the way in rather than overflowing at its own width:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;whole_micros&lt;/span&gt;(n.ms))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;200000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A selective import has to name the trait&lt;/strong&gt;, which is the one place &lt;code&gt;DurationUnits&lt;/code&gt; is written down
by anybody using it — a member is reached through the trait that declares it, so importing &lt;code&gt;millis&lt;/code&gt;
does not bring &lt;code&gt;ms&lt;/code&gt; along with it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.{&lt;span class=&quot;hl-type&quot;&gt;Duration&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;DurationUnits&lt;/span&gt;, whole_micros}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import sysl.time.*&lt;/code&gt; needs nothing said.&lt;/p&gt;
&lt;p&gt;There is no matching set for &lt;code&gt;Instant&lt;/code&gt;. A point on the timeline has no natural &lt;code&gt;5.&amp;lt;unit&amp;gt;&lt;/code&gt; — five of
what, from when? — so naming one still means saying which epoch it is counted from.&lt;/p&gt;
&lt;h2 id=&quot;the-calendar&quot;&gt;The calendar&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;// Proleptic Gregorian — the Gregorian rules run backwards through the years before anybody&lt;/span&gt;
&lt;span class=&quot;hl-comment&quot;&gt;// agreed to them.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Civil&lt;/span&gt;
    year: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    month: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    day: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// Days since 1970-01-01, signed.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;LocalDate&lt;/span&gt;
    day: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// Microseconds since midnight.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;LocalTime&lt;/span&gt;
    us: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;LocalDateTime&lt;/span&gt;
    date: &lt;span class=&quot;hl-type&quot;&gt;LocalDate&lt;/span&gt;
    time: &lt;span class=&quot;hl-type&quot;&gt;LocalTime&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A day number, not packed civil fields.&lt;/strong&gt; Year, month, day, hour and minute as bit fields inside one
word is the design most people reach for, and the arithmetic says no: packing to the nanosecond needs
30 bits for the nanosecond, 17 for the time of day and 9 for the day and month, which is 56 — leaving
8 bits of year, a range of ±128 years, which is not a calendar. A &lt;em&gt;count&lt;/em&gt; fits more comfortably at
the same width and costs nothing to compute with, because comparing, subtracting and adding a length
of time are one instruction each on a count and an unpack-recompute-repack on packed fields. Only
“what month is it” wants the fields, and that is the rare question — paid for where it is asked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proleptic Gregorian is a decision and not an oversight.&lt;/strong&gt; The alternative is a calendar with a
ten-day hole in it whose position depends on which country you ask.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;year_of&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;month_of&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;day_of&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;month_name&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;month_of&lt;/span&gt;(d)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;day_of_year&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;weekday_name&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;weekday&lt;/span&gt;(d)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;days_in_month&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;days_in_month&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;leap_year&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2000&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;leap_year&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1900&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;leap_year&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1970&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).day, &lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1969&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;31&lt;/span&gt;).day)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;weekday_name&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;weekday&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1970&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026 3 8 March
67 Sunday
28 29
true false true
0 -1
Thursday
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Dates before the epoch are ordinary values rather than a special case.&lt;/strong&gt; The day number is signed
and &lt;a href=&quot;https://howardhinnant.github.io/date_algorithms.html&quot;&gt;Hinnant’s civil-from-days algorithm&lt;/a&gt; never
branches on it — it shifts the epoch to the start of a 400-year era, after which every quantity is
non-negative and each leap rule becomes one exact division. &lt;code&gt;days_from_civil&lt;/code&gt; and &lt;code&gt;civil_from_days&lt;/code&gt;
are inverse over the whole &lt;code&gt;int&lt;/code&gt; range, which is the property worth asserting rather than any
particular date.&lt;/p&gt;
&lt;p&gt;The weekday falls out of the same count: 1970-01-01 was a Thursday, so shifting by four puts Sunday
at zero. Nothing here needs to know which day a week starts on.&lt;/p&gt;
&lt;h3 id=&quot;adding-to-a-calendar&quot;&gt;Adding to a calendar&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;plus_months&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;31&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;plus_months&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;31&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;plus_years&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;29&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;on_or_after&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Tuesday&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;datetime_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;plus_days&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;datetime_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-02-28
2024-02-29
2025-02-28
2026-03-10
2026-03-15 09:30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Months are added by the calendar rather than by counting days, and the day is clamped where the
target month is shorter.&lt;/strong&gt; The 31st of January plus one month is the 28th or the 29th of February,
whichever that year has. Every library that offers this makes the choice, and clamping is the one
that keeps “the last day of the month” landing on a last day. &lt;code&gt;plus_years&lt;/code&gt; is &lt;code&gt;plus_months&lt;/code&gt; by
twelve, which is what makes the 29th of February behave on a non-leap year without a rule of its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;plus_days&lt;/code&gt; on a wall clock reading is not adding a length of time to it.&lt;/strong&gt; Seven days later is the
same clock face seven rows down the calendar, whatever the timeline did in between; across a change
of a zone’s clocks the two answers differ by an hour. Both are right — they answer different
questions, which is why they are spelled differently. And why this is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_text&lt;/span&gt;(d + &lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1i64&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got sysl.time.LocalDate and sysl.time.Duration
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;on_or_after&lt;/code&gt; is the first date on or after a given one falling on a given weekday, which is what
“every Tuesday” means once a rule has been given a starting point.&lt;/p&gt;
&lt;h3 id=&quot;rendering&quot;&gt;Rendering&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-function&quot;&gt;time_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;date_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;time_text&lt;/span&gt;(t), &lt;span class=&quot;hl-function&quot;&gt;time_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;time_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;time_text&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;LocalTime&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;500000i64&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;datetime_at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;offset_text&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;330&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;offset_text&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;480&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;offset_text&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-03-08
09:30:07 09:30 00:00:00.500000
2026-03-08 09:30
+05:30 -08:00 Z
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All five types implement &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Display&lt;/code&gt;&lt;/a&gt;, so a value goes straight into a &lt;code&gt;print&lt;/code&gt; or an
interpolation; the &lt;code&gt;*_text&lt;/code&gt; functions are the same renderers reached by name, for a caller that wants
the string.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Seconds appear only when there are any.&lt;/strong&gt; A meeting at half past nine is written &lt;code&gt;09:30&lt;/code&gt; by every
human being who has ever written one down, and a renderer insisting on &lt;code&gt;09:30:00&lt;/code&gt; is reporting its
representation rather than its value. The microseconds appear on the same terms — and a renderer that
showed a value to the second while dropping what is below it would be reporting something the value
does not say.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Z&lt;/code&gt; for a zero offset is a spelling rather than a special case: ISO 8601 writes it that way, and
&lt;code&gt;parse_offset&lt;/code&gt; reads it back as zero.&lt;/p&gt;
&lt;h2 id=&quot;reading-text-back&quot;&gt;Reading text back&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;// Why a parse refused, at the granularity a caller can act on.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;TimeParseError&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;BadShape&lt;/span&gt;(at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;OutOfRange&lt;/span&gt;(what: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Trailing&lt;/span&gt;(at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-function&quot;&gt;parse_date&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-08&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(d) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_time&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;09:30&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_time&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;09:30:07.5&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_datetime&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-08T09:30&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(x) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_datetime&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-08 09:30:07&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(x) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_offset&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;+05:30&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(o) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(o)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-03-08
09:30
09:30:07.500000
2026-03-08 09:30
2026-03-08 09:30:07
+05:30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One format, and it is ISO 8601.&lt;/strong&gt; Not a pattern language, not a locale, not a list of alternatives
tried in turn — &lt;code&gt;YYYY-MM-DD&lt;/code&gt;, &lt;code&gt;HH:MM[:SS[.ffffff]]&lt;/code&gt;, and the two joined by a space or a &lt;code&gt;T&lt;/code&gt;. That is
the format the renderers above produce, so &lt;strong&gt;the pair round-trips&lt;/strong&gt;, and it is the format every
machine-readable timestamp in the world is already written in. A pattern language is a bigger feature
than this module and belongs above it.&lt;/p&gt;
&lt;p&gt;Both join characters are read because both are written: ISO 8601 says &lt;code&gt;T&lt;/code&gt;, and &lt;code&gt;datetime_text&lt;/code&gt; writes
a space because that is what a person reads.&lt;/p&gt;
&lt;p&gt;A fraction of fewer than six digits means what it says — &lt;code&gt;.5&lt;/code&gt; is half a second, not five
microseconds.&lt;/p&gt;
&lt;h3 id=&quot;what-a-parse-refuses&quot;&gt;What a parse refuses&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-function&quot;&gt;parse_date&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-02-30&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(d) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_date&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-13-01&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(d) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_date&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026/03/08&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(d) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_date&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-08T&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(d) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;parse_time&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;24:00&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;refused: day is out of range
refused: month is out of range
refused: not the expected shape at byte 4
refused: unexpected text at byte 10
refused: hour is out of range
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A parse checks the calendar, not only the shape&lt;/strong&gt;, and the first line is the whole reason to say
so. &lt;code&gt;2026-02-30&lt;/code&gt; is four digits, a dash, two digits, a dash and two digits — it is exactly the right
shape and it is not a date. Without holding the day against the month’s real length, the civil
conversion accepts it silently and hands back the 2nd of March, which is the failure mode a caller
has no way to notice.&lt;/p&gt;
&lt;p&gt;The three cases are separated by &lt;strong&gt;what a caller would do about them&lt;/strong&gt;. A shape error is a message
about the format; a range error is a message about the value; a trailing error usually means the text
held something more that the caller meant to split off first. &lt;code&gt;BadShape&lt;/code&gt; and &lt;code&gt;Trailing&lt;/code&gt; carry a byte
offset for the reason &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;BadDigit&lt;/code&gt; carries one: a message naming where
is worth writing and cannot be reconstructed afterwards.&lt;/p&gt;
&lt;h2 id=&quot;a-fixed-offset-which-is-not-a-zone&quot;&gt;A fixed offset, which is not a zone&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1772548200000000i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;at_offset&lt;/span&gt;(t, &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;at_offset&lt;/span&gt;(t, &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;330&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_offset&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;at_offset&lt;/span&gt;(t, &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;)), &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;)) == t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;timestamp_text&lt;/span&gt;(t, &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;timestamp_text&lt;/span&gt;(t, &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;timestamp_text&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1772548200500000i64&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Offset&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-03-03 09:30
2026-03-03 20:00
true
2026-03-03T09:30:00-05:00
2026-03-03T14:30:00Z
2026-03-03T09:30:00.500000-05:00
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Both directions are total, and that is the whole difference between an offset and a zone.&lt;/strong&gt; An
offset is a number; a zone is a rule with a history. Ask a zone what instant a wall clock reading
names and the honest answers are &lt;em&gt;one&lt;/em&gt;, &lt;em&gt;none&lt;/em&gt; and &lt;em&gt;two&lt;/em&gt; — the hour a spring-forward deletes has no
instant in it, and the hour an autumn-back repeats has two. Ask an offset and there is exactly one,
always, which is why this pair is a pair of plain functions and a zone conversion could never be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Most programs that handle timestamps need only this.&lt;/strong&gt; A timestamp on a wire, in a log line or in
a database column already carries the offset that was in force when it was written: the sender
resolved the zone, and what arrived is the record of that decision. Reading one back needs no table,
no update cadence and no filesystem — which is exactly what makes it the library’s business, where
the zone is not.&lt;/p&gt;
&lt;h3 id=&quot;the-renderer-is-written-for-machines-and-it-is-the-odd-one-out&quot;&gt;The renderer is written for machines, and it is the odd one out&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;timestamp_text&lt;/code&gt; breaks two of this page’s own rules, on purpose. The seconds are present even at
zero, where &lt;a href=&quot;#rendering&quot;&gt;&lt;code&gt;datetime_text&lt;/code&gt; drops them&lt;/a&gt;; the date and time are joined by a &lt;code&gt;T&lt;/code&gt; rather
than a space; and the offset is flush against the time.&lt;/p&gt;
&lt;p&gt;That is &lt;strong&gt;RFC 3339&lt;/strong&gt;, the profile of ISO 8601 that JSON APIs, logs and databases actually agree on,
and it &lt;em&gt;requires&lt;/em&gt; the seconds. The rule that a renderer should not report what a value does not say
is the right rule for a person glancing at a meeting time and exactly the wrong one for a parser
with a grammar — so the two renderers are two renderers. The fraction is still omitted when it is
zero, because RFC 3339 makes that part optional and &lt;code&gt;.000000&lt;/code&gt; on every timestamp is six characters
of noise on the wire.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1772548200000000i64&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T09:30:00-05:00&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)) == t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03 09:30-05:00&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)) == t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T14:30:00Z&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)) == t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T20:00:00+05:30&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Instant&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i64&lt;/span&gt;)) == t)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The parser reads more shapes than the renderer writes.&lt;/strong&gt; It takes the space as well as the &lt;code&gt;T&lt;/code&gt;,
and a time with no seconds as well as one with them, because what arrives was written by somebody
else — while the renderer emits one form, because a wire format with options is a wire format
everybody implements differently. Liberal in what it accepts, strict in what it sends.&lt;/p&gt;
&lt;p&gt;All four of those lines name the same point on the timeline, which is the point: the offset is not
decoration on the reading, it is what turns the reading into an instant.&lt;/p&gt;
&lt;h3 id=&quot;an-offset-is-not-optional&quot;&gt;An offset is not optional&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T09:30:00&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;()))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T09:30:00-25:00&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;()))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_timestamp&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2026-03-03T09:30:00Z &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;()))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;not the expected shape at byte 19
offset hour is out of range
unexpected text at byte 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A date and a time with no offset name a &lt;strong&gt;wall clock reading&lt;/strong&gt;, not an instant, and
&lt;code&gt;parse_datetime&lt;/code&gt; is what reads one of those. Defaulting the missing offset to UTC would be inventing
the fact the format exists to carry, and it is the single most common way a timestamp ends up hours
wrong in a system that never notices.&lt;/p&gt;
&lt;h2 id=&quot;reading-a-clock-sysl-posix-time&quot;&gt;Reading a clock — &lt;code&gt;sysl.posix.time&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Everything above is arithmetic, and arithmetic needs a value to start from. Obtaining one is asking
the environment what time it is, so it is a &lt;strong&gt;module of its own&lt;/strong&gt; — the same split
&lt;a href=&quot;/library/rand/&quot;&gt;&lt;code&gt;sysl.rand&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;sysl.posix.rand&lt;/code&gt; make, and for the same mechanical reason: a
capability requirement is module-wide, so a &lt;code&gt;now()&lt;/code&gt; written beside &lt;code&gt;Instant&lt;/code&gt; would take the whole
calendar away from every freestanding program that only wanted to add two durations.&lt;/p&gt;
&lt;p&gt;There are two clocks, and the return types are the distinction rather than a detail.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.time.{now, monotonic}

&lt;span class=&quot;hl-comment&quot;&gt;// The wall clock: a point on the timeline, comparable with one taken on another machine.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;now&lt;/span&gt;().us &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;1577836800000000&lt;/span&gt;)

&lt;span class=&quot;hl-comment&quot;&gt;// The monotonic clock: a length of time from an origin nobody specifies.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t0 = &lt;span class=&quot;hl-function&quot;&gt;monotonic&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;200000&lt;/span&gt;
    n = n * &lt;span class=&quot;hl-number&quot;&gt;31&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;(i)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; took = &lt;span class=&quot;hl-function&quot;&gt;monotonic&lt;/span&gt;() - t0

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(took.us &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n != &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;now&lt;/code&gt; answers an &lt;strong&gt;&lt;code&gt;Instant&lt;/code&gt;&lt;/strong&gt; — a point counted from 1970, which is the one to stamp something with.
It is also the clock a person and an &lt;code&gt;ntpd&lt;/code&gt; are both allowed to &lt;em&gt;set&lt;/em&gt;, so two readings of it can
differ by anything at all, including a negative amount.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;monotonic&lt;/code&gt; answers a &lt;strong&gt;&lt;code&gt;Duration&lt;/code&gt;&lt;/strong&gt;, not an &lt;code&gt;Instant&lt;/code&gt;, and that is the whole of the design. It is
counted from an origin the module deliberately does not name — boot, usually — so a single reading
means nothing and only the difference of two does. It cannot be set and never goes backwards, which
is what makes it the one to measure with. Giving it a type that no calendar function accepts is what
stops a measurement being mistaken for a timestamp:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.time.monotonic
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.time.instant_text

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;instant_text&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;monotonic&lt;/span&gt;()))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;error: &apos;t&apos; of &apos;sysl.time.instant_text&apos; is sysl.time.Instant, but sysl.time.Duration was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both require &lt;code&gt;posix&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-a-freestanding-target-does-instead&quot;&gt;What a freestanding target does instead&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Nothing in the library, and deliberately nothing shared with it.&lt;/strong&gt; A board’s clock is a board’s
decision: two boards carrying the same chip — so the same &lt;em&gt;target&lt;/em&gt; — can count time from a different
RTC, which is precisely the case a compile-time switch on the target cannot express. So an embedded
environment supplies a module of its own with these two function names, in its own package, and a
program picks its clock by which one it imports.&lt;/p&gt;
&lt;p&gt;What that gives up, for now, is a program that compiles unchanged against both a host clock and a
board’s. The shape that would buy it is a symbol declared in capability-free &lt;code&gt;sysl.time&lt;/code&gt; that a host
module and a board package alike link an implementation of — &lt;a href=&quot;/library/harness/&quot;&gt;&lt;code&gt;sysl.harness&lt;/code&gt;&lt;/a&gt;‘s
&lt;code&gt;attach&lt;/code&gt; one layer down — and it is not built, for want of a second thing that needs it. The names
above are chosen so that adding it later moves no caller.&lt;/p&gt;
&lt;h2 id=&quot;what-is-not-here&quot;&gt;What is not here&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The zone&lt;/strong&gt;, as distinct from the offset above. A wall clock reading becomes an instant only once
somebody says where the wall is, and answering that from a &lt;em&gt;name&lt;/em&gt; — &lt;code&gt;America/New_York&lt;/code&gt; rather than
&lt;code&gt;-05:00&lt;/code&gt; — needs the IANA time zone database — a table that changes several times a year, which a
standard library either ships and lets go stale or reads from the host and thereby needs a
filesystem. Both are decisions with costs, and neither belongs in a module whose whole claim is that
it is arithmetic. The &lt;a href=&quot;/guides/datetime/&quot;&gt;date and time guide&lt;/a&gt; builds a fixed-offset zone over this
module and shows what the real thing would take.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;wall_us&lt;/code&gt; and &lt;code&gt;wall_of&lt;/code&gt; are the seam a zone conversion starts from: they read a &lt;code&gt;LocalDateTime&lt;/code&gt; as a
single count measured from the same origin as an &lt;code&gt;Instant&lt;/code&gt;, which is what the count would be if the
offset happened to be zero.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The clock&lt;/strong&gt;, in &lt;em&gt;this&lt;/em&gt; module. There is no &lt;code&gt;sysl.time.now()&lt;/code&gt;, because reading one is a capability
rather than arithmetic — &lt;code&gt;clock_gettime&lt;/code&gt; is a call into the environment, and this module has no
&lt;code&gt;requires&lt;/code&gt; line. An &lt;code&gt;Instant&lt;/code&gt; is a value a freestanding target can compute with; where it comes from
is the caller’s to say, and on a host the answer is &lt;a href=&quot;#reading-a-clock-sysl-posix-time&quot;&gt;&lt;code&gt;sysl.posix.time&lt;/code&gt;&lt;/a&gt;
above.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/sync/&quot;&gt;&lt;code&gt;sysl.sync&lt;/code&gt;&lt;/a&gt; — atomics and the spinlock, which require nothing at all.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sysl.posix.threads</title>
    <link href="https://sysl.sh/library/threads/"/>
    <id>https://sysl.sh/library/threads/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Starting a thread, waiting for one, and the mutex above the spinlock — the half of concurrency that needs a scheduler.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt; is where the capability lands. Everything on the &lt;a href=&quot;/library/sync/&quot;&gt;&lt;code&gt;sysl.sync&lt;/code&gt;&lt;/a&gt; page is
reachable from a module that has given up its allocator and its operating system; nothing here is,
because creating a thread needs a scheduler underneath it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_posix&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.spawn

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this reaches &apos;sysl.posix.threads&apos;, which requires &apos;posix&apos;, and this module declared &apos;no posix&apos; — an environment capability gates which modules exist, so a module that gave one up may not reach one that needs it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note where that lands: &lt;strong&gt;at the import&lt;/strong&gt;, not at the call. A capability a module has given up decides
which modules exist for it, so a program that cannot spawn is a program whose author never sees the
name — and the &lt;code&gt;sysl.sync&lt;/code&gt; import on the line above is untouched, which is the split working exactly
as it is meant to.&lt;/p&gt;
&lt;p&gt;The module declares &lt;strong&gt;one&lt;/strong&gt; requirement, and the namespace it sits in says the same thing twice over:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module sysl.posix.threads
@requires(posix)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What is here is pthreads&lt;/strong&gt;, which is the whole claim and the reason the module lives under
&lt;code&gt;sysl.posix&lt;/code&gt; beside &lt;a href=&quot;/library/term/#taking-the-terminal-over-sysl-posix-tty-raw&quot;&gt;&lt;code&gt;sysl.posix.tty&lt;/code&gt;&lt;/a&gt; and
&lt;a href=&quot;/library/rand/&quot;&gt;&lt;code&gt;sysl.posix.rand&lt;/code&gt;&lt;/a&gt;. A module in that namespace is one a freestanding target does not
get, and the path is enough to know it without opening the file.&lt;/p&gt;
&lt;p&gt;There was a fourth capability, &lt;code&gt;threads&lt;/code&gt;, and it was &lt;strong&gt;removed rather than renamed&lt;/strong&gt;. It gated this
one module, and it read as a claim that the compiler tracks whether a scheduler exists — which it
does not, and which nothing in the library was gated on. &lt;strong&gt;A board running FreeRTOS or Zephyr has
threads and no POSIX&lt;/strong&gt;: it does not reach this module, and it binds its own kernel as a package,
because no capability could have made &lt;code&gt;pthread_create&lt;/code&gt; appear on it. So &lt;code&gt;@no_threads&lt;/code&gt; is now an
unknown capability, and the three that remain are &lt;code&gt;heap&lt;/code&gt;, &lt;code&gt;os&lt;/code&gt; and &lt;code&gt;posix&lt;/code&gt;.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;spawn(body, arg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;starts a thread, answering &lt;code&gt;Option[Thread]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Thread.join&lt;/code&gt;&lt;/td&gt;&lt;td&gt;waits for one, answering whether it waited&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;current()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the calling thread’s own handle&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yield_now()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;offers the processor away — a hint, not a wait&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Mutex[T]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;mutual exclusion that owns what it protects&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;spawn-takes-an-address-not-a-callable&quot;&gt;&lt;code&gt;spawn&lt;/code&gt; takes an address, not a callable&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Job&lt;/span&gt;
    input: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    output: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Job&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(j: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Job&lt;/span&gt;)
    j.output = j.input * j.input

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; job = &lt;span class=&quot;hl-type&quot;&gt;Job&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;square, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;job).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

t.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(job.input, job.output)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12 144
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;square&lt;/code&gt; is the address of a named function, and the parameter’s type is &lt;code&gt;*extern(*T) -&amp;gt; unit&lt;/code&gt; —
C’s own shape, because &lt;code&gt;pthread_create&lt;/code&gt; is underneath. &lt;strong&gt;A closure will not do&lt;/strong&gt;, and the refusal is
worth seeing in both of the ways a reader will hit it. Written bare, the argument has nothing to
infer its parameter type from, because &lt;code&gt;T&lt;/code&gt; is what is being inferred:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(a -&amp;gt; a.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;a&apos; has no type here — nothing says what this closure takes, so write it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Write the type in and the real mismatch surfaces:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;((a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;]) -&amp;gt; a.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;body&apos; of &apos;sysl.posix.threads.spawn&apos; is *extern(*sysl.sync.Atomic[int]) -&amp;gt; unit, but a closure was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two reasons, and neither is a limitation waiting to be lifted. A closure would have to be &lt;strong&gt;boxed&lt;/strong&gt;
for the new thread to reach it, which needs an allocator this module could otherwise do without; and
its &lt;strong&gt;captures&lt;/strong&gt; would be values crossing a domain boundary through a box whose shape says nothing
about what is in it. The address of a named function has neither problem, and what travels beside it
is an ordinary parameter — which is what lets the crossing rule be asked at all.&lt;/p&gt;
&lt;h3 id=&quot;a-body-with-nothing-to-read-is-passed-null&quot;&gt;A body with nothing to read is passed &lt;code&gt;null&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt; is generic in what the body reads, so &lt;code&gt;T&lt;/code&gt; is inferred from the body and the &lt;code&gt;ptr_cast&lt;/code&gt; to
C’s shape happens once, inside. A body with nothing of its own writes &lt;code&gt;null&lt;/code&gt;, and the type it would
otherwise have had to invent is one the &lt;em&gt;body’s&lt;/em&gt; own signature already gave:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-function&quot;&gt;quiet&lt;/span&gt;(state: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nothing to read&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;quiet, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;nothing to read
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; has no type of its own, so at a parameter still being solved it is set aside until the
arguments that have one are read — here the &lt;code&gt;&amp;amp;quiet&lt;/code&gt;, whose &lt;code&gt;*extern(*int) -&amp;gt; unit&lt;/code&gt; says &lt;code&gt;T&lt;/code&gt; is
&lt;code&gt;int&lt;/code&gt;. It is refused only where &lt;em&gt;nothing&lt;/em&gt; says: a call with no other argument to read is an error
asking for the type rather than a guess.&lt;/p&gt;
&lt;h3 id=&quot;join-does-not-carry-the-result-back&quot;&gt;&lt;code&gt;join&lt;/code&gt; does not carry the result back&lt;/h3&gt;
&lt;p&gt;It answers a &lt;code&gt;bool&lt;/code&gt; — whether it waited — and nothing else. That is the crossing rule rather than an
oversight: &lt;strong&gt;a result coming out of another domain is a value crossing a boundary&lt;/strong&gt;, which is what a
channel is for, and the channel is not written. So a body that has something to say writes it
through the address it was given, which is what the &lt;code&gt;Job&lt;/code&gt; above does.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Thread&lt;/code&gt; value is a &lt;strong&gt;handle rather than the thread&lt;/strong&gt;. Copying one copies the handle, and
joining either copy joins the one thread; joining &lt;strong&gt;twice&lt;/strong&gt; is undefined in POSIX and is not checked
here, for the same reason &lt;code&gt;SpinLock.unlock&lt;/code&gt; checks nothing — the word it would take to notice is
paid by every correct program. The &lt;code&gt;id&lt;/code&gt; field is public so that a program can hand it to a POSIX
call this module does not wrap, such as &lt;code&gt;pthread_detach&lt;/code&gt; or a scheduling parameter, since the
alternative is a wrapper per call.&lt;/p&gt;
&lt;h2 id=&quot;sharing-the-thing-at-the-address&quot;&gt;Sharing the thing at the address&lt;/h2&gt;
&lt;p&gt;The pointer &lt;em&gt;is&lt;/em&gt; the sharing. Two threads reading and writing what is at that address is a data race
unless something orders them, and the two things that order them are on the
&lt;a href=&quot;/library/sync/&quot;&gt;&lt;code&gt;sysl.sync&lt;/code&gt;&lt;/a&gt; page.&lt;/p&gt;
&lt;h3 id=&quot;what-may-be-at-that-address&quot;&gt;What may be at that address&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;spawn&lt;/code&gt; is declared &lt;code&gt;@crossing(arg)&lt;/code&gt;, which is how a facility says a parameter hands a value to
another concurrency domain (&lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt;). It is why the state a thread is given is
&lt;strong&gt;checked&lt;/strong&gt; rather than taken on trust: a raw pointer carries no refcount of its own, and the
annotation is what asks the compiler to look through it at the object that actually crossed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cell&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;
    cell: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; State&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;look&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.cell.n)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; st = &lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;(c)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;look, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;st).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;what &apos;arg&apos; of &apos;sysl.posix.threads.spawn&apos; points at reaches another concurrency domain, so every count inside it has to be atomic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A plain &lt;code&gt;&amp;amp;Cell&lt;/code&gt; has a &lt;strong&gt;non-atomic&lt;/strong&gt; count, so two threads retaining it is exactly the race the model
exists to prevent — and until the annotation existed, this program compiled and ran. Writing
&lt;code&gt;&amp;amp;sync Cell&lt;/code&gt; in the field and at the allocation is the whole fix: the count becomes atomic, and the
same program is accepted.&lt;/p&gt;
&lt;p&gt;Nothing here is special to this module. A package binding FreeRTOS or Zephyr writes the same line
above the wrapper it already has, and gets the same refusal at its own callers’ calls.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;])
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;10000&lt;/span&gt;
        a.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t1 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;bump, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t2 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;bump, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; j1 = t1.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; j2 = t2.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(j1, j2)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counter.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true
20000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;SpinLock&lt;/code&gt; works across real threads exactly as it does in the single-threaded program on the
other page, and this is where its “guards nothing by construction” becomes concrete — the lock is a
field beside the data, and remembering that &lt;code&gt;total&lt;/code&gt; is what &lt;code&gt;guard&lt;/code&gt; guards is the programmer’s job:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shared&lt;/span&gt;
    guard: &lt;span class=&quot;hl-type&quot;&gt;SpinLock&lt;/span&gt;
    total: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Shared&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;add_up&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shared&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;10000&lt;/span&gt;
        s.guard.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()
        s.total = s.total + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        s.guard.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sh = &lt;span class=&quot;hl-type&quot;&gt;Shared&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;SpinLock&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s1 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;add_up, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sh).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s2 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;add_up, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sh).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

s1.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()
s2.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sh.total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;20000
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;take-the-atomic-away-and-it-is-a-race&quot;&gt;Take the atomic away and it is a race&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-function&quot;&gt;racy&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;100000&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p = &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r1 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;racy, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;n).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r2 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;racy, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;n).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

r1.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()
r2.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program is a data race by definition: two threads, one word, no synchronization. &lt;strong&gt;On the run
that produced this page it printed &lt;code&gt;200000&lt;/code&gt; — the right answer.&lt;/strong&gt; It is not on the site as a checked
program for exactly that reason, and the reason is the lesson: a race that gives the right answer on
the machine you tested it on is why the model is built out of things you can &lt;em&gt;grep for&lt;/em&gt; rather than
things you can test for. &lt;code&gt;*T&lt;/code&gt; is one of the two spellings that share on purpose, and it is the
unchecked one.&lt;/p&gt;
&lt;h2 id=&quot;mutex-t&quot;&gt;&lt;code&gt;Mutex[T]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Mutex[T]&lt;/code&gt; &lt;strong&gt;owns what it protects&lt;/strong&gt;, which is the whole difference against &lt;code&gt;SpinLock&lt;/code&gt;. Both of its
fields are private, so there is no way to reach the value that does not go through &lt;code&gt;lock&lt;/code&gt; or
&lt;code&gt;try_lock&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Mutex&lt;/span&gt;.&lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.value)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;field &apos;value&apos; of &apos;sysl.posix.threads.Mutex&apos; is private to &apos;library/sysl/posix/threads/mutex.sysl&apos;, the file that declares it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Private is the entirety of what “owns” means here. With &lt;code&gt;value&lt;/code&gt; public, reading it would be an
unsynchronized read of the very thing the type exists to synchronize, and the type would be a
spinlock with a suggestion attached.&lt;/p&gt;
&lt;p&gt;The private field does a second job: it puts the &lt;strong&gt;positional constructor&lt;/strong&gt; out of reach, so
&lt;code&gt;Mutex.new&lt;/code&gt; is the only way in and there is no way to build one that starts out held.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; built = &lt;span class=&quot;hl-type&quot;&gt;Mutex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = built.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the constructor names every field of &apos;sysl.posix.threads.Mutex&apos; in order, and &apos;held&apos; is private to &apos;library/sysl/posix/threads/mutex.sysl&apos;, the file that declares it — build it through an associated function of its own
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;lock-answers-an-address-and-releasing-is-written&quot;&gt;&lt;code&gt;lock&lt;/code&gt; answers an address, and releasing is written&lt;/h3&gt;
&lt;p&gt;Rust returns a guard whose destruction releases the lock. sysl has a
&lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; now and deliberately does not use it here: a destructor runs for a
value held behind a &lt;code&gt;&amp;amp;T&lt;/code&gt;, so a guard would mean a heap allocation per &lt;code&gt;lock&lt;/code&gt; — on the one path where
the whole point is to hold a lock for as few instructions as possible. &lt;code&gt;defer m.unlock()&lt;/code&gt; is the
idiom, the same one &lt;a href=&quot;/library/fs/&quot;&gt;&lt;code&gt;sysl.fs&lt;/code&gt;&lt;/a&gt; uses for &lt;code&gt;close&lt;/code&gt;, and for the same reason.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-function&quot;&gt;inc&lt;/span&gt;(m: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Mutex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;])
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;10000&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = m.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()

        &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; m.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()
        &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p = &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mx = &lt;span class=&quot;hl-type&quot;&gt;Mutex&lt;/span&gt;.&lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a1 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;inc, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;mx).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a2 = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;inc, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;mx).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

a1.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()
a2.&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mp = mx.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;mp)

mx.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;20000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;defer&lt;/code&gt; is &lt;a href=&quot;/reference/statements/&quot;&gt;block-scoped&lt;/a&gt;, not function-scoped, so the &lt;code&gt;defer&lt;/code&gt; inside that
loop body runs at the end of &lt;strong&gt;each iteration&lt;/strong&gt; — which is what makes it usable for a lock taken in
a loop at all, and is the point at which sysl’s &lt;code&gt;defer&lt;/code&gt; and Go’s stop agreeing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The mistake this shape cannot prevent&lt;/strong&gt; is holding on to the address past the &lt;code&gt;unlock&lt;/code&gt;. Nothing
takes it away from you, and nothing will tell you.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;try_lock&lt;/code&gt; never waits and answers an &lt;code&gt;Option[*T]&lt;/code&gt;, which is the ordinary shape for “it might not
have worked”:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = &lt;span class=&quot;hl-type&quot;&gt;Mutex&lt;/span&gt;.&lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = q.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;g.&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; again = q.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(again.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;())

q.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; third = q.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(third.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;())

q.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 5
false
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neither &lt;code&gt;lock&lt;/code&gt; nor &lt;code&gt;try_lock&lt;/code&gt; takes an &lt;code&gt;Ordering&lt;/code&gt;, and neither does &lt;code&gt;unlock&lt;/code&gt;, because &lt;strong&gt;a lock’s
orderings are fixed by what a lock means&lt;/strong&gt;. The exchange that takes it is an acquire and the store
that frees it is a release, and that pairing is what publishes everything the holder wrote to
whichever thread takes the lock next. It is the whole of what makes the data safe to touch.&lt;/p&gt;
&lt;h3 id=&quot;it-is-not-built-on-pthread-mutex-t&quot;&gt;It is not built on &lt;code&gt;pthread_mutex_t&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The reason is a &lt;strong&gt;build property rather than a preference&lt;/strong&gt;, and it is worth spelling out because it
is the same argument that keeps the standard library buildable for targets nobody has tried yet.&lt;/p&gt;
&lt;p&gt;A caller-allocated opaque C type is one of the three things the
&lt;a href=&quot;/reference/ffi/&quot;&gt;compilation model&lt;/a&gt; names as reachable from C and from nothing else. Its size lives
in a header, and it differs both between platforms and between two libcs on the &lt;em&gt;same&lt;/em&gt; platform —
64 bytes on Darwin, 40 under glibc on x86-64, 48 on aarch64, 40 again under musl. &lt;code&gt;#if&lt;/code&gt; can ask
which operating system this is, but &lt;strong&gt;not which libc&lt;/strong&gt;. So a transcribed byte count would compile
everywhere and be checked nowhere, which is precisely the failure that section is about.&lt;/p&gt;
&lt;p&gt;The way to read a header is C, and the standard library deliberately includes none: it reaches libc
by symbol alone, which is what lets it go on building for any target the toolchain can lower for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[sysl] &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pthread_create&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_pthread_create&lt;/span&gt;(
    t: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;,
    attr: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;,
    body: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;,
    arg: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;,
) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[sysl] &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pthread_join&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_pthread_join&lt;/span&gt;(t: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, result: *&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every one of those is a &lt;strong&gt;scalar&lt;/strong&gt; handle or an address. A &lt;code&gt;pthread_t&lt;/code&gt; is one word on both platforms
this builds for — a pointer on Darwin, an &lt;code&gt;unsigned long&lt;/code&gt; under glibc — and &lt;code&gt;usize&lt;/code&gt; is the spelling
that is both. Transcribing that is safe in a way transcribing a &lt;em&gt;layout&lt;/em&gt; is not, and it is the only
transcription in the module.&lt;/p&gt;
&lt;p&gt;So &lt;code&gt;Mutex[T]&lt;/code&gt; is three atomic operations and a yield: an acquiring exchange to take it, a relaxed
load between attempts, and a releasing store to free it. &lt;strong&gt;What that costs is a context switch per
contended attempt&lt;/strong&gt;, where a futex would cost none. A futex-backed mutex is what a binding library
carrying its own C shim would add; it is not something the standard library can reach.&lt;/p&gt;
&lt;p&gt;The spin is not &lt;code&gt;SpinLock&lt;/code&gt;‘s, either. A failed exchange &lt;strong&gt;gives the processor up&lt;/strong&gt; rather than
turning round again, so a waiter cannot starve the holder the way a pure spin can on one core, and
the hold may be as long as it likes. What it does not do is &lt;em&gt;sleep&lt;/em&gt;: there is no wait queue.&lt;/p&gt;
&lt;h2 id=&quot;yield-now-and-current&quot;&gt;&lt;code&gt;yield_now&lt;/code&gt; and &lt;code&gt;current&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.threads.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;yield_now&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; me = &lt;span class=&quot;hl-function&quot;&gt;current&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mine = &lt;span class=&quot;hl-function&quot;&gt;current&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(me.id == mine.id)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;yield_now&lt;/code&gt; is a &lt;strong&gt;hint, not a wait&lt;/strong&gt;. A thread that yields is still runnable and may be handed the
processor straight back; what it is for is the spin in &lt;code&gt;Mutex.lock&lt;/code&gt;, where the thread holding the
lock may not be running at all and nothing else in the loop would make it so. It answers whether the
system took the offer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;current()&lt;/code&gt; is what a body compares against to learn that it is not the thread that spawned it.&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-async&quot;&gt;There is no &lt;code&gt;async&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;No &lt;code&gt;async&lt;/code&gt;, no &lt;code&gt;await&lt;/code&gt;, and no task runtime — in the language or in this module. Threads are what
sysl offers for doing two things at once, and this page is all of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is deferred rather than refused&lt;/strong&gt;, and the difference is worth knowing if you are deciding
whether to build on threads something you would rather have written as tasks. The shape it would take
here is settled: futures compiled to state machines, sized at compile time, with no allocation
inherent in a future and the executor an ordinary library. What stands between that and being built
is a schedule. Nothing on this page changes when it arrives — a thread will still be a thread.&lt;/p&gt;
&lt;p&gt;What you get in the meantime is worth having, and both halves of it are things an &lt;code&gt;await&lt;/code&gt; costs a
language that has one. sysl has no &lt;strong&gt;actor reentrancy&lt;/strong&gt; hazard — the trap where an actor’s state
changes across an &lt;code&gt;await&lt;/code&gt; — because there is no await-based interleaving. And blocking is honest: a
thread that waits is a thread that waits, with no cooperative-scheduling model to reason about on top
of it, and no way for one stalled task to stall nine others you never looked at.&lt;/p&gt;
&lt;h2 id=&quot;how-strong-this-is&quot;&gt;How strong this is&lt;/h2&gt;
&lt;p&gt;Honestly weaker than Rust or Swift 6, and worth saying plainly rather than implying a guarantee the
language cannot keep.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;checked&lt;/th&gt;&lt;th&gt;not checked&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;crossing a domain&lt;/td&gt;&lt;td&gt;what a &lt;code&gt;@crossing&lt;/code&gt; parameter is handed, structurally&lt;/td&gt;&lt;td&gt;a boundary &lt;strong&gt;nobody marked&lt;/strong&gt; — no annotation, no question&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;refcount races&lt;/td&gt;&lt;td&gt;what a &lt;code&gt;&amp;amp;sync T&lt;/code&gt; may hold, structurally&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;mutating shared state&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;&lt;strong&gt;use a &lt;code&gt;Mutex&lt;/code&gt;; nothing enforces it&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the kernel tier&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;&lt;code&gt;*T&lt;/code&gt;, spinlocks, orderings — as in C&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;This module is where the first row stops being theoretical.&lt;/strong&gt; &lt;code&gt;spawn&lt;/code&gt; is declared
&lt;code&gt;@crossing(arg)&lt;/code&gt;, so the pointer it takes is looked &lt;em&gt;through&lt;/em&gt; and a state whose counts are not all
atomic is refused where the call is written. That is also why this API takes an address rather than a
value: &lt;strong&gt;a &lt;code&gt;spawn&lt;/code&gt; taking a &lt;code&gt;T&lt;/code&gt; would be claiming the &lt;em&gt;copying&lt;/em&gt; half of the crossing rule&lt;/strong&gt;, which
belongs to a channel and is not written.&lt;/p&gt;
&lt;p&gt;The unchecked half of that row is where the annotation is &lt;strong&gt;absent&lt;/strong&gt;. A facility with no
&lt;code&gt;@crossing&lt;/code&gt; on it is a boundary the compiler was never told about, and there is no way to guess one:
a scheduler in a package looks like any other function until somebody writes the line.&lt;/p&gt;
&lt;p&gt;So a data race requires you to have shared something on purpose. Sharing takes &lt;code&gt;&amp;amp;sync&lt;/code&gt; or &lt;code&gt;*T&lt;/code&gt;, both
of which are greppable and neither of which is what an ordinary value is. What remains permanent is
the race you can write by putting a mutable field in a &lt;code&gt;&amp;amp;sync T&lt;/code&gt;, because it is the cost of not
having a borrow checker.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/args/&quot;&gt;&lt;code&gt;sysl.args&lt;/code&gt;&lt;/a&gt; — how &lt;code&gt;argc&lt;/code&gt; and &lt;code&gt;argv&lt;/code&gt; become a &lt;code&gt;[]string&lt;/code&gt;, and the two layers
that read options out of them.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The text module</title>
    <link href="https://sysl.sh/library/text/"/>
    <id>https://sysl.sh/library/text/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.text` — validating bytes into text, walking it by character, searching and trimming without an allocator, building and splitting with one, and reading values back out.</summary>
    <content type="html">&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is &lt;a href=&quot;/reference/types/&quot;&gt;an immutable, validated &lt;code&gt;[]u8&lt;/code&gt;&lt;/a&gt;, and the language gives it a few
things directly: its length, its bytes, a boundary-checked substring, and a cursor over its
characters. Everything a program then &lt;em&gt;does&lt;/em&gt; with text — validate, classify, search, trim, split,
join, build, parse — is &lt;code&gt;sysl.text&lt;/code&gt;, and none of it is a language feature.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One piece of the module is reached without being named.&lt;/strong&gt; &lt;code&gt;s.chars&lt;/code&gt; is a member the compiler
provides, and it calls this module’s &lt;code&gt;chars_of&lt;/code&gt; by key rather than by resolving the word — so
walking characters costs a program nothing, not even an import line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.len, s.bytes.len)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.chars
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(c))
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], s.bytes[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 6
h.é.l.l.o.
h 195
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six bytes and five characters, and &lt;code&gt;s.bytes[1]&lt;/code&gt; is &lt;code&gt;195&lt;/code&gt; — the first half of &lt;code&gt;é&lt;/code&gt;. That is the whole
of what this module is about: the two counts are different numbers, and every operation here is
explicit about which one it works in.&lt;/p&gt;
&lt;h2 id=&quot;what-is-in-it&quot;&gt;What is in it&lt;/h2&gt;
&lt;p&gt;The module is seven files, and the boundaries between them are arguments rather than filing:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;file&lt;/th&gt;&lt;th&gt;holds&lt;/th&gt;&lt;th&gt;why it is a file&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;utf8.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;from_utf8&lt;/code&gt;, &lt;code&gt;from_utf8_lossy&lt;/code&gt;, &lt;code&gt;Utf8Error&lt;/code&gt;, &lt;code&gt;char_from_u32&lt;/code&gt;, &lt;code&gt;from_cstring&lt;/code&gt;, &lt;code&gt;is_char_boundary&lt;/code&gt;, &lt;code&gt;Chars&lt;/code&gt;, &lt;code&gt;CharIndices&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the validity seam — what turns bytes into text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ascii.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;trait &lt;code&gt;Ascii&lt;/code&gt;, implemented for &lt;code&gt;u8&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;classification, &lt;strong&gt;named for the range it answers over&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;find.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;trait &lt;code&gt;Search&lt;/code&gt;, implemented for &lt;code&gt;string&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;[]const u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;everything that makes &lt;strong&gt;no new bytes&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;edit.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;split&lt;/code&gt;, &lt;code&gt;fields&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;, &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;replace_all&lt;/code&gt;, &lt;code&gt;to_upper&lt;/code&gt;, &lt;code&gt;to_lower&lt;/code&gt;&lt;/td&gt;&lt;td&gt;everything that &lt;strong&gt;does&lt;/strong&gt; — so it needs an allocator&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;parse.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ParseError&lt;/code&gt;, &lt;code&gt;parse_bool&lt;/code&gt;/&lt;code&gt;int&lt;/code&gt;/&lt;code&gt;long&lt;/code&gt;/&lt;code&gt;uint&lt;/code&gt;/&lt;code&gt;ulong&lt;/code&gt;/&lt;code&gt;real&lt;/code&gt; and the &lt;code&gt;_base&lt;/code&gt; forms&lt;/td&gt;&lt;td&gt;the direction &lt;code&gt;str(x)&lt;/code&gt; does not go&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;build.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;StrBuilder&lt;/code&gt;, &lt;code&gt;CString&lt;/code&gt;, &lt;code&gt;str_builder_with_capacity&lt;/code&gt;&lt;/td&gt;&lt;td&gt;gathering text, and the copy C reads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;width.sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;char_columns&lt;/code&gt;, &lt;code&gt;columns&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;data, not algorithm&lt;/strong&gt; — 499 ranges of the Unicode Character Database&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two of those rows carry the module’s whole design, and they are worth reading before anything else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Ascii&lt;/code&gt; and &lt;code&gt;Search&lt;/code&gt; are each written once over two receivers.&lt;/strong&gt; sysl had no
&lt;a href=&quot;/reference/declarations/&quot;&gt;overloading&lt;/a&gt; when they were written, so the obvious shape was two sets of
functions — &lt;code&gt;is_digit&lt;/code&gt; for a byte and some suffixed twin for a
character; a search over &lt;code&gt;string&lt;/code&gt; and another over &lt;code&gt;[]u8&lt;/code&gt;. The older sysl did exactly that and paid
1,630 lines of near-identical code for it. A trait says “either of these” instead: each
implementation supplies two or three members and every operation is a default written once against
them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;find&lt;/code&gt;/&lt;code&gt;edit&lt;/code&gt; split is the allocator, not taxonomy.&lt;/strong&gt; A search answers with an offset or a
&lt;code&gt;bool&lt;/code&gt;; a trim answers with a &lt;em&gt;view&lt;/em&gt; of what it was given. Neither makes a byte that was not already
there, so all of &lt;code&gt;find.sysl&lt;/code&gt; is reachable under &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;no alloc&lt;/code&gt;&lt;/a&gt; — and a program
that only searches never links an allocator on account of a &lt;code&gt;join&lt;/code&gt; it does not call. That is
demonstrated &lt;a href=&quot;#the-half-that-allocates&quot;&gt;below&lt;/a&gt;, because the compiler enforces it.&lt;/p&gt;
&lt;h2 id=&quot;characters-and-bytes&quot;&gt;Characters and bytes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;operation&lt;/th&gt;&lt;th&gt;spelling&lt;/th&gt;&lt;th&gt;cost&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;byte length&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.len&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;byte at an index&lt;/td&gt;&lt;td&gt;&lt;code&gt;s[i] -&amp;gt; u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1), bounds-checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;substring&lt;/td&gt;&lt;td&gt;&lt;code&gt;s[a..b] -&amp;gt; string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1), shares; bounds-checked &lt;strong&gt;and&lt;/strong&gt; boundary-checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the bytes&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.bytes -&amp;gt; []const u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1) view&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the characters&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.chars -&amp;gt; Chars&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1) per step&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;concatenation&lt;/td&gt;&lt;td&gt;&lt;code&gt;a + b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(n), allocates&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every row but one yields a value or a view. &lt;code&gt;s.chars&lt;/code&gt; yields a &lt;strong&gt;sequence&lt;/strong&gt;, and it has to: the
decoding is what makes the scalar values, so there is nothing a string could hand out the way a
container hands out a view of its storage. So &lt;code&gt;Chars&lt;/code&gt; carries a position and answers “the next one”,
which is the whole of the &lt;a href=&quot;/library/core/&quot;&gt;iteration protocol&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The cursor validates nothing, and does not need to — a &lt;code&gt;string&lt;/code&gt; is well-formed UTF-8 by
construction, so the decoder reads the width off the lead byte and takes the continuation bytes as
given. A &lt;code&gt;Chars&lt;/code&gt; built over a &lt;code&gt;[]u8&lt;/code&gt; that is &lt;em&gt;not&lt;/em&gt; a string is an ordinary struct over ordinary
bytes: it gives the garbage-in answer and never reads past the end, since every byte it takes goes
through the slice’s own bounds check.&lt;/p&gt;
&lt;h3 id=&quot;driving-a-cursor-by-hand&quot;&gt;Driving a cursor by hand&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;for&lt;/code&gt; walks a &lt;strong&gt;copy&lt;/strong&gt; of a cursor, so a loop over &lt;code&gt;s.chars&lt;/code&gt; cannot be asked afterwards where it
got to. A program that needs to know drives the cursor itself, and &lt;code&gt;Chars&lt;/code&gt; offers three things by
value for exactly that — &lt;code&gt;offset&lt;/code&gt;, &lt;code&gt;peek&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt;, none of which consume anything:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{char_indices, is_char_boundary}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.len, s.chars.&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.chars.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cur = s.chars

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cur.offset)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cur.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cur.offset, cur.&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; pair &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;char_indices&lt;/span&gt;(s.bytes)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(pair.&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, pair.&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_char_boundary&lt;/span&gt;(s.bytes[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;is_char_boundary&lt;/span&gt;(s.bytes[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 5
h
0
h
1 4
0 h
1 é
3 l
4 l
5 o
true false
é
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Read the &lt;code&gt;char_indices&lt;/code&gt; column downward: 0, 1, 3, 4, 5.&lt;/strong&gt; The jump from 1 to 3 is &lt;code&gt;é&lt;/code&gt; being two
bytes wide, and it is the entire reason this walk exists. The offset reported is each character’s
&lt;strong&gt;first&lt;/strong&gt; byte, so a slice built from two of them lands on boundaries by construction — which matters,
because &lt;code&gt;s[a..b]&lt;/code&gt; &lt;em&gt;traps&lt;/em&gt; on a mid-codepoint bound rather than handing back something that is not
text.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;is_char_boundary&lt;/code&gt; asks the same question of a single byte: one mask and one comparison, since a
continuation byte is the only one matching &lt;code&gt;10xxxxxx&lt;/code&gt;. It is what a program walking backwards, or
snapping an arbitrary offset onto a boundary, would otherwise write inline.&lt;/p&gt;
&lt;h3 id=&quot;what-that-shape-is-for&quot;&gt;What that shape is for&lt;/h3&gt;
&lt;p&gt;This is a lexer, and it is why &lt;code&gt;offset&lt;/code&gt; and &lt;code&gt;peek&lt;/code&gt; are on the cursor at all — without them a scanner
has to index bytes by hand and decode a second time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.&lt;span class=&quot;hl-type&quot;&gt;Ascii&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;scan&lt;/span&gt;(src: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cur = src.chars

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;()
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; start = cur.offset
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; c.&lt;span class=&quot;hl-function&quot;&gt;is_alpha&lt;/span&gt;()
            &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos; &apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_alnum&lt;/span&gt;()
                cur.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;()

            &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;word  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, src[start..&amp;lt;cur.offset])
        &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; c.&lt;span class=&quot;hl-function&quot;&gt;is_digit&lt;/span&gt;()
            &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos; &apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_digit&lt;/span&gt;()
                cur.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;()

            &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, src[start..&amp;lt;cur.offset])
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
            cur.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; scan&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;scan&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;let x1 = 42&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; walked = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.chars
    walked += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;after the loop the cursor is untouched:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s.chars.offset, walked)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;word   let
word   x1
number 42
after the loop the cursor is untouched: 0 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;src[start..&amp;lt;cur.offset]&lt;/code&gt; is an O(1) substring sharing the source’s bytes — a token costs a retain
and no copy.&lt;/p&gt;
&lt;h2 id=&quot;validating-bytes-into-text&quot;&gt;Validating bytes into text&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Utf8Error&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;from_utf8_lossy&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;from_cstring&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Utf8Error&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;char_from_u32&lt;/span&gt;(u: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;char&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Utf8Error&lt;/span&gt;
    offset: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    truncated: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The compiler supplies exactly one primitive here — &lt;code&gt;from_utf8_unchecked&lt;/code&gt;, which takes a &lt;code&gt;[]u8&lt;/code&gt; as a
&lt;code&gt;string&lt;/code&gt; with nothing looked at — and the validator on top of it is ordinary sysl.&lt;/strong&gt; Nothing in a
byte-by-byte scan needs anything the language does not already offer. What no sysl body can write is
the last line, because every &lt;em&gt;safe&lt;/em&gt; route to a &lt;code&gt;string&lt;/code&gt; already carries the guarantee.&lt;/p&gt;
&lt;p&gt;The validator is Unicode’s well-formedness table rather than a decode-then-range-check, and the
difference shows in what it costs to be right: in the table the &lt;strong&gt;lead&lt;/strong&gt; byte fixes the legal range
of the byte after it — &lt;code&gt;E0&lt;/code&gt; demands &lt;code&gt;A0..BF&lt;/code&gt;, &lt;code&gt;ED&lt;/code&gt; only &lt;code&gt;80..9F&lt;/code&gt;, &lt;code&gt;F0&lt;/code&gt; demands &lt;code&gt;90..BF&lt;/code&gt;, &lt;code&gt;F4&lt;/code&gt; only
&lt;code&gt;80..8F&lt;/code&gt; — so an overlong encoding, a surrogate, and a value past &lt;code&gt;10FFFF&lt;/code&gt; are all rejected at the
second byte by the same test, before any code point is assembled.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Utf8Error&lt;/code&gt; carries the offset and &lt;strong&gt;one&lt;/strong&gt; distinction beyond it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; good: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;195&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;169&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cut: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;195&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; surr: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;237&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;160&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;128&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(good) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset, e.truncated)

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(cut) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset, e.truncated)

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(surr) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset, e.truncated)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ok hé
refused 1 true
refused 0 false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;truncated&lt;/code&gt; is the only thing a caller can act on differently.&lt;/strong&gt; The second input is &lt;code&gt;h&lt;/code&gt; followed
by a lead byte with its continuation missing — more bytes would fix it, which is exactly the case a
program reading a stream in chunks is in. The third is a surrogate: no continuation could rescue it,
and reading further is reading past an error. A taxonomy of fault names would give a caller more to
match on and nothing more to &lt;em&gt;do&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The bytes are &lt;strong&gt;copied&lt;/strong&gt;, not viewed, which is why this entry requires an allocator. A &lt;code&gt;[]u8&lt;/code&gt; is
writable and a &lt;code&gt;string&lt;/code&gt; is not, so sharing would let a later write through the slice change a value
that had already been checked. Copying is what makes the validation mean anything afterwards.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;char_from_u32&lt;/code&gt; is the same shape one scalar down — the fallible half of &lt;code&gt;u32 -&amp;gt; char&lt;/code&gt;, refusing a
surrogate or anything past &lt;code&gt;10FFFF&lt;/code&gt;, where the plain &lt;code&gt;char(u)&lt;/code&gt; conversion traps instead. It is a free
function because a scalar has no member namespace to hang a &lt;code&gt;char.try&lt;/code&gt; on.&lt;/p&gt;
&lt;h3 id=&quot;when-a-refusal-is-the-wrong-answer-from-utf8-lossy&quot;&gt;When a refusal is the wrong answer: &lt;code&gt;from_utf8_lossy&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;Result&lt;/code&gt; is right when the bytes &lt;em&gt;ought&lt;/em&gt; to be valid, and wrong when they carry whatever was sent.
Text off a wire, out of a serial port, or in a file somebody else wrote is the second case, and a
program reading it usually wants something it can show a person rather than a fault it can only
report. &lt;code&gt;from_utf8_lossy&lt;/code&gt; keeps what is well-formed and puts &lt;strong&gt;U+FFFD&lt;/strong&gt; where the rest was.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8_lossy

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cut: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;97&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;226&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;130&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; stray: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;97&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;98&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8_lossy&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8_lossy&lt;/span&gt;(cut))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8_lossy&lt;/span&gt;(stray))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;héllo
a�
a�b
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One replacement per maximal ill-formed subsequence, not one per byte.&lt;/strong&gt; The second input is &lt;code&gt;a&lt;/code&gt;
followed by two thirds of a euro sign: those two bytes are one truncated character, so they become
one U+FFFD and not two. That is what Unicode recommends, and it is the part a hand-rolled
skip-a-byte-and-retry loop gets wrong.&lt;/p&gt;
&lt;p&gt;It walks the same table &lt;code&gt;from_utf8&lt;/code&gt; does, so the two cannot come to disagree about which bytes are
text — they differ only in what they do about the ones that are not. Valid input costs a single walk
and no allocation at all.&lt;/p&gt;
&lt;h2 id=&quot;classification-ascii&quot;&gt;Classification: &lt;code&gt;Ascii&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ascii&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;to_upper&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;to_lower&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;is_ascii&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_digit&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_upper&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_lower&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_alpha&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_alnum&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_space&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_hex_digit&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_punct&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_print&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_control&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;digit_value&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three members are required; every classifier below the line is a default written once over &lt;code&gt;code()&lt;/code&gt;.
Adding one is a line in the trait and nothing in either implementation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The name is the promise.&lt;/strong&gt; This answers over the ASCII range and nothing else — a value at or above
128 answers &lt;code&gt;false&lt;/code&gt; to every question rather than being guessed at. That is what &lt;code&gt;is_ascii&lt;/code&gt; is for:
it distinguishes “not a letter” from “not a letter I can see”. Real Unicode classification needs
property tables, which must not be in a kernel, so it belongs to a library above this one.&lt;/p&gt;
&lt;p&gt;The older sysl called the equivalent module &lt;code&gt;unicode&lt;/code&gt; and classified nothing above 127, so every
caller read a promise the code did not keep. This name exists to avoid that.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.&lt;span class=&quot;hl-type&quot;&gt;Ascii&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;7&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_digit&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;7&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_alpha&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;7&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;digit_value&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;f&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;digit_value&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;z&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;digit_value&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_none&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;is_ascii&lt;/span&gt;(), &lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;is_alpha&lt;/span&gt;(), &lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;to_upper&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;A&apos;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;to_lower&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;a&apos;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;to_upper&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false 7
15 true
false false é
a 65
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things in that last line. &lt;code&gt;&apos;é&apos;.to_upper()&lt;/code&gt; is &lt;code&gt;é&lt;/code&gt; — &lt;strong&gt;both conversions are total&lt;/strong&gt;, leaving
anything that is not a letter of the other case exactly as they found it, which is what makes mapping
one over arbitrary text safe rather than merely defined. And &lt;code&gt;u8(&apos;a&apos;).to_upper()&lt;/code&gt; prints &lt;code&gt;65&lt;/code&gt;, not
&lt;code&gt;A&lt;/code&gt;: it answers in the receiver’s own type, and a &lt;code&gt;u8&lt;/code&gt; renders as a number. That is the only reason
the two conversions are per-implementation at all — the arithmetic is identical.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;digit_value(base)&lt;/code&gt; is here rather than beside the parsers because it is a question about a
character, and because parsing wants exactly this and nothing else from a digit. Letters count from
ten in either case, so base 16 and base 36 need no separate spelling, and a base outside 2..36
answers &lt;code&gt;None&lt;/code&gt; for every input rather than trapping — the caller that passed it is the one that can
say what to do about it.&lt;/p&gt;
&lt;h2 id=&quot;searching-and-trimming-search&quot;&gt;Searching and trimming: &lt;code&gt;Search&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Search&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;slice&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, lo: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, hi: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;is_empty&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;starts_with&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, prefix: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;ends_with&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, suffix: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;index_of&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, needle: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;last_index_of&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, needle: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;index_of_byte&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;last_index_of_byte&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;contains&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, needle: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;has_byte&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count_of&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, needle: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trim_start&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trim_end&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trim_matches&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, cutset: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trim_start_matches&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, cutset: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trim_end_matches&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, cutset: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two required members carry all of it. &lt;strong&gt;&lt;code&gt;view&lt;/code&gt; is the whole of what a &lt;code&gt;string&lt;/code&gt; and a &lt;code&gt;[]const u8&lt;/code&gt;
disagree about&lt;/strong&gt; — the bytes to look at. &lt;strong&gt;&lt;code&gt;slice&lt;/code&gt; is what lets a trim answer with a view rather than
a copy&lt;/strong&gt;, and it is required rather than defaulted because a default cannot build a &lt;code&gt;Self&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is deliberately no &lt;code&gt;len&lt;/code&gt;: both implementations already have one the compiler provides, and a
trait member of that name would hide it rather than agree with it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.&lt;span class=&quot;hl-type&quot;&gt;Search&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  hello, world  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;contains&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), s.&lt;span class=&quot;hl-function&quot;&gt;index_of&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;aaa&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;count_of&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--x--&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;trim_matches&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;path/to/file.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;last_index_of_byte&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;/&apos;&lt;/span&gt;)).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;// comment&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;starts_with&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;file.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;ends_with&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, world
true 9
1 x
7
true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;quot;aaa&amp;quot;&lt;/code&gt; contains one &lt;code&gt;&amp;quot;aa&amp;quot;&lt;/code&gt;, not two.&lt;/strong&gt; Counting is non-overlapping and left to right, which is the
same rule &lt;code&gt;replace_all&lt;/code&gt; substitutes by — so the number &lt;code&gt;count_of&lt;/code&gt; reports and the number of
replacements made always agree.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;index_of&lt;/code&gt; answers with an &lt;code&gt;Option&lt;/code&gt; rather than the older sysl’s &lt;code&gt;-1&lt;/code&gt;, because a sentinel is a value
the type calls ordinary and every caller has to remember to check.&lt;/p&gt;
&lt;h3 id=&quot;a-byte-level-search-over-utf-8-is-correct-not-a-shortcut&quot;&gt;A byte-level search over UTF-8 is correct, not a shortcut&lt;/h3&gt;
&lt;p&gt;UTF-8 is self-synchronizing: a continuation byte is distinguishable from a lead byte, so a
well-formed needle &lt;strong&gt;cannot&lt;/strong&gt; match starting anywhere but at a character boundary. So these ignore
encoding entirely, and an offset one of them returns is always safe to slice at.&lt;/p&gt;
&lt;p&gt;Trimming whitespace is safe from the other side of the same fact — every whitespace byte is ASCII, so
every byte removed is a whole character and every bound left behind is one the receiver already had.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A cutset is a set of bytes, and that is the group’s one caveat.&lt;/strong&gt; A non-ASCII character in a cutset
is its bytes and not itself, so such a cutset can cut a character in half — which for a &lt;code&gt;string&lt;/code&gt; is a
trap rather than a wrong answer. The whitespace trims are the ones without a caveat.&lt;/p&gt;
&lt;h3 id=&quot;the-second-implementation-and-what-it-is-for&quot;&gt;The second implementation, and what it is for&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Search&lt;/code&gt; is implemented for &lt;code&gt;[]const u8&lt;/code&gt; as well, and that receiver is the point of the trait: bytes
that are not text, or not yet — what a program has read off a socket or a file before it knows
whether it is UTF-8.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.&lt;span class=&quot;hl-type&quot;&gt;Search&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; raw: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;105&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;33&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; needle: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;105&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;33&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(raw[..].&lt;span class=&quot;hl-function&quot;&gt;contains&lt;/span&gt;(needle), raw[..].&lt;span class=&quot;hl-function&quot;&gt;index_of&lt;/span&gt;(needle).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(raw[..].&lt;span class=&quot;hl-function&quot;&gt;starts_with&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;104u8&lt;/span&gt;]), raw[..].&lt;span class=&quot;hl-function&quot;&gt;is_empty&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  hello  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes.&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;().len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 1
true false
5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;raw[..]&lt;/code&gt; is a &lt;code&gt;[]u8&lt;/code&gt; — writable — and the implementation is written for &lt;code&gt;[]const u8&lt;/code&gt;. It resolves
because &lt;a href=&quot;/reference/types/&quot;&gt;a &lt;code&gt;[]T&lt;/code&gt; is accepted wherever a &lt;code&gt;[]const T&lt;/code&gt; is wanted&lt;/a&gt;: the read-only bit
is part of one type rather than making two, and a receiver is such a place. The reverse does not
hold, and must not: a member written for a &lt;code&gt;[]T&lt;/code&gt; may write through its receiver.&lt;/p&gt;
&lt;h2 id=&quot;the-half-that-allocates&quot;&gt;The half that allocates&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;split&lt;/code&gt;, &lt;code&gt;fields&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;, &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;replace_all&lt;/code&gt;, &lt;code&gt;to_upper&lt;/code&gt; and &lt;code&gt;to_lower&lt;/code&gt; are free functions over
&lt;code&gt;string&lt;/code&gt;, not members of &lt;code&gt;Search&lt;/code&gt;. &lt;strong&gt;A trait default cannot write them&lt;/strong&gt; — it would have to build a
&lt;code&gt;Self&lt;/code&gt; out of new bytes, and there is no way for a trait to say how. That is the honest boundary of
the write-it-once trick, and it falls exactly where the allocator does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{split, fields, join, repeat, replace_all, to_upper, to_lower}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; parts = &lt;span class=&quot;hl-function&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a,b,,c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; words = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(parts.len, parts[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], parts[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;] == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, parts[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fields&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  one   two  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).len)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;(words, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;repeat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;repeat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;replace_all&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;aaa&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;to_upper&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;to_lower&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;HÉLLO&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 a true c
2
x-y-z
ababab true
ba
HéLLO hÉllo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;to_upper(&amp;quot;héllo&amp;quot;)&lt;/code&gt; is &lt;code&gt;HéLLO&lt;/code&gt;.&lt;/strong&gt; The &lt;code&gt;é&lt;/code&gt; is untouched, which is the ASCII promise made visible
rather than merely stated. These walk &lt;em&gt;characters&lt;/em&gt; rather than bytes and go through &lt;code&gt;push_char&lt;/code&gt;, so
every way into the builder still carries the UTF-8 guarantee and no unchecked primitive is named —
and it works because &lt;code&gt;Ascii for char&lt;/code&gt; is total, so a character outside the range is re-encoded to
exactly the bytes it arrived as. A byte map would be the faster loop and would need a raw-byte way
into a builder, which is the one thing the builder deliberately does not offer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;split&lt;/code&gt; drops nothing and &lt;code&gt;fields&lt;/code&gt; drops whitespace.&lt;/strong&gt; Adjacent separators yield an empty piece
between them and a separator at either end yields an empty piece outside it, so &lt;code&gt;&amp;quot;a,b,,c&amp;quot;&lt;/code&gt; is four
pieces of which the third is empty. &lt;code&gt;fields&lt;/code&gt; is not &lt;code&gt;split&lt;/code&gt; on a space: a run of whitespace separates
two fields rather than producing empty ones between them, which is what reading a line of columns
wants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What splitting hands back are views.&lt;/strong&gt; A piece shares the bytes of the string it came from and
costs a retain, so &lt;code&gt;split&lt;/code&gt; allocates the &lt;em&gt;vector&lt;/em&gt; and not the text. The older sysl copied every
piece, for want of an O(1) substring to hand out — this is where the representation pays off most
visibly.&lt;/p&gt;
&lt;p&gt;Two edges are deliberate and share a reason: an empty separator yields the whole string as one piece,
and an empty pattern in &lt;code&gt;replace_all&lt;/code&gt; matches nowhere. The byte-level reading of either would cut
multi-byte characters apart, and the character-level reading is what &lt;code&gt;s.chars&lt;/code&gt; already is.&lt;/p&gt;
&lt;h3 id=&quot;the-split-is-enforced-not-documented&quot;&gt;The split is enforced, not documented&lt;/h3&gt;
&lt;p&gt;A module that has given up its allocator can search and trim all it likes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.&lt;span class=&quot;hl-type&quot;&gt;Search&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; line = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  key = value  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line.&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line.&lt;span class=&quot;hl-function&quot;&gt;index_of&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), line.&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;starts_with&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line.&lt;span class=&quot;hl-function&quot;&gt;trim_matches&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;key = value
6 true
11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…and reaching into the other file is refused at compile time, naming the allocating call it found:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.join

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; words = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;(words, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this reaches &apos;sysl.buf.Buf.extend.byte&apos;, which makes heap storage, and this module declared &apos;@no_alloc&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That diagnostic names &lt;code&gt;sysl.buf&lt;/code&gt;, three calls down, because &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;alloc&lt;/code&gt; is checked on what a module
&lt;em&gt;calls&lt;/em&gt;&lt;/a&gt; rather than on which modules it depends on — the standard library is
exactly why. Inferring it per module would put the whole of &lt;code&gt;sysl.text&lt;/code&gt; on one side of a line that
runs through the middle of it.&lt;/p&gt;
&lt;h2 id=&quot;gathering-text-strbuilder&quot;&gt;Gathering text: &lt;code&gt;StrBuilder&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a + b&lt;/code&gt; allocates a fresh buffer every time, so gathering &lt;em&gt;n&lt;/em&gt; pieces that way copies everything it
has so far on every step. A builder keeps one growable buffer and pays for each piece once.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push_int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; ok=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push_bool&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; x=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push_real&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push_char&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;!&apos;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.len)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;19
n=42 ok=true x=1.5!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every way in carries the guarantee.&lt;/strong&gt; &lt;code&gt;push&lt;/code&gt; takes a &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;push_char&lt;/code&gt; takes a &lt;code&gt;char&lt;/code&gt;, and the
four renderers take a number or a &lt;code&gt;bool&lt;/code&gt; — UTF-8 is closed under appending any of them, so &lt;code&gt;finish&lt;/code&gt;
hands back a plain &lt;code&gt;string&lt;/code&gt; rather than something a caller has to validate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That is why a builder is not a &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Writer&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; A public &lt;code&gt;write&lt;/code&gt; taking a &lt;code&gt;[]u8&lt;/code&gt; would
be &lt;code&gt;from_utf8_unchecked&lt;/code&gt; with a longer name and none of its greppability. The two shapes look
interchangeable and are not: a &lt;code&gt;Writer&lt;/code&gt; is a sink for bytes and a builder is a producer of text.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;push_int&lt;/code&gt;, &lt;code&gt;push_uint&lt;/code&gt;, &lt;code&gt;push_real&lt;/code&gt; and &lt;code&gt;push_bool&lt;/code&gt; exist so that gathering a number costs no
allocation.&lt;/strong&gt; The spelling without them is &lt;code&gt;push(str(n))&lt;/code&gt;, which builds a whole reference-counted
&lt;code&gt;string&lt;/code&gt; — a heap object with a refcount and a deallocation hook — copies its bytes out, and drops
it, for a value whose text is a couple of dozen bytes and is wanted only inside this buffer. A stack
array and one &lt;code&gt;snprintf&lt;/code&gt; is the same rendering with none of that.&lt;/p&gt;
&lt;p&gt;They agree with &lt;code&gt;str&lt;/code&gt; to the byte, and that is the property that makes the cheap path a &lt;em&gt;substitute&lt;/em&gt;
rather than a second rendering: a program that builds half a line with a builder and half with an
interpolation must not be able to tell which half a number came through. &lt;code&gt;push_real&lt;/code&gt; is &lt;code&gt;%g&lt;/code&gt; for the
same reason.&lt;/p&gt;
&lt;p&gt;They take &lt;code&gt;long&lt;/code&gt; and &lt;code&gt;ulong&lt;/code&gt; rather than one member per width — the bargain the &lt;code&gt;print&lt;/code&gt; family
makes. &lt;a href=&quot;/reference/declarations/&quot;&gt;Overloading&lt;/a&gt; would give a set of members one &lt;em&gt;name&lt;/em&gt;; it would not
give them one &lt;em&gt;body&lt;/em&gt;, which is what the widening buys. The difference is that &lt;code&gt;print&lt;/code&gt; has the
compiler widening its arguments and a member cannot:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

b.&lt;span class=&quot;hl-function&quot;&gt;push_int&lt;/span&gt;(k)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;n&apos; of &apos;sysl.text$StrBuilder.push_int&apos; is long, but int was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So a narrower value is written &lt;code&gt;b.push_int(long(k))&lt;/code&gt; — and a caller who would rather not is
describing &lt;code&gt;push(str(k))&lt;/code&gt;, which still works, still costs the allocation, and still saves the
quadratic copying that made a builder worth having. A value of any other type is pushed that way too.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;str_builder_with_capacity(n)&lt;/code&gt; starts one with room, skipping the reallocate-and-copy at each
doubling on the way up to &lt;code&gt;n&lt;/code&gt;. It is a guess and nothing depends on it: too small and the buffer
grows the way it always does, too large and the slack goes with the rest. &lt;code&gt;join&lt;/code&gt; uses it, because
&lt;code&gt;join&lt;/code&gt; can compute the answer’s length before it starts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;finish&lt;/code&gt; copies rather than lending&lt;/strong&gt;, so a builder may go on being appended to and the string
already taken out of it does not change. And &lt;code&gt;len&lt;/code&gt; is a property rather than a method, which the
compiler will point out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;len&apos; is a property of &apos;sysl.text$StrBuilder&apos; — read it as &apos;value.len&apos;, without &apos;()&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reading-a-value-back-the-parsers&quot;&gt;Reading a value back: the parsers&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;BadDigit&lt;/span&gt;(at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;Overflow&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;BadBase&lt;/span&gt;(base: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;parse_bool&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_long&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_uint&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;uint&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_ulong&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;ulong&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_real&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;parse_int_base&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_long_base&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;parse_ulong_base&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;ulong&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;str(x)&lt;/code&gt; renders and nothing read back, which is a gap a program feels immediately — an argument, a
configuration field and a number in a file are all text. The digits are easy; the library exists for
the edges.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{parse_int, parse_int_base, parse_long, parse_ulong, parse_bool, parse_real}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-42&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int_base&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ff&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_long&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-9223372036854775808&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_ulong&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;18446744073709551615&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_bool&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;parse_real&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 -42
255
-9223372036854775808
18446744073709551615
true 1.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;long&lt;/code&gt;‘s most negative value comes back with no special case, and that is the whole trick.&lt;/strong&gt; The
signed range is asymmetric — the magnitude of &lt;code&gt;MIN&lt;/code&gt; is one larger than the largest positive value —
so a parser that builds a magnitude and negates at the end cannot represent it at any point. These
accumulate on the &lt;strong&gt;negative&lt;/strong&gt; side, which covers the entire range with one path and leaves only a
&lt;em&gt;positive&lt;/em&gt; result of &lt;code&gt;MIN&lt;/code&gt;‘s magnitude to refuse, just before the final negation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The overflow test happens before the arithmetic that would overflow&lt;/strong&gt;, because integer arithmetic
&lt;a href=&quot;/reference/types/&quot;&gt;wraps rather than trapping&lt;/a&gt;: a product that has already wrapped is not a number a
later comparison can learn anything from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The unsigned range is not the signed one with the sign removed.&lt;/strong&gt; &lt;code&gt;&amp;quot;ffffffffffffffff&amp;quot;&lt;/code&gt; is an
ordinary 64-bit mask that overflows every signed parse there is, so a systems language needs the
unsigned direction to read back what its own literals are written in. No sign is accepted there, not
even &lt;code&gt;+&lt;/code&gt;: a leading &lt;code&gt;-&lt;/code&gt; on an unsigned value is a question with no good answer.&lt;/p&gt;
&lt;h3 id=&quot;refusing-and-saying-why&quot;&gt;Refusing, and saying why&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ParseError&lt;/code&gt;‘s four cases are separated by what a caller would &lt;em&gt;do&lt;/em&gt; about them rather than by
taxonomy — an empty field is often a default, a bad digit is a message to a user, an overflow is a
wider type or a refusal, and a bad base is the program’s own mistake rather than the input’s. Each
renders through &lt;code&gt;Display&lt;/code&gt;, so a refusal can be printed without being matched on:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{parse_int, parse_int_base, parse_long, parse_bool, parse_real}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;12abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2147483648&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;parse_long&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2147483648&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int_base&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_bool&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_real&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1.5x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;no digits to read
not a digit at byte 2
value too large for its type 2147483648
99 is not a base between 2 and 36
not a digit at byte 0
not a digit at byte 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four things are visible there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;BadDigit&lt;/code&gt; carries the offset&lt;/strong&gt;, for the reason &lt;code&gt;Utf8Error&lt;/code&gt; does: a message naming &lt;em&gt;where&lt;/em&gt; is worth
writing and cannot be reconstructed afterwards. &lt;code&gt;&amp;quot;12abc&amp;quot;&lt;/code&gt; fails at byte 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Trailing garbage is refused.&lt;/strong&gt; &lt;code&gt;&amp;quot;12abc&amp;quot;&lt;/code&gt; is not &lt;code&gt;12&lt;/code&gt;, and &lt;code&gt;&amp;quot;1.5x&amp;quot;&lt;/code&gt; is not &lt;code&gt;1.5&lt;/code&gt; — which for the
float means checking C’s end pointer, since &lt;code&gt;strtod&lt;/code&gt; on its own stops where it likes and reports
success.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Overflow&lt;/code&gt; is relative to the type asked for.&lt;/strong&gt; &lt;code&gt;2147483648&lt;/code&gt; is a perfectly good &lt;code&gt;long&lt;/code&gt; and is not
an &lt;code&gt;int&lt;/code&gt;, so &lt;code&gt;parse_int&lt;/code&gt; refuses the same text &lt;code&gt;parse_long&lt;/code&gt; accepts. What the caller asked for is an
&lt;code&gt;int&lt;/code&gt;, and there is no honest &lt;code&gt;int&lt;/code&gt; to hand back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;parse_bool&lt;/code&gt; accepts exactly the two spellings &lt;code&gt;str&lt;/code&gt; produces.&lt;/strong&gt; &lt;code&gt;&amp;quot;True&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;yes&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt; are
each somebody’s convention and none is this library’s; a program wanting one writes three lines that
read as the policy they are.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;parse_real&lt;/code&gt; goes to C’s &lt;code&gt;strtod&lt;/code&gt; for the reason the float half of &lt;code&gt;str&lt;/code&gt; goes to &lt;code&gt;snprintf&lt;/code&gt;:
correctly rounded decimal-to-binary conversion is hard to get right, easy to get subtly wrong, and
the two directions must agree or a value will not survive being written and read back. It costs one
allocation, since C reads a NUL-terminated pointer and a &lt;code&gt;string&lt;/code&gt; carries a length instead.&lt;/p&gt;
&lt;h3 id=&quot;a-parse-in-a-result-is-not-the-value&quot;&gt;A parse in a &lt;code&gt;Result&lt;/code&gt; is not the value&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.parse_int

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;41&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got sysl.Result[int, sysl.text.ParseError] and int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the type doing its job. The usual shape is to let &lt;code&gt;?&lt;/code&gt; carry the refusal outward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{split, parse_int, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Search&lt;/span&gt;}

&lt;span class=&quot;hl-function&quot;&gt;read_port&lt;/span&gt;(line: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;ParseError&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; parts = &lt;span class=&quot;hl-function&quot;&gt;split&lt;/span&gt;(line, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-function&quot;&gt;parse_int&lt;/span&gt;(parts[parts.len - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;].&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;())?

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(n)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read_port&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;read_port&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;port = 8080&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;read_port&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;port = eighty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8080
not a digit at byte 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-c-boundary&quot;&gt;The C boundary&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; carries a length and has no terminator, so passing one to C is an explicit, allocating
conversion — and &lt;code&gt;CString&lt;/code&gt; owns the copy, because a language with no manual free has to say who frees
it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{cstring, from_cstring}

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cs = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hé&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cs.len, &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(cs.ptr))

&lt;span class=&quot;hl-function&quot;&gt;from_cstring&lt;/span&gt;(cs.ptr) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;back&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t, t.len)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 3
back hé 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cs.ptr&lt;/code&gt; is the &lt;code&gt;*u8&lt;/code&gt; an &lt;code&gt;extern&lt;/code&gt; taking a &lt;code&gt;char *&lt;/code&gt; is given, and &lt;code&gt;cs.len&lt;/code&gt; is the byte length &lt;strong&gt;not&lt;/strong&gt;
counting the terminator, so that it agrees with the &lt;code&gt;s.len&lt;/code&gt; it came from. The pointer carries an
ordinary &lt;code&gt;*T&lt;/code&gt;‘s rule: it is valid while the &lt;code&gt;CString&lt;/code&gt; is held.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The hazard the explicitness exists for survives, and it is worth stating as an equation:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cs = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cs.len, &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(cs.ptr))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both numbers are right. sysl counts three bytes because carrying a length is the whole point; C stops
at the interior NUL. Neither can be made to be the other, which is exactly why a conversion is
written rather than inferred.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;from_cstring&lt;/code&gt; is the other direction — a &lt;code&gt;string&lt;/code&gt; copied out of the NUL-terminated bytes a C
function handed back, which every binding needs the moment a C library reports anything in words. The
copy is not optional: the bytes belong to C, a static buffer it may reuse on the next call or storage
the caller is about to free, and a &lt;code&gt;string&lt;/code&gt; outlives the call that produced it. But it is &lt;strong&gt;one&lt;/strong&gt;
copy, and it is &lt;code&gt;from_utf8&lt;/code&gt;‘s — slicing the &lt;code&gt;*u8&lt;/code&gt; names the bytes where C left them without taking
any hold on them, and validation is what turns that borrowed run into a &lt;code&gt;string&lt;/code&gt; owning its own.&lt;/p&gt;
&lt;p&gt;It is fallible for the same reason &lt;code&gt;from_utf8&lt;/code&gt; is: nothing about a &lt;code&gt;char *&lt;/code&gt; promises well-formed
UTF-8, and a C library reporting in a non-UTF-8 locale is the ordinary case rather than a corrupt one.&lt;/p&gt;
&lt;p&gt;For a &lt;strong&gt;literal&lt;/strong&gt;, none of this is needed — &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt; is a plain &lt;code&gt;*u8&lt;/code&gt; pointing at read-only data, with
no allocation and no copy. That form is on &lt;a href=&quot;/reference/ffi/&quot;&gt;foreign functions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-wide-is-it-on-screen-columns&quot;&gt;How wide is it on screen: &lt;code&gt;columns&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;s.len&lt;/code&gt; is bytes and a &lt;code&gt;Chars&lt;/code&gt; walk counts scalar values. &lt;strong&gt;Neither is what a terminal draws&lt;/strong&gt;, and a
program laying anything out in columns — a table, a progress bar, anything with a border on the
right — is asking a third question:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.{columns, char_columns}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;columns&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;café&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;char_columns&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;日&apos;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;columns&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;日本&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
2
4
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;char_columns(c: char) -&amp;gt; usize&lt;/code&gt;&lt;/strong&gt; — &lt;strong&gt;two&lt;/strong&gt; for the East Asian wide and fullwidth forms, &lt;strong&gt;none&lt;/strong&gt;
for a combining mark or a format character, one for everything else. A control character answers
zero, which is the honest answer to a question it does not really have: a terminal does not draw
&lt;code&gt;\n&lt;/code&gt; in a column, it acts on it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;columns(text: []const u8) -&amp;gt; usize&lt;/code&gt;&lt;/strong&gt; — the sum over a run of UTF-8. It takes bytes rather than a
&lt;code&gt;string&lt;/code&gt; so that text being assembled can be measured without being copied into one first;
&lt;code&gt;s.bytes&lt;/code&gt; is what a caller holding a &lt;code&gt;string&lt;/code&gt; passes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;This is data rather than algorithm&lt;/strong&gt;, which is the whole reason it belongs to the library. The rule
is two lines long; what makes it right is 499 ranges out of the Unicode Character Database, and no
program should be carrying its own copy of those.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A format specifier cannot answer this and is not meant to.&lt;/strong&gt; &lt;code&gt;f&amp;quot;${s}%-10s&amp;quot;&lt;/code&gt; counts &lt;em&gt;bytes&lt;/em&gt;, exactly
as C’s &lt;code&gt;%-10s&lt;/code&gt; does, so &lt;code&gt;café&lt;/code&gt; padded to ten is short by one column and &lt;code&gt;naïveté&lt;/code&gt; by two — and the
error differs between two cells of the same column, which is the worst way to be wrong. The
specifier keeps its equivalence with &lt;code&gt;snprintf&lt;/code&gt;; layout asks here instead, by name. Only the caller
knows where the next border falls, so what the library owes it is a &lt;em&gt;number&lt;/em&gt;, not a padded field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;no alloc&lt;/code&gt; module may use all of it.&lt;/strong&gt; The tables are static, the search allocates nothing, and a
program that calls neither function links neither table.&lt;/p&gt;
&lt;h2 id=&quot;reaching-the-module&quot;&gt;Reaching the module&lt;/h2&gt;
&lt;p&gt;Everything above the free surface needs an &lt;code&gt;import&lt;/code&gt;, and a trait needs to be &lt;em&gt;in scope&lt;/em&gt; for its
members to be reachable — which the compiler says in those words:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.split

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).len)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  x  &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;trim&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;string has &apos;trim&apos; from sysl.text.Search, and that trait is not in scope here — import it to reach the member
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import sysl.text.Search&lt;/code&gt; is the fix, and it is worth reading as a feature rather than a hoop: a
member arriving on &lt;code&gt;string&lt;/code&gt; from three modules away, with nothing in the file saying so, is how a
program becomes unreadable. The &lt;a href=&quot;/reference/modules/&quot;&gt;import forms&lt;/a&gt; are the same ones every module
uses.&lt;/p&gt;
&lt;p&gt;One conversion is easy to write backwards, since text and bytes are so nearly the same thing here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;b&apos; of &apos;sysl.text.from_utf8&apos; is []const byte, but string was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;from_utf8&lt;/code&gt; goes &lt;strong&gt;bytes to text&lt;/strong&gt;. The other direction is &lt;code&gt;s.bytes&lt;/code&gt;, is free, and needs no function
at all — a &lt;code&gt;string&lt;/code&gt; is already a validated &lt;code&gt;[]u8&lt;/code&gt;, so there is nothing to check on the way out.
(Note that the compiler renders &lt;code&gt;u8&lt;/code&gt; as &lt;code&gt;byte&lt;/code&gt; in diagnostics.)&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/regex/&quot;&gt;&lt;code&gt;sysl.regex&lt;/code&gt;&lt;/a&gt; — a pattern over that same text, matched without backtracking.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sysl.term</title>
    <link href="https://sysl.sh/library/term/"/>
    <id>https://sysl.sh/library/term/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The escape sequences a terminal understands — colour, emphasis, and the screen — as constants a program with no allocator can still name.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.term&lt;/code&gt; is forty-odd &lt;code&gt;const string&lt;/code&gt;s and nothing else. Each one is an ANSI escape sequence, and
writing one into the output stream is how a terminal is told to change colour, start underlining, or
clear itself.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.term.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;red&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;bold&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;reset&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;: the file was not there&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A sequence is written &lt;strong&gt;where the text it affects is written&lt;/strong&gt;, because that is what it is — a mark
in the stream rather than a property of a string. There is no coloured-string type here and nothing
to wrap: &lt;code&gt;red&lt;/code&gt; is text that happens to be invisible, it concatenates like any other text, and
&lt;code&gt;reset&lt;/code&gt; is how you stop.&lt;/p&gt;
&lt;h2 id=&quot;why-constants-and-what-that-buys&quot;&gt;Why constants, and what that buys&lt;/h2&gt;
&lt;p&gt;A string literal is &lt;a href=&quot;/reference/strings/&quot;&gt;immortal&lt;/a&gt; — it lives in the program’s own image with no
owner and no reference count — so naming forty of them costs nothing at run time and nothing in
storage. That is what lets this module declare &lt;code&gt;@no_alloc&lt;/code&gt;, and it is the point of the whole design:
colouring a line is exactly what a program that has given up its allocator most wants to do, and a
facility such a program could not use would be no facility at all.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.term.*

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;green&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;reset&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The module requires no capability at all, so an interrupt handler can name a colour.&lt;/p&gt;
&lt;h2 id=&quot;the-colours&quot;&gt;The colours&lt;/h2&gt;
&lt;p&gt;Eight, each with a bright variant and a background form. The arithmetic between them is the
specification rather than a coincidence: &lt;strong&gt;a background is its foreground plus ten, and a bright
colour is its ordinary one plus sixty.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.term.*

&lt;span class=&quot;hl-comment&quot;&gt;// An escape is invisible, so this reads the parameter back out of one.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.bytes
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; b &amp;gt;= &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;0&apos;&lt;/span&gt;) &amp;amp;&amp;amp; b &amp;lt;= &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;9&apos;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; n = n * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(b - &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;0&apos;&lt;/span&gt;))

    n

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(red), &lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(bright_red), &lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(on_red), &lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(on_bright_red))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;31 91 41 101
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;foreground&lt;/th&gt;&lt;th&gt;bright&lt;/th&gt;&lt;th&gt;background&lt;/th&gt;&lt;th&gt;bright background&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;black&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_black&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_black&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_black&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;red&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_red&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_red&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_red&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;green&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_green&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_green&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_green&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;yellow&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_yellow&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_yellow&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_yellow&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;blue&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_blue&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_blue&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_blue&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;magenta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_magenta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_magenta&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_magenta&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cyan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_cyan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_cyan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_cyan&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;white&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bright_white&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_white&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;on_bright_white&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;default_color&lt;/code&gt; and &lt;code&gt;on_default&lt;/code&gt; put each back to whatever the terminal was using.&lt;/p&gt;
&lt;h2 id=&quot;emphasis-and-why-reset-is-not-enough&quot;&gt;Emphasis, and why &lt;code&gt;reset&lt;/code&gt; is not enough&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bold&lt;/code&gt;&lt;/td&gt;&lt;td&gt;heavier, or brighter on a terminal with no bold face&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dim&lt;/code&gt;&lt;/td&gt;&lt;td&gt;fainter&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;italic&lt;/code&gt;&lt;/td&gt;&lt;td&gt;slanted, where the terminal has it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;underline&lt;/code&gt;&lt;/td&gt;&lt;td&gt;underlined&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;blink&lt;/code&gt;&lt;/td&gt;&lt;td&gt;blinking, where the terminal allows it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;reverse&lt;/code&gt;&lt;/td&gt;&lt;td&gt;foreground and background swapped&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hidden&lt;/code&gt;&lt;/td&gt;&lt;td&gt;not shown, but still selectable&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;strike&lt;/code&gt;&lt;/td&gt;&lt;td&gt;struck through&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;all of the above, and the colours, off at once&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;ANSI has no way to end one attribute and leave the others — &lt;code&gt;reset&lt;/code&gt; ends everything there is. So a
program that wants its colour back without losing an emphasis writes &lt;code&gt;default_color&lt;/code&gt; rather than
&lt;code&gt;reset&lt;/code&gt;, and one that has ended a colour inside an underlined field has to open the underline again
afterwards.&lt;/p&gt;
&lt;h2 id=&quot;the-screen-and-the-cursor&quot;&gt;The screen and the cursor&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;clear_screen&lt;/code&gt; / &lt;code&gt;clear_line&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the whole screen, the whole line — neither moves the cursor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;clear_below&lt;/code&gt; / &lt;code&gt;clear_to_line_end&lt;/code&gt;&lt;/td&gt;&lt;td&gt;from the cursor onwards&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;home&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the top left corner&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hide_cursor&lt;/code&gt; / &lt;code&gt;show_cursor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a program that hides it owns showing it again, including on the way out&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;save_cursor&lt;/code&gt; / &lt;code&gt;restore_cursor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one remembered position, the terminal’s own — these do not nest&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;clear_screen&lt;/code&gt; is nearly always written with &lt;code&gt;home&lt;/code&gt; after it, since clearing does not move anything.&lt;/p&gt;
&lt;h2 id=&quot;whether-to-write-escapes-at-all-sysl-posix-tty&quot;&gt;Whether to write escapes at all — &lt;code&gt;sysl.posix.tty&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Naming a colour and deciding to use one are different questions, and they live in different modules.
Everything above asks for no capability at all, so an allocator-free, OS-free program can reach it.
Asking whether output is a terminal needs &lt;code&gt;isatty&lt;/code&gt;, which needs &lt;code&gt;posix&lt;/code&gt; — and a capability
requirement is &lt;strong&gt;module-wide&lt;/strong&gt;, so one function here would have taken all forty constants away from
the programs this module is arranged for. The answer sits in &lt;code&gt;sysl.posix&lt;/code&gt; instead, and the split
shows up in the import, which is honest about what the second one costs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is &lt;code&gt;sysl.posix.tty&lt;/code&gt; rather than &lt;code&gt;sysl.term.tty&lt;/code&gt;, and the namespace is the point.&lt;/strong&gt; Everything
under &lt;code&gt;sysl.posix&lt;/code&gt; requires that one capability, so a freestanding target reaches none of it — which
is now visible in the import line rather than only in the module’s own header. What this needs is
&lt;code&gt;isatty(3)&lt;/code&gt; and &lt;code&gt;termios&lt;/code&gt;, so that is where it belongs, however much it reads as terminal handling.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;answers&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;is_tty(fd)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;is this descriptor a terminal?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;color_wanted()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;does the environment want colour — &lt;code&gt;NO_COLOR&lt;/code&gt; unset or empty, &lt;code&gt;TERM&lt;/code&gt; not &lt;code&gt;dumb&lt;/code&gt;?&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;color_on(fd)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;both, for one descriptor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;color()&lt;/code&gt; / &lt;code&gt;color_err()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;both, for standard output and standard error&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Ask once and keep the answer.&lt;/strong&gt; Each of these is a system call or an environment scan, and nothing
a running program does changes what they say.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.term.{red, reset}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.tty.color

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; paint = &lt;span class=&quot;hl-function&quot;&gt;color&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; on    = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; paint &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; red &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; off   = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; paint &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; reset &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;on&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;off&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;: not found&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;error: not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That output is the point rather than an accident: this page’s programs run with their output
captured, so &lt;code&gt;color()&lt;/code&gt; answers false and the escapes are never written — which is exactly what the
same program does in a pipeline or redirected to a file.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;is_tty&lt;/code&gt; is worth having alone: a progress bar, a spinner and a prompt are all worth suppressing when
output is a pipe, and none of them is about colour. So is &lt;code&gt;color_wanted&lt;/code&gt; — a &lt;code&gt;--color=always&lt;/code&gt; flag
overrides the descriptor without overriding the user’s &lt;code&gt;NO_COLOR&lt;/code&gt;, and that is exactly this function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;NO_COLOR&lt;/code&gt; is about the variable being there rather than about its value.&lt;/strong&gt; Present and non-empty
turns colour off whatever it contains, so &lt;code&gt;NO_COLOR=0&lt;/code&gt; means no colour, while set-and-empty does not.
A program reading it as a boolean and looking for &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt; has misread the convention.&lt;/p&gt;
&lt;h2 id=&quot;taking-the-terminal-over-sysl-posix-tty-raw&quot;&gt;Taking the terminal over — &lt;code&gt;sysl.posix.tty.raw&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A terminal at a shell is in &lt;strong&gt;cooked&lt;/strong&gt; mode: the kernel’s line discipline echoes what is typed,
honours backspace, and hands the program a whole line at Enter. That is why &lt;code&gt;sysl.io.console_lines&lt;/code&gt;
is all a hosted program usually needs — something else is doing the editing.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;raw()&lt;/code&gt; puts that out of the way, so a program sees each keystroke as it is typed.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;raw()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;cbreak mode — keystrokes arrive as typed, nothing is echoed. &lt;strong&gt;Answers whether it worked&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;cooked()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;puts back what &lt;code&gt;raw&lt;/code&gt; changed, and only that&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;flush()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;pushes out what C is holding — a prompt with no newline after it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tty_writer()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;standard output as a sink that flushes what it is given&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;raw()&lt;/code&gt; answering &lt;code&gt;false&lt;/code&gt; is not an error — it is the other situation.&lt;/strong&gt; With input redirected from
a file or a pipe there is no terminal to change, and an editor is the wrong facility anyway: nothing
is being typed and nothing should be echoed. So a program picks its reader from the answer, and
&lt;code&gt;prog &amp;lt; script.txt&lt;/code&gt; goes on working.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{stdin, console_lines}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.tty.{raw, cooked}

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; input = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;raw&lt;/span&gt;()
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a terminal&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;cooked&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cursor = &lt;span class=&quot;hl-function&quot;&gt;console_lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;input)

        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a pipe&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a pipe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That output is the point rather than an accident, exactly as above: this page’s programs run with
their input closed, so &lt;code&gt;raw()&lt;/code&gt; declines and the cooked path is what runs.&lt;/p&gt;
&lt;h3 id=&quot;what-it-sets-and-the-one-thing-it-gives-up&quot;&gt;What it sets, and the one thing it gives up&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-icanon -echo -isig opost onlcr&lt;/code&gt;. Output translation is &lt;strong&gt;asserted rather than assumed&lt;/strong&gt; — nothing
here turns it off, so leaving it out looked safe, and a terminal that arrives without it makes every
&lt;code&gt;print&lt;/code&gt; stair-step down the screen while the editor’s own output looks fine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Signals go, and that is a choice rather than a limitation.&lt;/strong&gt; Leaving &lt;code&gt;isig&lt;/code&gt; alone would keep Ctrl-C
interrupting, which reads like a feature for a REPL. It used not to be available at all: a program
interrupted in cbreak mode must restore the terminal from a signal handler, and restoring meant
allocating a command string and forking a shell, neither of which is async-signal-safe — so the
handler deadlocked rather than tidying up. That was a fact about &lt;code&gt;stty&lt;/code&gt;, and restoring is now one
&lt;code&gt;tcsetattr&lt;/code&gt; on a saved struct, which POSIX lists as async-signal-safe. The handler is still not
written, because &lt;code&gt;-isig&lt;/code&gt; means there is no signal to catch and every exit is an ordinary one.
Ctrl-C arrives as &lt;strong&gt;byte 3&lt;/strong&gt; for the editor instead.&lt;/p&gt;
&lt;p&gt;What that costs is worth saying plainly: a program that has stopped responding can no longer be
interrupted from its own terminal, and the escape is &lt;code&gt;kill&lt;/code&gt; from another one. What it buys is that
the terminal is never left broken, and that a hosted program behaves exactly like one on a board —
which never had signals to disable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is &lt;code&gt;termios&lt;/code&gt;, through a shim, and it used to be &lt;code&gt;stty&lt;/code&gt; through &lt;code&gt;system&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;struct termios&lt;/code&gt; is
caller-allocated and laid out differently on every platform, which is the transcription the library
refuses — so the structure stays in C and a file descriptor is all that crosses. The shim sits in a
per-OS directory (&lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;), which is what keeps a &lt;code&gt;#include &amp;lt;termios.h&amp;gt;&lt;/code&gt; away
from a target that has no terminal to configure.&lt;/p&gt;
&lt;p&gt;Three things follow: no shell is forked to set two flags; &lt;code&gt;cooked&lt;/code&gt; restores &lt;strong&gt;what was actually
there&lt;/strong&gt;, from a saved struct, where naming &lt;code&gt;icanon echo isig&lt;/code&gt; to put back would restore a different
terminal from the one it found; and it works when standard input is not the shell’s, since the shim
is handed a descriptor where &lt;code&gt;stty&lt;/code&gt; acted on whatever it inherited.&lt;/p&gt;
&lt;h2 id=&quot;reading-a-line-sysl-term-edit&quot;&gt;Reading a line — &lt;code&gt;sysl.term.edit&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The other half of what a console needs, and the reason it exists: &lt;strong&gt;a terminal with no line
discipline gives a program nothing.&lt;/strong&gt; Over a serial cable there is none at all; at a hosted terminal
&lt;code&gt;raw()&lt;/code&gt; has just removed it. Either way nothing appears as it is typed and a mistake cannot be
corrected — which is not a program that reads badly but a program that looks broken.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;editor(r, w)&lt;/code&gt; is a line editor over a &lt;code&gt;*Reader&lt;/code&gt; and a &lt;code&gt;*Writer&lt;/code&gt;. It answers whole lines through
&lt;code&gt;Iterate[string]&lt;/code&gt;, the same as &lt;code&gt;sysl.io.lines&lt;/code&gt; and &lt;code&gt;console_lines&lt;/code&gt;, &lt;strong&gt;so the three are
interchangeable at a call site&lt;/strong&gt; and a program chooses by what is producing its input.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{bytes_reader, bytes_writer}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.term.edit.editor

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; typed = &lt;span class=&quot;hl-function&quot;&gt;bytes_reader&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; echo  = &lt;span class=&quot;hl-function&quot;&gt;bytes_writer&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ed    = &lt;span class=&quot;hl-function&quot;&gt;editor&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;typed, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;echo)

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; ed
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;one
two
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;keys&lt;/th&gt;&lt;th&gt;do&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;←&lt;/code&gt; &lt;code&gt;→&lt;/code&gt; &lt;code&gt;Home&lt;/code&gt; &lt;code&gt;End&lt;/code&gt;&lt;/td&gt;&lt;td&gt;move within the line — and &lt;code&gt;Ctrl-A&lt;/code&gt; / &lt;code&gt;Ctrl-E&lt;/code&gt; / &lt;code&gt;Ctrl-B&lt;/code&gt; / &lt;code&gt;Ctrl-F&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Backspace&lt;/code&gt; &lt;code&gt;Delete&lt;/code&gt;&lt;/td&gt;&lt;td&gt;at the cursor, not only at the end&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl-U&lt;/code&gt; &lt;code&gt;Ctrl-K&lt;/code&gt;&lt;/td&gt;&lt;td&gt;kill the line, or from the cursor on&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;↑&lt;/code&gt; &lt;code&gt;↓&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the last 64 lines — and &lt;code&gt;Ctrl-P&lt;/code&gt; / &lt;code&gt;Ctrl-N&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl-C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;abandon the line and answer an empty one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ctrl-D&lt;/code&gt;&lt;/td&gt;&lt;td&gt;end the input, &lt;strong&gt;on an empty line only&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The line is held as characters and measured in columns.&lt;/strong&gt; A cursor is an index rather than a byte
offset, so a half character can never be left behind by a backspace — one never enters the line. And
a wide character occupies two columns, so erasing a CJK character or an emoji clears both; an editor
counting characters leaves half of one on the screen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Both spellings of an arrow key are read.&lt;/strong&gt; &lt;code&gt;ESC [ D&lt;/code&gt; is CSI and &lt;code&gt;ESC O D&lt;/code&gt; is SS3, and a terminal
chooses between them by whether application cursor key mode is on. Reading only the first is not a
simplification — it means a left arrow inserts a stray &lt;code&gt;D&lt;/code&gt; into the line.&lt;/p&gt;
&lt;h3 id=&quot;what-it-is-not&quot;&gt;What it is not&lt;/h3&gt;
&lt;p&gt;There is no completion, no multi-line editing and no absolute cursor addressing. A program wanting
those wants &lt;a href=&quot;https://github.com/sysl-lang/linenoise&quot;&gt;linenoise&lt;/a&gt;. &lt;strong&gt;A line that wraps past the
terminal’s width redraws wrong&lt;/strong&gt;, which is the honest cost of moving the cursor by writing &lt;code&gt;\b&lt;/code&gt;: it
stops at column zero rather than climbing to the row above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It asks for nothing of the platform&lt;/strong&gt; — no capability, no C — which is what lets the same program
run at a terminal and over a cable. It does allocate: the line is a &lt;code&gt;Buf[char]&lt;/code&gt; and the answer is a
&lt;code&gt;string&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-prompt-and-why-the-editor-pokes-its-sink&quot;&gt;The prompt, and why the editor pokes its sink&lt;/h3&gt;
&lt;p&gt;The editor prints no prompt and is not told one. Every movement it makes is relative, so it never
needs to know how far along the row the line starts, and a caller goes on printing its own prompt —
which is what makes a REPL’s continuation prompt the caller’s business rather than a field here.&lt;/p&gt;
&lt;p&gt;What it does do is hand its sink a &lt;strong&gt;zero-length write&lt;/strong&gt; before waiting for a keystroke. A hosted sink
buffers — &lt;code&gt;putbytes&lt;/code&gt; goes through C’s &lt;code&gt;putchar&lt;/code&gt;, which line-buffers a terminal — so a prompt with no
newline after it would sit in the buffer until something wrote one, which is one keystroke too late.
The poke gives a buffering sink its chance, and keeps the obligation off every caller that prints a
prompt. A board pays nothing for it: a sink with no buffer writes no bytes.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-not-here&quot;&gt;What is deliberately not here&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Anything that takes a number.&lt;/strong&gt; Moving the cursor to a row and column means building
&lt;code&gt;ESC [ row ; col H&lt;/code&gt;, and building a string is an allocation — the one thing the module is arranged to
avoid. The sequences above are the ones whose text is fixed; a program that wants the others writes
&lt;code&gt;f&amp;quot;\u{1b}[${row};${col}H&amp;quot;&lt;/code&gt; and knows what it is spending.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>table</title>
    <link href="https://sysl.sh/guides/table/"/>
    <id>https://sysl.sh/guides/table/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Text measured for display — a column is as wide on screen as its widest cell, and both a byte count and a character count are the wrong unit.</summary>
    <content type="html">&lt;p&gt;Cells of any type that renders, laid out in columns that line up. A column is a &lt;strong&gt;promise about where
the next border falls&lt;/strong&gt;, so the program has to know how wide text &lt;em&gt;looks&lt;/em&gt; — and that is a different
question from how many bytes it is and from how many characters it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: text measured for display.&lt;/strong&gt; Every other program in the set treats a string as bytes to
be copied or compared. Nothing else asks how wide one appears, and the moment something does, two
plausible answers turn out to be wrong.&lt;/p&gt;
&lt;p&gt;Deliberately not modelled: multiple border styles, Markdown and TSV output, row spanning, and
wrapping a cell wider than its column. Each is more of the same layout, and none of them asks the
language anything the program does not already ask.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;FormatSpec&lt;/code&gt;‘s width is a byte count, so it cannot lay out a column.&lt;/strong&gt; The specifier’s width and
precision count bytes, as C’s do, and &lt;code&gt;display_pad&lt;/code&gt; pads to that. A table is the program that minds:
&lt;code&gt;café&lt;/code&gt; is five bytes and four columns, so a field padded to a byte count is short by one — and short
by &lt;strong&gt;one per non-ASCII character&lt;/strong&gt;, so two cells of one column come out wrong by different amounts
and the column is ragged rather than merely narrow. There is no correction to apply afterwards.&lt;/p&gt;
&lt;p&gt;So the program ignores the specifier’s width entirely, hands every cell the neutral spec, and does
its own padding over a count it asks the library for. That division is right — only the caller knows
where the next border falls — but it means the one field a table would have used is the one it
cannot use, and a program that trusted it would produce a table that is wrong &lt;strong&gt;only for text that is
not ASCII&lt;/strong&gt;, which is the worst way to be wrong.&lt;/p&gt;
&lt;p&gt;Settled in the &lt;a href=&quot;/reference/traits/&quot;&gt;core traits&lt;/a&gt;: the specifier keeps counting bytes and keeps its
equivalence with &lt;code&gt;snprintf&lt;/code&gt;, because a specifier is for &lt;code&gt;printf&lt;/code&gt;-shaped output. Laying anything out
asks &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;columns&lt;/code&gt;&lt;/a&gt; instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A character is not a column either.&lt;/strong&gt; The first version of this program counted characters, which
is right for &lt;code&gt;café&lt;/code&gt; and &lt;code&gt;Zürich&lt;/code&gt; and wrong for &lt;code&gt;日本&lt;/code&gt; — two characters occupying four terminal
columns. It was recorded as a boundary rather than solved, on the grounds that the East Asian Width
table from UAX #11 is &lt;em&gt;data&lt;/em&gt; rather than language and had nowhere to live.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That reason was already false when it was written, and that is the more useful half of the
finding.&lt;/strong&gt; Module-level &lt;code&gt;const&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt; had landed the day before, and four other programs in the
set were already using them — &lt;a href=&quot;/guides/datetime/&quot;&gt;datetime&lt;/a&gt; carries a transition table built by a
function at module level, which is the exact shape a width table needs. An absence is worth checking
against the language as it is &lt;em&gt;today&lt;/em&gt; rather than as it was when the habit formed. This one cost a
paragraph explaining why something could not be done that could.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;columns&lt;/code&gt; now lives in &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;, backed by the Unicode Character Database, and
the program measures &lt;code&gt;日本&lt;/code&gt; and a decomposed &lt;code&gt;café&lt;/code&gt; as correctly as it measures ASCII. &lt;strong&gt;What the
program keeps is the call, not the table.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ask the library before reporting an absence&lt;/strong&gt; — the same correction &lt;a href=&quot;/guides/png/&quot;&gt;png&lt;/a&gt; recorded.
This program was most of the way to writing up “a rendered value cannot become a &lt;code&gt;string&lt;/code&gt;“: the sink
answers a &lt;code&gt;[]u8&lt;/code&gt;, and two earlier programs had wanted &lt;code&gt;from_utf8&lt;/code&gt; and not had it. It was already
there. What that would have cost was not just a false note — the checks were written twice, once
comparing bytes by hand, before the conversion was looked for.&lt;/p&gt;
&lt;h2 id=&quot;what-the-assertion-is&quot;&gt;What the assertion is&lt;/h2&gt;
&lt;p&gt;The program checks the property that actually matters, which a byte count would have passed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;even&lt;/span&gt;(text: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; want = &lt;span class=&quot;hl-function&quot;&gt;columns&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;line&lt;/span&gt;(text, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(text))
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;columns&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;line&lt;/span&gt;(text, i)) != want &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;

        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; even&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every line the same width &lt;strong&gt;on screen&lt;/strong&gt; is the whole of what it means for a table to line up. A
program that measured wrongly would still pass a byte-equality check and produce a table nobody could
read, so the assertion is written in the same unit the renderer is.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sysl.sys</title>
    <link href="https://sysl.sh/library/sys/"/>
    <id>https://sysl.sh/library/sys/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The platform seam — every declaration in the standard library that is not sysl, in one file you cannot call.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.sys&lt;/code&gt; is the one module in the standard library with &lt;strong&gt;no surface at all&lt;/strong&gt;. Every name in it is
&lt;code&gt;private[sysl]&lt;/code&gt;, so the whole of it is closed to a program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sys.sysl_putchar

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sysl_putchar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;sysl.sys.sysl_putchar&apos; is private to module &apos;sysl&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is not a page with nothing to say, though — it is the page about a &lt;strong&gt;seam&lt;/strong&gt;. Every declaration
in the standard library that is not sysl lives here, which means the surface a host has to supply
can be read off two files, and the question “what would a freestanding target have to provide?” has
a place to be answered.&lt;/p&gt;
&lt;h2 id=&quot;nothing-in-it-is-reachable-by-any-route&quot;&gt;Nothing in it is reachable, by any route&lt;/h2&gt;
&lt;p&gt;A fully-qualified path is refused for the same reason a bare one is. Being able to &lt;em&gt;see&lt;/em&gt; a name is
not being able to use it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sys.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sysl.sys.&lt;span class=&quot;hl-function&quot;&gt;sysl_sqrt&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;sysl.sys.sysl_sqrt&apos; is private to module &apos;sysl&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the glob import above is worth looking at twice, because it is &lt;strong&gt;not itself refused&lt;/strong&gt; — it
succeeds, and brings in nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sys.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sysl_putchar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;undefined function &apos;sysl_putchar&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;private[sysl]&lt;/code&gt; means &lt;em&gt;the module &lt;code&gt;sysl&lt;/code&gt; and its whole subtree&lt;/em&gt;, so every other part of the standard
library may reach these and no program may. Putting a name here is therefore a decision about the
library’s &lt;strong&gt;own workings&lt;/strong&gt; rather than an addition to its surface — which is exactly what a reader
wants a module like this to mean.&lt;/p&gt;
&lt;h2 id=&quot;the-sysl-prefix-and-what-it-buys-you&quot;&gt;The &lt;code&gt;sysl_&lt;/code&gt; prefix, and what it buys you&lt;/h2&gt;
&lt;p&gt;Every extern here is bound to a &lt;code&gt;sysl_&lt;/code&gt;-prefixed sysl name while going on resolving to the ordinary
C symbol:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;sysl&lt;/span&gt;.sys
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[sysl] &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;   &lt;span class=&quot;hl-function&quot;&gt;sysl_putchar&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[sysl] &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llvm.sqrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sysl_sqrt&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[sysl] &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cbrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;      &lt;span class=&quot;hl-function&quot;&gt;sysl_cbrt&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An extern’s &lt;em&gt;symbol&lt;/em&gt; is not qualified and cannot be.&lt;/strong&gt; It names something the linker already has,
and the linker knows nothing about sysl’s modules. So the sysl-side name is what had to move, and
moving it is what keeps &lt;code&gt;putchar&lt;/code&gt;, &lt;code&gt;sqrt&lt;/code&gt;, &lt;code&gt;pow&lt;/code&gt;, &lt;code&gt;floor&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;memchr&lt;/code&gt; and &lt;code&gt;strtod&lt;/code&gt; free for a
program to declare itself:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;putchar&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;putchar&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sqrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strtod&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strtod&lt;/span&gt;(p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, end: *&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;putchar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;putchar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;105&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;putchar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;3.5 and the rest&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; endp: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;strtod&lt;/span&gt;(s.ptr, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;endp)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hi
1.41421
3.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those three names are the program’s, bound to the same three symbols the library is bound to, and
nothing collides. Spending seven ordinary words out of every program’s namespace would have bought
nothing, and &lt;code&gt;guide/fft&lt;/code&gt; had already declared its own &lt;code&gt;sqrt&lt;/code&gt; before there was a module to ask.&lt;/p&gt;
&lt;h2 id=&quot;the-two-halves&quot;&gt;The two halves&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;platform.sysl&lt;/code&gt;&lt;/strong&gt; — what the library asks of the C library it is hosted on, and the whole of it:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;symbol&lt;/th&gt;&lt;th&gt;what the library uses it for&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;putchar&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every byte &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;prints&lt;/code&gt; emit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;snprintf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;formatting a number into text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;read&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sysl.io&lt;/code&gt;‘s &lt;code&gt;FdReader&lt;/code&gt;, and &lt;code&gt;stdin()&lt;/code&gt; under it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;memchr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;find_byte&lt;/code&gt;, and the line splitting built on it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;strtod&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;parse_real&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;math.sysl&lt;/code&gt;&lt;/strong&gt; — what &lt;code&gt;sysl.math&lt;/code&gt; asks of the machine and of the C mathematics library. Roots,
exponentials and logarithms; powers and &lt;code&gt;hypot&lt;/code&gt;; the circular and hyperbolic trigonometry; the four
roundings; &lt;code&gt;fmod&lt;/code&gt;; and the two sign-bit operations.&lt;/p&gt;
&lt;h2 id=&quot;two-entry-points-per-operation&quot;&gt;Two entry points per operation&lt;/h2&gt;
&lt;p&gt;C names the float widths apart, so &lt;code&gt;sqrt&lt;/code&gt; takes a &lt;code&gt;double&lt;/code&gt; and &lt;code&gt;sqrtf&lt;/code&gt; a &lt;code&gt;float&lt;/code&gt;, and both are
declared. &lt;a href=&quot;/reference/declarations/&quot;&gt;Overloading&lt;/a&gt; could give the pair one sysl name, and
deliberately does not here: these are the raw declarations, and a name that did not match the symbol
it resolves to is the one thing this module exists not to do. &lt;strong&gt;&lt;code&gt;sysl.math&lt;/code&gt; is where the width stops
being visible&lt;/strong&gt;, and it stops there by dispatching on the receiver’s type rather than by a caller
choosing which one they meant.&lt;/p&gt;
&lt;p&gt;The intrinsics are spelled the same twice for a different reason: one base name, two widths, and the
compiler derives &lt;code&gt;.f64&lt;/code&gt; or &lt;code&gt;.f32&lt;/code&gt; from the signature.&lt;/p&gt;
&lt;h2 id=&quot;llvm-or-libm-which-is-which-and-why&quot;&gt;&lt;code&gt;llvm.&lt;/code&gt; or libm — which is which, and why&lt;/h2&gt;
&lt;p&gt;Two kinds of declaration, told apart by the &lt;strong&gt;namespace the link name is in&lt;/strong&gt;. A name beginning
&lt;code&gt;llvm.&lt;/code&gt; is an intrinsic: the back end recognises it and emits the machine’s own instruction, and
there is no symbol for a linker to find. Everything else is libm’s, resolved at the link.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The split is not stylistic — it is which operations the hardware has.&lt;/strong&gt; A square root, an absolute
value, a sign transfer and the four roundings are instructions on every machine sysl targets. A sine
is not, on any of them, so asking LLVM for &lt;code&gt;llvm.sin&lt;/code&gt; would produce a call to the same libm function
this file already names, one indirection later.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;on the machine&lt;/th&gt;&lt;th&gt;in libm&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sqrt&lt;/code&gt;, &lt;code&gt;fabs&lt;/code&gt;, &lt;code&gt;copysign&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;cbrt&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt;, &lt;code&gt;exp2&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;log2&lt;/code&gt;, &lt;code&gt;log10&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;floor&lt;/code&gt;, &lt;code&gt;ceil&lt;/code&gt;, &lt;code&gt;round&lt;/code&gt;, &lt;code&gt;trunc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;pow&lt;/code&gt;, &lt;code&gt;hypot&lt;/code&gt;, &lt;code&gt;fmod&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sin&lt;/code&gt;, &lt;code&gt;cos&lt;/code&gt;, &lt;code&gt;tan&lt;/code&gt;, &lt;code&gt;asin&lt;/code&gt;, &lt;code&gt;acos&lt;/code&gt;, &lt;code&gt;atan&lt;/code&gt;, &lt;code&gt;atan2&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sinh&lt;/code&gt;, &lt;code&gt;cosh&lt;/code&gt;, &lt;code&gt;tanh&lt;/code&gt;, &lt;code&gt;asinh&lt;/code&gt;, &lt;code&gt;acosh&lt;/code&gt;, &lt;code&gt;atanh&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;What that buys beyond speed is a program that needs no libc.&lt;/strong&gt; A freestanding target has no libm
to link against, so the whole module used to be hosted-only. The operations in the left column now
work on a bare machine, and only the transcendentals in the right one do not.&lt;/p&gt;
&lt;h3 id=&quot;round-goes-away-from-zero&quot;&gt;&lt;code&gt;round&lt;/code&gt; goes away from zero&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;llvm.round&lt;/code&gt; is C’s &lt;code&gt;round&lt;/code&gt;, and it is &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;llvm.roundeven&lt;/code&gt;‘s rule. The two differ at exactly
the inputs a rounding is chosen for, so the one adopted here is pinned by a test rather than assumed
from the name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;round&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;3.5&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;round&lt;/span&gt;(), (-&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;round&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;trunc&lt;/span&gt;(), (-&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;trunc&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;floor&lt;/span&gt;(), (-&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;floor&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 4 -3
2 -2 2 -3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Banker’s rounding would have answered &lt;code&gt;2 4 -2&lt;/code&gt; on the first line. All four roundings answer in the
float’s own type, because a &lt;code&gt;floor&lt;/code&gt; that returned an integer would be undefined for the operands
that do not fit one — and the caller who wants an integer is the one who knows the range.&lt;/p&gt;
&lt;h2 id=&quot;where-the-line-is-drawn&quot;&gt;Where the line is drawn&lt;/h2&gt;
&lt;p&gt;The transcendentals are here and most of the comparisons are not, and &lt;strong&gt;the line is what the machine
can do that sysl’s operators cannot&lt;/strong&gt;. A range-reduced sine is an algorithm. So, less obviously, are
the two sign operations — because they read and write the &lt;strong&gt;sign bit&lt;/strong&gt; directly, and a sign bit is
something no comparison can see.&lt;/p&gt;
&lt;p&gt;An absolute value written the obvious way is wrong, and here is the proof:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; z = -&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hand = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; z &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; -z &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; z

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / z, &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / z.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / hand)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;-inf inf -inf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-0.0 &amp;lt; 0.0&lt;/code&gt; is &lt;strong&gt;false&lt;/strong&gt; — no comparison distinguishes a negative zero from a positive one — so the
negation never runs and the magnitude comes back negative. &lt;code&gt;abs&lt;/code&gt; clears the sign bit and gets it
right. The only way to see the difference is to divide into it, which is what the program does.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;copysign&lt;/code&gt; is on the same side of the line for the same reason:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;), (-&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;-3 3 true
-inf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read those two lines together. The third value on the first line says the result &lt;strong&gt;compares equal&lt;/strong&gt;
to positive zero; the second line says it is nevertheless a negative zero. That gap is the whole
argument: a sysl body written out of comparisons cannot produce this value or detect it, so the
operation has to be the machine’s.&lt;/p&gt;
&lt;p&gt;Everything that &lt;em&gt;is&lt;/em&gt; a comparison and nothing more — &lt;code&gt;signum&lt;/code&gt;, &lt;code&gt;is_finite&lt;/code&gt;, &lt;code&gt;is_nan&lt;/code&gt;, the
interpolation — &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt; writes in sysl and calls nothing.&lt;/p&gt;
&lt;h2 id=&quot;link-m&quot;&gt;&lt;code&gt;link &amp;quot;m&amp;quot;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The module carries a &lt;code&gt;link &amp;quot;m&amp;quot;&lt;/code&gt; directive, and the reason it names the &lt;strong&gt;library&lt;/strong&gt; rather than the
flag is that where libm lives is the target’s answer: a file of its own on ELF, part of &lt;code&gt;libSystem&lt;/code&gt;
on Darwin, absent from a freestanding machine.&lt;/p&gt;
&lt;p&gt;The driver used to carry this instead, and every ELF link was handed &lt;code&gt;-lm&lt;/code&gt; whether or not the
program computed anything — because the compiler had no way to be told and this file had no way to
say. Now the requirement travels with the declarations that create it.&lt;/p&gt;
&lt;h2 id=&quot;why-it-is-a-leaf&quot;&gt;Why it is a leaf&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sysl.sys&lt;/code&gt; needs nothing. It imports no module, calls no sysl function, and reports no error — and
that is a property worth protecting rather than an accident of how small it is.&lt;/p&gt;
&lt;p&gt;The clearest illustration is a module that is &lt;strong&gt;not&lt;/strong&gt; here. &lt;code&gt;args_of&lt;/code&gt; converts C’s &lt;code&gt;argc&lt;/code&gt;/&lt;code&gt;argv&lt;/code&gt;
into a &lt;code&gt;[]string&lt;/code&gt;, which sounds exactly like platform business — but it calls &lt;code&gt;print&lt;/code&gt; and &lt;code&gt;exit&lt;/code&gt;,
which are &lt;code&gt;sysl&lt;/code&gt;‘s, and &lt;code&gt;sysl&lt;/code&gt; reaches &lt;code&gt;sysl.sys&lt;/code&gt; for its printing. Putting both in one module would
make the two depend on each other, which the &lt;a href=&quot;/reference/modules/&quot;&gt;acyclic module graph&lt;/a&gt; refuses. So
it lives in &lt;a href=&quot;/library/args/&quot;&gt;&lt;code&gt;sysl.args&lt;/code&gt;&lt;/a&gt; instead, and what is left here is a leaf.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A declaration that reports its own failure in words is not a leaf&lt;/strong&gt;, because reporting is itself a
dependency. That is the shape to look for when deciding whether something belongs at the seam.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;That is the last module. Back to the &lt;a href=&quot;/library/&quot;&gt;section index&lt;/a&gt; for the tree, or to the
&lt;a href=&quot;/reference/&quot;&gt;language reference&lt;/a&gt; for what the compiler itself accepts.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sysl.sync</title>
    <link href="https://sysl.sh/library/sync/"/>
    <id>https://sysl.sh/library/sync/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Atomics, the five memory orderings, and a spinlock — the concurrency a target has before it has a scheduler.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.sync&lt;/code&gt; is two types and five names, and the most important thing about it is what it does
&lt;strong&gt;not&lt;/strong&gt; require. There is no &lt;code&gt;requires&lt;/code&gt; clause on the module at all, so a program that has given up
its allocator and its operating system can still reach every name in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hits = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; guard = &lt;span class=&quot;hl-type&quot;&gt;SpinLock&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

guard.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()
hits.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
guard.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(hits.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(), guard.held)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole reason this module exists apart from &lt;a href=&quot;/library/threads/&quot;&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt;&lt;/a&gt;. A word the
processor can touch indivisibly is something a bare machine has; a &lt;em&gt;thread&lt;/em&gt; is not, because creating
one needs a scheduler underneath. A module’s capability requirement is module-wide, so putting one
type that needed &lt;code&gt;posix&lt;/code&gt; in here would have taken &lt;code&gt;Atomic[T]&lt;/code&gt; out of reach of the allocator, the
scheduler, and the interrupt handler — the three pieces of code that need a lock before there is
anything to schedule.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;name&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ordering&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the five C11 orderings — &lt;code&gt;Relaxed&lt;/code&gt;, &lt;code&gt;Acquire&lt;/code&gt;, &lt;code&gt;Release&lt;/code&gt;, &lt;code&gt;AcqRel&lt;/code&gt;, &lt;code&gt;SeqCst&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Atomic[T]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one word, and the nine operations that touch it indivisibly&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SpinLock&lt;/code&gt;&lt;/td&gt;&lt;td&gt;mutual exclusion held by spinning rather than by sleeping&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;This is the &lt;code&gt;*T&lt;/code&gt; tier of concurrency in the same sense &lt;code&gt;*T&lt;/code&gt; is the unsafe tier of memory: nothing
here is checked, everything is greppable, and it is how a kernel is written. What sits above it —
&lt;code&gt;Mutex[T]&lt;/code&gt;, &lt;code&gt;spawn&lt;/code&gt;, and the crossing rule — is on the &lt;a href=&quot;/library/threads/&quot;&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt;&lt;/a&gt; page.&lt;/p&gt;
&lt;h2 id=&quot;ordering&quot;&gt;&lt;code&gt;Ordering&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;An ordering is &lt;strong&gt;not a property of the value&lt;/strong&gt;. Every ordering reads the same bits; what differs is
the promise about what &lt;em&gt;else&lt;/em&gt; is guaranteed to have happened around the read. That is why it is an
argument rather than something fixed on the variable: the same word is read with &lt;code&gt;Relaxed&lt;/code&gt; in a
statistics counter and with &lt;code&gt;Acquire&lt;/code&gt; in the handoff that publishes a structure, and only the
operation knows which it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;These are C11’s and LLVM’s, named the same way.&lt;/strong&gt; Nothing here is sysl’s invention, so the
standards text and the machine documentation a reader already has apply unchanged.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;ordering&lt;/th&gt;&lt;th&gt;what it promises&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Relaxed&lt;/code&gt;&lt;/td&gt;&lt;td&gt;nothing but indivisibility — correct for a counter read once at the end&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Acquire&lt;/code&gt;&lt;/td&gt;&lt;td&gt;everything the releasing thread wrote before its release is visible here afterwards&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Release&lt;/code&gt;&lt;/td&gt;&lt;td&gt;everything written before this becomes visible to whoever acquires it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;AcqRel&lt;/code&gt;&lt;/td&gt;&lt;td&gt;both, for a read-modify-write that is a handoff in each direction at once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;SeqCst&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every thread agrees on one order for all &lt;code&gt;SeqCst&lt;/code&gt; operations in the program&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;SeqCst&lt;/code&gt; is the strongest and the slowest, and it is what every method here defaults to, because it
is the one that makes an ordinary program behave the way its author read it.&lt;/p&gt;
&lt;h3 id=&quot;a-load-and-a-store-take-three-of-the-five&quot;&gt;A load and a store take three of the five&lt;/h3&gt;
&lt;p&gt;A release publishes the writes that came before it, and &lt;strong&gt;a load makes none&lt;/strong&gt;; an acquire sees what
a release published, and &lt;strong&gt;a store reads nothing&lt;/strong&gt;. So &lt;code&gt;Release&lt;/code&gt; and &lt;code&gt;AcqRel&lt;/code&gt; name loads that do not
exist, &lt;code&gt;Acquire&lt;/code&gt; and &lt;code&gt;AcqRel&lt;/code&gt; name stores that do not exist, and no machine has an instruction for
any of them. &lt;code&gt;Ordering&lt;/code&gt; answers the question directly, which is what lets a wrapper taking an
ordering as a &lt;em&gt;value&lt;/em&gt; check it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;SeqCst&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_load&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Release&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_load&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;AcqRel&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_load&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;SeqCst&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_store&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Acquire&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_store&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;AcqRel&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;orders_a_store&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false false
true false false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the two rows against each other: &lt;code&gt;SeqCst&lt;/code&gt; is in both, and it is worth being clear that this is
not a special case. It is stronger than an acquire rather than a release in disguise, and stronger
than a release rather than an acquire in disguise, so it orders either operation. &lt;code&gt;AcqRel&lt;/code&gt; is in
neither, because it is exactly the ordering that asks for both halves at once.&lt;/p&gt;
&lt;p&gt;This is a fact about what the operations &lt;em&gt;are&lt;/em&gt;, not about any particular machine, and &lt;strong&gt;a stronger
processor would not lift it&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-ordering-is-written-at-the-call&quot;&gt;The ordering is written at the call&lt;/h2&gt;
&lt;p&gt;Below &lt;code&gt;Atomic[T]&lt;/code&gt; sit nine forms in the language’s raw tier, beside &lt;code&gt;sizeof&lt;/code&gt; and &lt;code&gt;ptr_cast&lt;/code&gt;. Each is
one machine instruction that no sysl body could have written, and each takes an &lt;strong&gt;address&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;atomic_load(p, ord)                  atomic_swap(p, v, ord)
atomic_store(p, v, ord)              atomic_cas(p, expected, desired, ord)
atomic_add / _sub / _and / _or / _xor(p, v, ord)
atomic_fence(ord)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The ordering on one of these has to be &lt;strong&gt;one of &lt;code&gt;Ordering&lt;/code&gt;‘s names, spelled there&lt;/strong&gt;, because it
becomes a keyword in the emitted instruction rather than a value the instruction reads. An ordering
held in a variable is well-typed sysl that cannot be lowered:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ord = &lt;span class=&quot;hl-type&quot;&gt;Acquire&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;atomic_load&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;q.v, ord))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;atomic_load&apos; spells its ordering into the instruction, so it has to be one of Ordering&apos;s names written here — not a value carrying one. Where a caller chooses, branch on their choice and write a call per ordering
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last clause is the whole implementation strategy of the module above: each method on &lt;code&gt;Atomic[T]&lt;/code&gt;
is a match from the ordering it was &lt;em&gt;given&lt;/em&gt; to the ordering it &lt;em&gt;writes&lt;/em&gt;, one arm per name. That is
also what &lt;code&gt;core::sync::atomic&lt;/code&gt; does in Rust, for the same reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And it costs nothing.&lt;/strong&gt; At every ordinary call the scrutinee is a constant, so the match folds
away and the method call becomes the single instruction it names. Measured on AArch64 at &lt;code&gt;-O1&lt;/code&gt;:
&lt;code&gt;a.add(1)&lt;/code&gt; is &lt;code&gt;ldaddal&lt;/code&gt;, &lt;code&gt;a.add(1, Relaxed)&lt;/code&gt; is &lt;code&gt;ldadd&lt;/code&gt;, &lt;code&gt;a.load(Acquire)&lt;/code&gt; is &lt;code&gt;ldapr&lt;/code&gt;, and
&lt;code&gt;a.store(v, Release)&lt;/code&gt; is &lt;code&gt;stlr&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-module-is-the-gate&quot;&gt;The module is the gate&lt;/h3&gt;
&lt;p&gt;The five names live in &lt;code&gt;sysl.sync&lt;/code&gt; and nowhere else, and none of the nine forms accepts a name a
program declared for itself. So a program that never imported the module has &lt;strong&gt;no ordering it can
write&lt;/strong&gt;, and the raw tier is closed to it by the ordinary rules about names rather than by a rule of
its own. Importing the type is not importing the names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.&lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Relaxed&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;undefined name &apos;Relaxed&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import sysl.sync.*&lt;/code&gt; is therefore the ordinary way to reach this module — there are seven names in
it, five of them are orderings, and a program using the sixth almost always wants some of the five.&lt;/p&gt;
&lt;h3 id=&quot;a-fence-has-no-wrapper-and-the-omission-is-deliberate&quot;&gt;A fence has no wrapper, and the omission is deliberate&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;atomic_fence(ord)&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; the fence. It is a barrier the whole thread passes through rather than an
operation on any one location, so there is no value for it to be a member of and nothing for a
struct to hold. What a free function beside it could add is the default — and the default is what it
could not survive, because &lt;code&gt;Relaxed&lt;/code&gt; is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-function&quot;&gt;atomic_fence&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Relaxed&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a fence is nothing but its ordering, so &apos;Relaxed&apos; would ask for a barrier that orders nothing — write &apos;Acquire&apos;, &apos;Release&apos;, &apos;AcqRel&apos; or &apos;SeqCst&apos;, or drop the fence
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A wrapper taking an &lt;code&gt;Ordering&lt;/code&gt; would need a &lt;code&gt;Relaxed&lt;/code&gt; arm, and the only two things that arm could do
are call a form that refuses it or quietly do nothing. Softening that diagnostic is worse than
writing the form out, so the form is what a program writes.&lt;/p&gt;
&lt;h2 id=&quot;atomic-t&quot;&gt;&lt;code&gt;Atomic[T]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Atomic[T]&lt;/code&gt; is an &lt;strong&gt;ordinary struct with one field&lt;/strong&gt;, and its methods take the address of that field
and hand it to the forms above. There is nothing else to it, and that is the point: the type a
program reaches for lives in the library where a reader can open it, rather than inside the compiler
where they cannot.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

a.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; was = a.&lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(was, a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every method takes a &lt;code&gt;*self&lt;/code&gt; receiver, including &lt;code&gt;load&lt;/code&gt;&lt;/strong&gt; — and that is worth stating, because a
read looks like it should not need one. A &lt;code&gt;self&lt;/code&gt; receiver is handed a &lt;strong&gt;copy&lt;/strong&gt; of the struct, and
the address of a copy is not the address the other threads are writing to. It would compile, it
would be atomic, and it would read the wrong word.&lt;/p&gt;
&lt;h3 id=&quot;every-read-modify-write-answers-what-was-there-before&quot;&gt;Every read-modify-write answers what was there before&lt;/h3&gt;
&lt;p&gt;That is the property, and it is what makes an atomic increment usable as a &lt;strong&gt;ticket&lt;/strong&gt;: every caller
gets a different number and none of them is skipped.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; next = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t1 = next.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t2 = next.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t3 = next.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t1, t2, t3, next.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 1 2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same shape covers the bitwise members. &lt;code&gt;or&lt;/code&gt; is how a flag is set in a word other threads are
setting their own flags in, and the answer tells the caller whether it was the one that set it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; flags = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0b1100&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o = flags.&lt;span class=&quot;hl-function&quot;&gt;or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0b0011&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = flags.&lt;span class=&quot;hl-function&quot;&gt;and&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0b0110&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x = flags.&lt;span class=&quot;hl-function&quot;&gt;xor&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0b1111&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(o, n, x, flags.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12 15 6 9
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;cas-answers-the-value-it-found&quot;&gt;&lt;code&gt;cas&lt;/code&gt; answers the value it found&lt;/h3&gt;
&lt;p&gt;Not a &lt;code&gt;bool&lt;/code&gt;, and not an &lt;code&gt;Option&lt;/code&gt;. A caller learns whether it swapped by comparing the answer
against what it expected — one comparison it was going to make anyway — and &lt;strong&gt;on failure the answer
is the value to retry against&lt;/strong&gt;, so the whole retry loop is one line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; slot = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; seen = slot.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; slot.&lt;span class=&quot;hl-function&quot;&gt;cas&lt;/span&gt;(seen, seen * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;) != seen
    seen = slot.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(seen, slot.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing else is running here, so the exchange succeeded the first time round and the body never
ran — which is the ordinary case, and the reason the loop is worth writing this way rather than as a
&lt;code&gt;bool&lt;/code&gt; plus a second load.&lt;/p&gt;
&lt;h3 id=&quot;naming-another-ordering&quot;&gt;Naming another ordering&lt;/h3&gt;
&lt;p&gt;An ordering on the surface is a parameter with a default, and this is the one place in the design
where the ordering is not written at the raw call — it is written at &lt;em&gt;this&lt;/em&gt; call, one level up:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; stats = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
    stats.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Relaxed&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(stats.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Acquire&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-t-may-be&quot;&gt;What &lt;code&gt;T&lt;/code&gt; may be&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;An integer of 8, 16, 32 or 64 bits, or a pointer&lt;/strong&gt; — what the machine has an instruction for.
Nothing in the declaration says so, and there is no bound that could: sysl’s integers are an
&lt;a href=&quot;/reference/generics/&quot;&gt;open family&lt;/a&gt;, so &lt;code&gt;u12&lt;/code&gt; is a type a program may name and no &lt;code&gt;impl&lt;/code&gt; list could
have covered it. What refuses the type is the &lt;strong&gt;form inside&lt;/strong&gt;, where the instruction would have had
to be chosen:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(0u12)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(wide.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;atomic_load&apos; is one machine instruction, and a machine has one for 8, 16, 32 and 64 bits — u12 is 12, so there is nothing to emit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An aggregate is refused for a different reason and with a different message, because it is a
different mistake — there is no width to round to, and what the author wanted was a lock:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; here = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(here.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;().x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;atomic_load&apos; reaches a word the machine can touch indivisibly — an integer of 8, 16, 32 or 64 bits, or a pointer — and Point is neither
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A float is in the same position, and it is the one people are most surprised by — a &lt;code&gt;real&lt;/code&gt; is 64
bits wide and there is still no instruction that loads one atomically as a float:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;atomic_load&apos; reaches a word the machine can touch indivisibly — an integer of 8, 16, 32 or 64 bits, or a pointer — and real is neither. An aggregate is what a &apos;SpinLock&apos; or a &apos;&amp;amp;sync Mutex[T]&apos; is for (`06`)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The arithmetic members are refused on a pointer&lt;/strong&gt;, and for a third reason again: an address plus a
number is a question the raw tier does not answer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; raw: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(raw)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sum = ap.&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(raw)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sum == &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;atomic_add&apos; is arithmetic, and what an address plus a number means is the question the raw tier does not answer — use &apos;atomic_swap&apos; or &apos;atomic_cas&apos; to change a pointer, or do the arithmetic on a &apos;usize&apos; beside it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Read where those four diagnostics point.&lt;/strong&gt; The caret is on a line in &lt;code&gt;library/sysl/sync/atomic.sysl&lt;/code&gt;,
not on the line the program wrote — because the form that refuses is inside the method, and the
method is ordinary library sysl like everything else here. It is the honest place for it to land,
and it is also the clearest demonstration on this page that &lt;code&gt;Atomic[T]&lt;/code&gt; really is a struct somebody
wrote rather than a type the compiler knows about.&lt;/p&gt;
&lt;h3 id=&quot;the-narrowing-on-load-and-store-lands-at-run-time&quot;&gt;The narrowing on &lt;code&gt;load&lt;/code&gt; and &lt;code&gt;store&lt;/code&gt; lands at run time&lt;/h3&gt;
&lt;p&gt;This is the one check in the module that does, and the reason is exactly the boundary the module
sits on. The &lt;strong&gt;form&lt;/strong&gt; refuses a releasing load where the name is written, and it cannot see a name
that arrived in a variable — which is precisely what a method taking an &lt;code&gt;Ordering&lt;/code&gt; hands it. So
&lt;code&gt;load&lt;/code&gt; and &lt;code&gt;store&lt;/code&gt; carry a &lt;code&gt;require&lt;/code&gt; over the two predicates above.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Release&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That compiles, and the process &lt;strong&gt;traps&lt;/strong&gt; when it runs: the contract clause lowers to a trap
instruction, so there is no message and no unwinding, the shell reports signal 5, and anything still
sitting in the output buffer never reaches the terminal. It folds away entirely wherever the
ordering was written at the call, which is every ordinary use.&lt;/p&gt;
&lt;p&gt;What the check buys is that an ordering that cannot be honoured &lt;strong&gt;stops the program&lt;/strong&gt; rather than
being quietly promoted to &lt;code&gt;SeqCst&lt;/code&gt;. Promotion would be sound — it is strictly stronger — and it is
not what the author asked for, which is the more useful thing to find out.&lt;/p&gt;
&lt;h3 id=&quot;reading-the-field-directly&quot;&gt;Reading the field directly&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Atomic[T].v&lt;/code&gt; is &lt;strong&gt;not hidden&lt;/strong&gt;, and that is deliberate rather than an oversight:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; done = &lt;span class=&quot;hl-type&quot;&gt;Atomic&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

done.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Release&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(done.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A thread that knows it is alone with the value — the one that built it, or the one left after every
other has been joined — is entitled to the cheap read, and hiding it would only have meant a method
doing the same thing less visibly. Everywhere else it is a data race, and it is &lt;strong&gt;greppable&lt;/strong&gt;, which
is the bargain the whole &lt;code&gt;*T&lt;/code&gt; tier makes.&lt;/p&gt;
&lt;h2 id=&quot;spinlock&quot;&gt;&lt;code&gt;SpinLock&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The lock a kernel has before it has a scheduler. Blocking means handing the processor to something
else, which means there is something else to hand it to — and the allocator, the scheduler’s own run
queue, and an interrupt handler are all code that has to take a lock before any of that exists.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.sync.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; lk = &lt;span class=&quot;hl-type&quot;&gt;SpinLock&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; first = lk.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; second = lk.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(first, second, lk.held)

lk.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; third = lk.&lt;span class=&quot;hl-function&quot;&gt;try_lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(lk.held, third)

lk.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()
lk.&lt;span class=&quot;hl-function&quot;&gt;lock&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(lk.held)

lk.&lt;span class=&quot;hl-function&quot;&gt;unlock&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false 1
1 true
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;try_lock&lt;/code&gt; never spins and answers whether it took the lock; &lt;code&gt;lock&lt;/code&gt; spins until it is free. Neither
takes an &lt;code&gt;Ordering&lt;/code&gt; and there is no overload that does, because &lt;strong&gt;a lock’s orderings are fixed by
what a lock means&lt;/strong&gt;: the exchange that takes it is an acquire, the store that frees it is a release,
and that pairing is the whole of what makes the guarded data safe to touch.&lt;/p&gt;
&lt;h3 id=&quot;three-things-it-will-not-do-for-you&quot;&gt;Three things it will not do for you&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;It guards nothing by construction.&lt;/strong&gt; A spinlock is a flag beside the data, and what the data is
stays the programmer’s to remember. That is the difference against
&lt;a href=&quot;/library/threads/#mutex-t&quot;&gt;&lt;code&gt;Mutex[T]&lt;/code&gt;&lt;/a&gt;, which owns what it protects — and it is deliberate, because
the code that needs a spinlock is code that is also reaching through raw pointers, where a type that
owned its contents would have nothing coherent to own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing checks that the releasing thread is the one that took it&lt;/strong&gt;, or that it was held at all.
That would be a second word to maintain on every take, paid by every correct program, to diagnose a
bug the discipline below already asks the reader to hold to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A thread that spins burns its processor for as long as it waits.&lt;/strong&gt; So this is right only where the
hold is short and bounded: a few instructions under the lock, no allocation, no system call, and
above all no second lock. Where a wait may be long, or where the holder might be descheduled
mid-hold, the answer is a &lt;code&gt;Mutex[T]&lt;/code&gt; and a real blocking primitive underneath it. &lt;strong&gt;On one processor
with no preemption a spin is a deadlock outright&lt;/strong&gt; — nothing can release what nothing else is
running to release.&lt;/p&gt;
&lt;h3 id=&quot;why-the-flag-is-not-an-atomic-i32&quot;&gt;Why the flag is not an &lt;code&gt;Atomic[i32]&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;It is used as exactly that, and it is written as three raw calls anyway. &lt;code&gt;SpinLock&lt;/code&gt; is declared in
the same file as &lt;code&gt;Atomic[T]&lt;/code&gt;, and a lock whose entire implementation is three atomic operations
reads better as those three than as a wrapper around a wrapper.&lt;/p&gt;
&lt;p&gt;The implementation is worth reading for one detail, which is that &lt;code&gt;lock&lt;/code&gt; &lt;strong&gt;does not spin on the
exchange&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;atomic_swap&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.held, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Acquire&lt;/span&gt;) != &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; busy = &lt;span class=&quot;hl-function&quot;&gt;atomic_load&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.held, &lt;span class=&quot;hl-type&quot;&gt;Relaxed&lt;/span&gt;)

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; busy != &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
        busy = &lt;span class=&quot;hl-function&quot;&gt;atomic_load&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.held, &lt;span class=&quot;hl-type&quot;&gt;Relaxed&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A read-modify-write has to take the cache line exclusively every time round, so waiters spinning on
the exchange itself fight each other for the line — and worse, they fight the holder trying to write
the release, which is the one thread whose progress everybody is waiting on. A relaxed load spins in
a shared line and costs nobody anything.&lt;/p&gt;
&lt;h2 id=&quot;what-is-not-here&quot;&gt;What is not here&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt; is not a synchronization tool&lt;/strong&gt;, and the mistake is worth naming because C’s own
reference material used to recommend the qualifier for shared variables. It constrains the
&lt;em&gt;compiler&lt;/em&gt; — it stops accesses being elided, merged, or reordered relative to one another — and says
nothing about other cores, about ordering, or about tearing. It is for
&lt;a href=&quot;/reference/memory/&quot;&gt;device memory&lt;/a&gt; and for nothing else. Two threads sharing a counter want
&lt;code&gt;Atomic[T]&lt;/code&gt;; a &lt;code&gt;volatile&lt;/code&gt; counter is a race with a keyword in front of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;sync T&lt;/code&gt; is the language’s, not this module’s.&lt;/strong&gt; The sigil that makes a reference’s refcount
atomic is a spelling the compiler checks, and it lives on &lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt;. It makes the
&lt;em&gt;reference&lt;/em&gt; safe to share and not the object safe to mutate — the fields are still mutable through
any alias — so &lt;code&gt;&amp;amp;sync Mutex[T]&lt;/code&gt; and &lt;code&gt;&amp;amp;sync Atomic[i32]&lt;/code&gt; are how shared mutable state is actually
reached.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no channel yet.&lt;/strong&gt; The message-passing half of the model — where the rule about which
values may cross a domain boundary is meant to be enforced — is not written. Until it is, that rule
is specification with nothing asking the question, which the &lt;a href=&quot;/library/threads/&quot;&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt;&lt;/a&gt; page
says more about, since that is where it becomes visible rather than theoretical.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/threads/&quot;&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt;&lt;/a&gt; — spawning, joining, and the mutex above the spinlock.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Structs and methods</title>
    <link href="https://sysl.sh/tour/structs/"/>
    <id>https://sysl.sh/tour/structs/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Data with a name, then behaviour beside it — and a receiver that says how the method takes the instance.</summary>
    <content type="html">&lt;h2 id=&quot;a-struct-is-its-fields&quot;&gt;A struct is its fields&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;point:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p.x, p.y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;point: 6 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Construction is positional and uses the type’s own name. There is no &lt;code&gt;new&lt;/code&gt;, and no allocation has
happened: &lt;code&gt;p&lt;/code&gt; is a value, it lives in this frame, and it is exactly as big as its fields.&lt;/p&gt;
&lt;p&gt;A struct is copied when you assign it, the same as any other value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a

b.x = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, a.x, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, b.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a: 1 b: 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is worth pausing on if you are used to a language where every object is a reference. &lt;code&gt;b = a&lt;/code&gt;
copied the point. If you want two names for &lt;em&gt;one&lt;/em&gt; object, you ask for it — and that is the
&lt;a href=&quot;/tour/memory/&quot;&gt;memory chapter&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;methods&quot;&gt;Methods&lt;/h2&gt;
&lt;p&gt;A member with a &lt;code&gt;self&lt;/code&gt; receiver is a method. The sigil on &lt;code&gt;self&lt;/code&gt; says how the method takes the
instance, exactly as it would on any other parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// A read that does not touch the original takes `self` by value.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.x + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.y

    &lt;span class=&quot;hl-comment&quot;&gt;// `*self` is a raw pointer to the instance, so the writes land in the caller&apos;s value.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;shift&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, dx: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, dy: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.x += dx
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.y += dy
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Vec2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; here = &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;before:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, here.&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;())
here.&lt;span class=&quot;hl-function&quot;&gt;shift&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;after:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, here.&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;before: 7
after: 37
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;self&lt;/code&gt; by value gets a copy, which is what a read wants and what stops a method that only reads from
being able to write. &lt;code&gt;*self&lt;/code&gt; is the receiver a mutating method takes, and it is spelled with the
same sigil that means “raw pointer” everywhere else — because that is what it is.&lt;/p&gt;
&lt;p&gt;There is no &lt;code&gt;this&lt;/code&gt; and no implicit receiver: &lt;code&gt;self&lt;/code&gt; is written, and a field access through it is
written too.&lt;/p&gt;
&lt;h2 id=&quot;properties-and-associated-functions&quot;&gt;Properties and associated functions&lt;/h2&gt;
&lt;p&gt;A member with no parameter list is a &lt;strong&gt;property&lt;/strong&gt; — it reads like a field but is computed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    area -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h
    perimeter -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; * (&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;area:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, r.area, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;perimeter:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, r.perimeter)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;area: 12 perimeter: 14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the missing parentheses at the call: &lt;code&gt;r.area&lt;/code&gt;, not &lt;code&gt;r.area()&lt;/code&gt;. The convention that goes with
that spelling is that a property is &lt;em&gt;cheap&lt;/em&gt; — anything that allocates or loops is a method, so that
the parentheses warn you.&lt;/p&gt;
&lt;p&gt;A member with no &lt;code&gt;self&lt;/code&gt; at all is an &lt;strong&gt;associated function&lt;/strong&gt;, called through the type name. It is
where a named constructor goes, since the positional &lt;code&gt;Rect(w, h)&lt;/code&gt; covers only one shape:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    area -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

    &lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(n, n)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;square:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;).area)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;square: 25
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/memory/&quot;&gt;memory&lt;/a&gt; — the three modes, and the chapter that makes sysl a different
language rather than a different syntax.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Strings</title>
    <link href="https://sysl.sh/tour/strings/"/>
    <id>https://sysl.sh/tour/strings/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>An immutable, validated `[]u8` — the same three words, with a guarantee added and an operation taken away.</summary>
    <content type="html">&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is the slice from the last chapter with one thing added and one taken away: its bytes are
guaranteed to be well-formed UTF-8, and nothing may write through it. Everything else — the three
words, the O(1) substring, the retain on slicing — is the slice machinery unchanged.&lt;/p&gt;
&lt;p&gt;That guarantee is not decoration. It is what lets &lt;code&gt;char&lt;/code&gt; mean “a Unicode scalar value” rather than
“whatever these bytes turned out to be”, and it is why there are no replacement characters anywhere
in the language: there is nothing to repair.&lt;/p&gt;
&lt;h2 id=&quot;bytes-and-characters&quot;&gt;Bytes and characters&lt;/h2&gt;
&lt;p&gt;A string is measured and indexed in &lt;strong&gt;bytes&lt;/strong&gt;, and decoded into &lt;strong&gt;characters&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;naïve&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; chars = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.chars &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; chars += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bytes:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;chars:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, chars, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;last byte:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s[s.len - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;bytes: 6 chars: 5 last byte: 101
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six bytes and five characters, because &lt;code&gt;ï&lt;/code&gt; takes two. &lt;code&gt;s[i]&lt;/code&gt; is a &lt;code&gt;u8&lt;/code&gt; — a byte, not a character —
and &lt;code&gt;s.chars&lt;/code&gt; is a cursor that decodes them one scalar value at a time.&lt;/p&gt;
&lt;p&gt;That is Go’s choice rather than Swift’s, and the reason is placement: grapheme clusters need Unicode
break tables, tables must not be in a kernel, and making them the default would put &lt;code&gt;s.len&lt;/code&gt; at O(n)
for every program that only wanted a byte offset. Grapheme clusters are a library built over this,
not the thing underneath.&lt;/p&gt;
&lt;p&gt;A substring shares its parent’s bytes and costs no copy:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; path = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/usr/local/bin&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;front:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, path[..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;], &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;back:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, path[&lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;..], &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;whole:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, path.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;front: /usr back: bin whole: 14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two checks happen there rather than one. The bounds are checked, as on any slice — and the ends are
checked for landing &lt;strong&gt;between characters&lt;/strong&gt;. Slicing through the middle of a multi-byte character
traps, because the alternative is a &lt;code&gt;string&lt;/code&gt; that is not valid UTF-8, and the whole type rests on
that not being possible.&lt;/p&gt;
&lt;p&gt;The sharing has the hazard Go’s has: a two-byte substring of a two-megabyte string keeps the whole
buffer alive. The operation that copies out of it is named — &lt;code&gt;s.copy()&lt;/code&gt; — and the hazard is
documented rather than encoded in a second type.&lt;/p&gt;
&lt;h2 id=&quot;joining&quot;&gt;Joining&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; joins two strings and &lt;code&gt;+=&lt;/code&gt; appends onto a slot. Both allocate a fresh buffer; UTF-8 is closed
under concatenation, so nothing is re-validated.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sysl&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; greeting = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + name

greeting += &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(greeting, greeting.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, sysl! 12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; is &lt;strong&gt;strict&lt;/strong&gt;. It joins a string to a string and to nothing else:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got string and int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the same no-implicit-conversion stance the numeric operators take. The written conversion is
&lt;code&gt;str(x)&lt;/code&gt;, which renders a value into its string form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count: &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; * &lt;span class=&quot;hl-number&quot;&gt;14&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;count: 42
true é 2.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every case but a string allocates a fresh buffer. A &lt;code&gt;bool&lt;/code&gt; renders to one of two literals and
allocates nothing at all, and a struct or an enum renders through its &lt;code&gt;Display&lt;/code&gt; implementation.&lt;/p&gt;
&lt;h2 id=&quot;interpolation&quot;&gt;Interpolation&lt;/h2&gt;
&lt;p&gt;Writing &lt;code&gt;str&lt;/code&gt; at every splice gets old, so a literal may carry a prefix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; word = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ratio = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt; / &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n is $n, and twice that is &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%6d&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;] [&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;word&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%-6s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;ratio&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%.3f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;n is 42, and twice that is 84
[    42] [left  ] 0.667
a\nb
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;s&amp;quot;…&amp;quot;&lt;/code&gt; splices &lt;code&gt;$name&lt;/code&gt; or &lt;code&gt;${ expression }&lt;/code&gt;, each rendered by &lt;code&gt;str&lt;/code&gt; — so &lt;code&gt;s&amp;quot;a${e}b&amp;quot;&lt;/code&gt; is exactly
&lt;code&gt;&amp;quot;a&amp;quot; + str(e) + &amp;quot;b&amp;quot;&lt;/code&gt;, and interpolation is not a new kind of value. &lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt; adds one thing: a hole may
be followed by a printf specifier controlling width, precision and justification, checked against the
value’s type while compiling. &lt;code&gt;raw&amp;quot;…&amp;quot;&lt;/code&gt; leaves a backslash as an ordinary character.&lt;/p&gt;
&lt;p&gt;Note where the specifier sits — &lt;em&gt;after&lt;/em&gt; the hole, not in a separate format string at the front. The
value and the way it is formatted stay next to each other, which is the whole reason for the
spelling.&lt;/p&gt;
&lt;h2 id=&quot;literals-that-span-lines&quot;&gt;Literals that span lines&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; doc = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    to whom it may concern:&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    the indentation you see here is not in the value&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(doc.len)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(doc)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;73
to whom it may concern:
the indentation you see here is not in the value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The content starts on the line &lt;em&gt;after&lt;/em&gt; the opening delimiter, and each line’s incidental indentation
is dropped — the strip is the least-indented line with content, together with the closing delimiter’s
own line when it sits alone. So the closing delimiter is the control: move it left and the value
keeps more indentation, right and it keeps less.&lt;/p&gt;
&lt;p&gt;This matters more in an indentation-sensitive language than elsewhere. A block written inside a
deeply nested body would otherwise carry that body’s indentation into its value, and how deep a piece
of code sits is not something its data should record.&lt;/p&gt;
&lt;p&gt;Trailing blanks are dropped too, since whitespace at the end of a line is invisible in a source file.
A trailing space that is &lt;em&gt;meant&lt;/em&gt; is written &lt;code&gt;\u{20}&lt;/code&gt;, which survives because escapes are decoded after
the trimming. And a &lt;code&gt;\&lt;/code&gt; at the end of a line joins it to the next, which is what the form is really
for: a blob of embedded data written over twenty lines is a single constant, where the same data
assembled with &lt;code&gt;+&lt;/code&gt; would allocate and copy once per piece.&lt;/p&gt;
&lt;h2 id=&quot;comparison-and-matching&quot;&gt;Comparison, and matching&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;==&lt;/code&gt; and &lt;code&gt;&amp;lt;&lt;/code&gt; compare the byte sequences, which for well-formed UTF-8 is also codepoint order.
Normalization is &lt;strong&gt;not&lt;/strong&gt; applied — a composed &lt;code&gt;é&lt;/code&gt; does not equal a decomposed one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(cmd: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    cmd &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;combines&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;removes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        _     -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nope&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &amp;lt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;del&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;combines unknown true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Swift compares by canonical equivalence, which is right for user-facing text and surprising in
systems code, where a string is usually a path, a device name, or a protocol token that has to
compare as the bytes it is. Normalization is a library operation, applied where it is wanted and
visible when it costs something.&lt;/p&gt;
&lt;h2 id=&quot;building-text-a-piece-at-a-time&quot;&gt;Building text a piece at a time&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+=&lt;/code&gt; in a loop copies everything gathered so far on every step. &lt;code&gt;StrBuilder&lt;/code&gt; keeps one growable
buffer instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;items:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
    b.&lt;span class=&quot;hl-function&quot;&gt;push_char&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos; &apos;&lt;/span&gt;)
    b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(i))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;items: 1 2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two ways in are the two that keep the guarantee: a &lt;code&gt;push&lt;/code&gt; takes a string and a &lt;code&gt;push_char&lt;/code&gt; takes
a character, and UTF-8 is closed under appending either — so &lt;code&gt;finish&lt;/code&gt; hands back a plain &lt;code&gt;string&lt;/code&gt;
that nobody has to validate. That is exactly why a builder is &lt;em&gt;not&lt;/em&gt; a &lt;code&gt;Writer&lt;/code&gt;: a public &lt;code&gt;write&lt;/code&gt;
taking arbitrary bytes would be an unchecked constructor with a friendlier name.&lt;/p&gt;
&lt;h2 id=&quot;coming-from-bytes&quot;&gt;Coming from bytes&lt;/h2&gt;
&lt;p&gt;Bytes a program computed are the one route into a string that can fail, so it is the one that returns
a &lt;code&gt;Result&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; good: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;105&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;33&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;  = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(good) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(s)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;text:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bad at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset)

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(bad) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(s)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;text:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bad at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;truncated:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.truncated)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;text: hi!
bad at 1 truncated: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error carries the offending offset and one distinction a caller can act on: whether the input
merely &lt;em&gt;ended&lt;/em&gt; mid-sequence, which more bytes would fix, or holds something no continuation could
rescue.&lt;/p&gt;
&lt;p&gt;The bytes are copied rather than viewed, and that is deliberate — a slice is writable, so sharing
would let a later write change something that had already been checked. Copying is what makes the
validation mean anything afterwards.&lt;/p&gt;
&lt;h2 id=&quot;talking-to-c&quot;&gt;Talking to C&lt;/h2&gt;
&lt;p&gt;A sysl string carries a length and may hold a NUL as an ordinary byte, so there is no free conversion
to the shape C reads. For a literal there is no conversion needed at all — the compiler emits a NUL
after every string literal in read-only data, and &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt; is that constant’s address:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;printf&lt;/span&gt;(fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;%d items&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 items
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No allocation, no copy, no runtime. For a string that is not a literal, &lt;code&gt;cstring(s)&lt;/code&gt; allocates a
NUL-terminated copy and hands back a &lt;code&gt;CString&lt;/code&gt; that owns it — and the hazard the explicitness exists
for is worth stating as an equation: for &lt;code&gt;cstring(&amp;quot;a\0b&amp;quot;)&lt;/code&gt;, &lt;code&gt;cs.len&lt;/code&gt; is 3 and C’s &lt;code&gt;strlen(cs.ptr)&lt;/code&gt; is&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Both are right, and neither can be made into the other.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;literals-cost-nothing&quot;&gt;Literals cost nothing&lt;/h2&gt;
&lt;p&gt;A string literal is bytes in read-only data with &lt;strong&gt;no owner at all&lt;/strong&gt; — the owner word is null, and
retain and release both test for that and do nothing. So a literal needs no allocation, no refcount
traffic, and not even an instruction to build.&lt;/p&gt;
&lt;p&gt;That is what lets allocator-free code hold, pass, compare and slice strings: panic messages, device
node names, format fragments. Anything derived from a literal by slicing is immortal too, because it
shares the owner — which is to say it shares having none.&lt;/p&gt;
&lt;p&gt;The rule for the whole type is that the &lt;em&gt;type&lt;/em&gt; is not gated, the &lt;em&gt;allocating operations&lt;/em&gt; are. Holding,
passing, comparing, indexing, slicing and iterating any string are free; the ones that make new bytes
— &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;copy()&lt;/code&gt;, &lt;code&gt;from_utf8&lt;/code&gt;, &lt;code&gt;str_builder&lt;/code&gt;, &lt;code&gt;cstring&lt;/code&gt; — are the ones a &lt;code&gt;no alloc&lt;/code&gt; module may
not reach.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/enums/&quot;&gt;enums and patterns&lt;/a&gt; — where &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; come from, and what &lt;code&gt;match&lt;/code&gt;
can really do.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Strings</title>
    <link href="https://sysl.sh/reference/strings/"/>
    <id>https://sysl.sh/reference/strings/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>An immutable, validated `[]u8` — the representation, the guarantee, every form that makes new bytes, and where the allocator line falls.</summary>
    <content type="html">&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is a &lt;strong&gt;three-word owning view of validated UTF-8 bytes&lt;/strong&gt; — the same shape every
&lt;a href=&quot;/reference/arrays/&quot;&gt;slice&lt;/a&gt; has, with one thing added and one taken away:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;owner&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the counted buffer keeping the bytes alive, or &lt;strong&gt;null&lt;/strong&gt; for immortal bytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ptr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the first byte of &lt;em&gt;this&lt;/em&gt; string — an interior pointer into the owner’s bytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;len&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the length in &lt;strong&gt;bytes&lt;/strong&gt;, not characters&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Added: the bytes are guaranteed well-formed UTF-8. Taken away: nothing may write through it. Every
rule on the &lt;a href=&quot;/reference/arrays/&quot;&gt;arrays page&lt;/a&gt; about indexing, slicing, length and ownership is
therefore true here too, and this page is the two differences and what follows from them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ptr&lt;/code&gt; is separate from &lt;code&gt;owner&lt;/code&gt; because a substring must name a range inside its parent’s buffer
while still keeping that parent alive.&lt;/strong&gt; Two words cannot do both jobs: with only &lt;code&gt;{ptr, len}&lt;/code&gt;,
release has no way back to the buffer header, so either substrings copy or lifetime goes unchecked.
The third word buys O(1) substring sharing for eight bytes.&lt;/p&gt;
&lt;p&gt;That is the trade against the three languages this came from. Go’s two words work because a garbage
collector owns the bytes and can find the object from an interior pointer; sysl has no collector, so
those two words leave lifetime unanswered. Swift’s packed sixteen hide three representations behind a
discriminator, require an allocator unconditionally, and carry a grapheme-cluster element type whose
break tables cannot be in a kernel. Rust’s split — a &lt;code&gt;&amp;amp;str&lt;/code&gt; view against an owning &lt;code&gt;String&lt;/code&gt; — is the
honest two-word answer, and the price is that every signature and every programmer chooses between
two types. One type at three words is the trade this language prefers.&lt;/p&gt;
&lt;h2 id=&quot;validity&quot;&gt;Validity&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Every &lt;code&gt;string&lt;/code&gt; is well-formed UTF-8.&lt;/strong&gt; This follows &lt;code&gt;char&lt;/code&gt;, which already enforces that its value
is a Unicode scalar value: a &lt;code&gt;string&lt;/code&gt; that could hold arbitrary bytes would make decoding partial
again, and would hand a decoder a way to produce a &lt;code&gt;char&lt;/code&gt; that cannot exist.&lt;/p&gt;
&lt;p&gt;This is Swift’s guarantee rather than Go’s. Go strings are arbitrary bytes that are UTF-8 by
convention, so its decoder must substitute U+FFFD and advance one byte on malformed input. Here there
is no repair path, because there is nothing to repair.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;from&lt;/th&gt;&lt;th&gt;spelling&lt;/th&gt;&lt;th&gt;behaviour&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a literal&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;quot;héllo&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;validated while compiling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;bytes&lt;/td&gt;&lt;td&gt;&lt;code&gt;from_utf8(b: []const u8)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;validates; the error names the byte offset&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;bytes, trusted&lt;/td&gt;&lt;td&gt;&lt;code&gt;from_utf8_unchecked(b)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;unsafe&lt;/strong&gt; — the long name is the point: it stays greppable&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string(c)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;encodes one scalar value&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; good: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0xC3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0xA9&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0xC3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0x28&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(good) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t.len, t)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bad&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset)

&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(bad) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(t) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, t.len)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bad at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;truncated:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.truncated)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ok 2 é
bad at 0 truncated: false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Utf8Error&lt;/code&gt; carries one thing besides the offset: whether the input merely &lt;em&gt;ended&lt;/em&gt; in the middle of
a sequence.&lt;/strong&gt; That is the only distinction a caller can act on differently — more bytes would fix an
unfinished sequence and could never fix a wrong one — which is why it is a field rather than a
taxonomy of fault names nobody would match on. The pair above is the difference: &lt;code&gt;C3 28&lt;/code&gt; is a lead
byte followed by something that is not a continuation, so no amount of further input rescues it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The validator is Unicode’s well-formedness table, not a decode-then-range-check&lt;/strong&gt;, and the
difference is not stylistic. In the table the &lt;em&gt;lead&lt;/em&gt; byte fixes the legal range of the byte after it
— &lt;code&gt;E0&lt;/code&gt; demands &lt;code&gt;A0..BF&lt;/code&gt;, &lt;code&gt;ED&lt;/code&gt; only &lt;code&gt;80..9F&lt;/code&gt;, &lt;code&gt;F0&lt;/code&gt; demands &lt;code&gt;90..BF&lt;/code&gt;, &lt;code&gt;F4&lt;/code&gt; only &lt;code&gt;80..8F&lt;/code&gt; — so an
overlong encoding, a surrogate, and a value past &lt;code&gt;10FFFF&lt;/code&gt; are all rejected at the second byte, by the
same test, before any codepoint is assembled. Written the other way each needs its own check and each
is its own chance to be forgotten.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;from_utf8&lt;/code&gt; copies rather than views.&lt;/strong&gt; A &lt;code&gt;string&lt;/code&gt; could in principle share a &lt;code&gt;[]u8&lt;/code&gt;‘s owner, which
would make the conversion O(1) — but a slice is writable and a string is not, so a later write
through the slice would change a value that had already been checked. Copying is what makes
validation mean anything afterwards, and it is why that entry requires an allocator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The division of labour is the reason &lt;code&gt;from_utf8&lt;/code&gt; is not built in.&lt;/strong&gt; The compiler supplies exactly
one primitive — &lt;code&gt;from_utf8_unchecked&lt;/code&gt;, which is a &lt;code&gt;[]u8&lt;/code&gt; taken as a &lt;code&gt;string&lt;/code&gt; with nothing looked at —
and the validator on top of it is ordinary sysl in &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;. What no sysl body
could do is that last line, because every safe route to a &lt;code&gt;string&lt;/code&gt; already carries the guarantee.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bytes: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;104&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;105&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;33&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8_unchecked&lt;/span&gt;(bytes))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hi!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It needs no import: it is a compiler primitive, deliberately in the same category as a raw pointer,
because breaking the UTF-8 invariant breaks &lt;code&gt;char&lt;/code&gt;‘s invariant downstream.&lt;/p&gt;
&lt;h2 id=&quot;immortal-bytes&quot;&gt;Immortal bytes&lt;/h2&gt;
&lt;p&gt;A string literal is bytes in read-only data with &lt;strong&gt;no owner at all&lt;/strong&gt; — the owner word is null, and
retain and release both test for that and do nothing. Three consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A literal costs no allocation and no refcount traffic. It is a &lt;em&gt;constant&lt;/em&gt;, so it needs no
instruction to build either.&lt;/li&gt;
&lt;li&gt;Allocator-free code can hold, pass, compare, index and slice literals.&lt;/li&gt;
&lt;li&gt;Any string derived from a literal by slicing is immortal too, because it shares the owner.&lt;/li&gt;
&lt;li&gt;A module-level &lt;code&gt;val&lt;/code&gt; holds one with no code running first. Module storage may hold a built string
too, and never releases it; a literal is the case that needs no prologue at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A sentinel refcount in a header would say the same thing. The null owner is better because it is not
string-specific: it is already how a slice of static storage says “nothing to keep alive”, so
immortality needs no mechanism of its own.&lt;/p&gt;
&lt;h2 id=&quot;granularity-bytes-and-scalar-values&quot;&gt;Granularity: bytes and scalar values&lt;/h2&gt;
&lt;p&gt;A string is indexed and measured in &lt;strong&gt;bytes&lt;/strong&gt;, and decoded into &lt;strong&gt;&lt;code&gt;char&lt;/code&gt;&lt;/strong&gt; — Unicode scalar values.
Grapheme clusters are a library built over the scalar view, not the element type.&lt;/p&gt;
&lt;p&gt;The reason is where the Unicode data would have to live. Grapheme breaking needs tables that must not
be in a kernel, and making the default element type the one that requires them would put a length at
O(n) and force an opaque index type on every program that just wants a byte offset. Go’s choice is
right for a systems language; Swift’s is right for an application language.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;operation&lt;/th&gt;&lt;th&gt;spelling&lt;/th&gt;&lt;th&gt;cost&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;byte length&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.len&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;byte at an index&lt;/td&gt;&lt;td&gt;&lt;code&gt;s[i] -&amp;gt; u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1), bounds-checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;substring&lt;/td&gt;&lt;td&gt;&lt;code&gt;s[a..b] -&amp;gt; string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1), shares; bounds-checked &lt;strong&gt;and&lt;/strong&gt; boundary-checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;bytes&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.bytes -&amp;gt; []const u8&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1) view&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;scalar values&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.chars&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(1) per step, total — no replacement characters&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;copy out&lt;/td&gt;&lt;td&gt;&lt;code&gt;s.copy()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(n), allocates; releases the parent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;concatenation&lt;/td&gt;&lt;td&gt;&lt;code&gt;a + b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;O(n), allocates&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;repeated append&lt;/td&gt;&lt;td&gt;&lt;code&gt;str_builder()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;amortized&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.len, s[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], s[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], s[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.chars &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(count, s.bytes.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 104 195 169
5 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six bytes, five characters, and the &lt;code&gt;é&lt;/code&gt; is the two bytes &lt;code&gt;195 169&lt;/code&gt; sitting where one index used to be
enough. That gap between the two counts is the whole of what this section is about.&lt;/p&gt;
&lt;h3 id=&quot;indexing-gives-a-byte-and-there-is-no-way-to-write-one&quot;&gt;Indexing gives a byte, and there is no way to write one&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

s[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;65&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a string is immutable, so its bytes have no address to write through
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;s.bytes&lt;/code&gt; does not open a way round it, and gets a diagnostic of its own that says why:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

s.bytes[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;65&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;bytes&apos; views the string&apos;s own storage rather than a copy of it — so writing through one is writing the string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bytes are a &lt;code&gt;[]const u8&lt;/code&gt;, which is the type that records exactly this, and the way out is the one
that type always names: copy them into a &lt;code&gt;[]u8&lt;/code&gt; of your own first.&lt;/p&gt;
&lt;h3 id=&quot;slicing-is-boundary-checked&quot;&gt;Slicing is boundary-checked&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], s[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], s[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;..])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;h é llo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;s[a..b]&lt;/code&gt; must land on scalar-value boundaries at &lt;strong&gt;both&lt;/strong&gt; ends. Landing mid-character traps, in the
same runtime-safety category as a bounds check and a failed &lt;code&gt;char(u)&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Byte 2 is the second half of the &lt;code&gt;é&lt;/code&gt;, so that program stops there — no message, no unwinding.&lt;/p&gt;
&lt;p&gt;Go permits the mid-character slice and lets you build an invalid string with it. That option is
closed here by the validity guarantee, and it is closed for a string that arrived through &lt;code&gt;from_utf8&lt;/code&gt;
exactly as it is for a literal: validating at the door is worth nothing if something downstream may
undo it.&lt;/p&gt;
&lt;h3 id=&quot;walking-the-characters&quot;&gt;Walking the characters&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;s.chars&lt;/code&gt; is a &lt;strong&gt;cursor&lt;/strong&gt; — a value implementing &lt;code&gt;Iterate[char]&lt;/code&gt; — and it is the one row of the table
above that could not be a value or a view. Every other row yields a value; this one yields a
&lt;em&gt;sequence&lt;/em&gt;, and the decoding is what makes the scalar values, so something has to carry a position
and answer “the next one”.&lt;/p&gt;
&lt;p&gt;The cursor validates nothing. A &lt;code&gt;string&lt;/code&gt; is well-formed by construction, so the decoding reads the
length off the lead byte and takes the continuation bytes as given — which is why the cost is O(1)
per step and why there are no replacement characters to hand back.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;for&lt;/code&gt; walks a &lt;strong&gt;copy&lt;/strong&gt; of a cursor, so a loop cannot be asked afterwards where it got to. A program
that needs to know drives the cursor itself, and gets three more answers, all by value, so asking
consumes nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cur = s.chars

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cur.offset, cur.&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(), cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

cur.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cur.offset, cur.&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 5 h
1 é
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That shape is a lexer’s, and it was underserved before those existed: a reader with only “the next
one” indexes bytes by hand and decodes a second time to find out where it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;char_indices&lt;/code&gt; is the paired walk&lt;/strong&gt;, yielding each character with the offset of its &lt;strong&gt;first&lt;/strong&gt; byte
— Rust’s name, for Rust’s reason. That the offset is the first byte is what makes it directly usable:
a slice built from two reported offsets lands on boundaries by construction, and since &lt;code&gt;s[a..b]&lt;/code&gt;
traps on a mid-character bound, that is a guarantee rather than a convention.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.char_indices

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; pair &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;char_indices&lt;/span&gt;(s.bytes)
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (i, c) = pair
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i, c)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 h
1 é
3 l
4 l
5 o
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The offsets go &lt;code&gt;0 1 3&lt;/code&gt; rather than &lt;code&gt;0 1 2&lt;/code&gt;, which is the two-byte &lt;code&gt;é&lt;/code&gt; visible from the other side. It
wraps a &lt;code&gt;Chars&lt;/code&gt; rather than decoding for itself, so there is one decoder and the two cursors cannot
come to disagree about a width.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_char_boundary&lt;/code&gt; is the same question about a single byte&lt;/strong&gt; — one mask and one comparison, since
the continuation byte is the only one matching &lt;code&gt;10xxxxxx&lt;/code&gt;. It is what a program walking backwards, or
snapping an arbitrary offset onto a boundary, would otherwise write inline:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.is_char_boundary

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = s.bytes

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_char_boundary&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;is_char_boundary&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;is_char_boundary&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;comparison-is-by-bytes&quot;&gt;Comparison is by bytes&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt; and the rest compare the byte sequences. For well-formed UTF-8 that is also codepoint order,
so the ordering is the useful one. A literal is also a pattern, matched by the same comparison:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &amp;lt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; verdict = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(verdict)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true true
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Normalization is not applied.&lt;/strong&gt; Swift’s &lt;code&gt;==&lt;/code&gt; compares by canonical equivalence, so a composed &lt;code&gt;&amp;quot;é&amp;quot;&lt;/code&gt;
equals a decomposed one — correct for user-facing text, surprising and expensive in systems code,
where a string is usually a path, a device name, or a protocol token that must compare as the bytes
it is. Normalization and collation are library operations, applied where they are wanted and visible
when they cost something.&lt;/p&gt;
&lt;h2 id=&quot;concatenation&quot;&gt;Concatenation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a + b&lt;/code&gt; joins two strings and &lt;code&gt;s += t&lt;/code&gt; appends onto a slot. Both allocate: the result is a fresh
buffer — an ordinary counted heap object — so it owns a count of its own and frees itself like any
other reference. UTF-8 is closed under concatenation, so the validity invariant is preserved for free
and nothing is re-checked. The operands are copied out rather than aliased, so an operand that was
itself a substring keeps no hold on the result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hé&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = a + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

t += &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t, t.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;héllo! 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;+&lt;/code&gt; is strict&lt;/strong&gt;: it joins a &lt;code&gt;string&lt;/code&gt; to a &lt;code&gt;string&lt;/code&gt; and nothing else.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got string and int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the same no-implicit-coercion stance the numeric operators take, where a mixed-width sum is
an error asking for a conversion. The way to build a string out of values of other types is
interpolation, where the conversion is written where it happens; making &lt;code&gt;+&lt;/code&gt; polymorphic over
“anything with a string form” would reintroduce exactly the invisible conversion the rest of the
language refuses.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; is the only arithmetic operator a string defines. The rest are rejected as they are for any type
that does not define them.&lt;/p&gt;
&lt;h2 id=&quot;rendering-a-value&quot;&gt;Rendering a value&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;str(x)&lt;/code&gt; is the written conversion from a value to its string form — the counterpart to the strict
&lt;code&gt;+&lt;/code&gt;, and what interpolation is built on.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;already&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 true é 2.5 already
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;result&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;integer&lt;/td&gt;&lt;td&gt;its decimal digits, with a sign for a negative signed value&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;quot;true&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;false&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the one scalar value’s UTF-8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;float&lt;/td&gt;&lt;td&gt;the same &lt;code&gt;%g&lt;/code&gt; rendering &lt;code&gt;print&lt;/code&gt; gives it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;itself, unchanged&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every case but a &lt;code&gt;string&lt;/code&gt; allocates a fresh buffer; a &lt;code&gt;string&lt;/code&gt; is returned as it is, and a &lt;code&gt;bool&lt;/code&gt;
renders to one of two immortal literals and allocates nothing. An integer is rendered without the C
library — the digits are divided out into a scratch buffer, which is correct even for the most
negative value because the magnitude is taken in unsigned arithmetic. A float goes through
&lt;code&gt;snprintf&lt;/code&gt;, the one case that needs libc, chosen so that &lt;code&gt;str(x)&lt;/code&gt; and &lt;code&gt;print(x)&lt;/code&gt; can never disagree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any other type renders through &lt;code&gt;Display&lt;/code&gt;.&lt;/strong&gt; A struct or an enum carrying an &lt;code&gt;impl&lt;/code&gt; writes itself
into a growable buffer, and the bytes that land there become the string — so &lt;code&gt;str&lt;/code&gt; of a user type is
an ordinary call, and &lt;code&gt;str&lt;/code&gt; of one &lt;em&gt;without&lt;/em&gt; an implementation names the &lt;code&gt;impl&lt;/code&gt; to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(p))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;write an &apos;impl sysl.Display for Point&apos; to say how it renders
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A reference, a pointer, a slice and an array remain errors, since none of them can carry an &lt;code&gt;impl&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;interpolation&quot;&gt;Interpolation&lt;/h2&gt;
&lt;p&gt;An interpolated string is a literal with a prefix, and inside it &lt;code&gt;$name&lt;/code&gt; or &lt;code&gt;${ expression }&lt;/code&gt;
splices a value in. &lt;code&gt;$$&lt;/code&gt; is one literal dollar.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n is $n, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; doubled, $$5&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;n is 7, 14 doubled, $5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each spliced value is rendered by &lt;code&gt;str&lt;/code&gt;, so the same rules apply: a primitive renders, and a type
with no string form is an error at the splice. The whole thing desugars to the machinery already
built — &lt;code&gt;s&amp;quot;a${e}b&amp;quot;&lt;/code&gt; is exactly &lt;code&gt;&amp;quot;a&amp;quot; + str(e) + &amp;quot;b&amp;quot;&lt;/code&gt; — so an interpolation is not a new kind of value,
just a concise way to write a concatenation. A hole holds a full expression, which may itself
interpolate, and an empty literal segment beside a hole is dropped, since it is the identity under
&lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This follows Scala’s interpolators, and deliberately not a &lt;code&gt;printf&lt;/code&gt;-style format string in the
default form: the value and the text around it stay where they are read, and the conversion is &lt;code&gt;str&lt;/code&gt;
applied at the splice rather than a directive parsed out of a separate string.&lt;/p&gt;
&lt;h3 id=&quot;format-specifiers&quot;&gt;Format specifiers&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt; adds one thing: a hole may be followed by a printf specifier controlling width, precision,
sign and justification.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%03d&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%08.2f&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%-5s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;007|00002.50|hi   |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A hole with no specifier renders through &lt;code&gt;str&lt;/code&gt; exactly as in an &lt;code&gt;s&amp;quot;…&amp;quot;&lt;/code&gt; string. A specifier binds only
to the &lt;code&gt;%&lt;/code&gt; written immediately after a hole, so a bare &lt;code&gt;%&lt;/code&gt; elsewhere in the text — &lt;code&gt;f&amp;quot;${n}%d done, 100% sure&amp;quot;&lt;/code&gt; — is ordinary text. Keeping the specifier beside its value is the point of putting it
after the hole rather than in a separate format string.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The conversion is checked against the value’s type while compiling:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;format &apos;%s&apos; expects a string, but the value has type int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;%d %i %x %X %o %u&lt;/code&gt; want an integer, &lt;code&gt;%f %e %g %E %G&lt;/code&gt; a float, and &lt;code&gt;%s&lt;/code&gt; a string. An unsigned
conversion reads the value at its own width — &lt;code&gt;%x&lt;/code&gt; of an &lt;code&gt;i32 -1&lt;/code&gt; is &lt;code&gt;ffffffff&lt;/code&gt;, of a &lt;code&gt;u8 255&lt;/code&gt; is
&lt;code&gt;ff&lt;/code&gt; — while &lt;code&gt;%d&lt;/code&gt; keeps the value’s sign. A string is copied NUL-terminated so that C’s &lt;code&gt;%s&lt;/code&gt; can
apply width and precision, which means an interior NUL ends the field there, as it does for any &lt;code&gt;%s&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;s&lt;/code&gt;, &lt;code&gt;raw&lt;/code&gt; and &lt;code&gt;f&lt;/code&gt; are only prefixes when written directly against the opening quote. Used as
ordinary names they are unaffected, so &lt;code&gt;s + raw&lt;/code&gt; and &lt;code&gt;f + 1&lt;/code&gt; are ordinary expressions.&lt;/p&gt;
&lt;h2 id=&quot;literals&quot;&gt;Literals&lt;/h2&gt;
&lt;p&gt;Double-quoted and UTF-8, with the usual escape table. A one-quote literal may not span a line break,
and a comment marker inside one is ordinary text. &lt;code&gt;raw&amp;quot;…&amp;quot;&lt;/code&gt; does no escape decoding:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.len, &lt;span class=&quot;hl-keyword&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 3 a\nb
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;text-blocks&quot;&gt;Text blocks&lt;/h3&gt;
&lt;p&gt;A literal that spans lines is written &lt;code&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; … &lt;code&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt;. The content begins on the line &lt;strong&gt;after&lt;/strong&gt; the
opening delimiter, which is what gives the indentation rule an anchor: the opening delimiter’s own
column then means nothing, so the form reads the same at any depth of nesting.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; block = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;        one&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;          two&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;        three&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    block

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;().len)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;16
one
  two
three
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things happen to a line inside a block that do not happen inside &lt;code&gt;&amp;quot;…&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Its incidental indentation is dropped.&lt;/strong&gt; The strip is the least indented line that carries content,
together with the line the closing delimiter sits on when it sits alone on one — so the closing
delimiter is the control, and there is no margin character to remember. Move it left and the value
keeps more; right and it keeps less. This matters more here than in a free-form language: a block
written inside an indented body would otherwise carry that body’s indentation in its value, and the
depth a piece of code sits at is not something its data should record.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Its trailing blanks are dropped&lt;/strong&gt;, because whitespace at the end of a line is invisible in a source
file and would otherwise enter the value unseen. One that is &lt;em&gt;meant&lt;/em&gt; is written &lt;code&gt;\u{20}&lt;/code&gt;, which
survives because escapes are read after the trimming rather than before it. A carriage return goes
with the rest of a line’s trailing whitespace, so a block means the same thing in a file with either
line ending.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;\&lt;/code&gt; at the end of a line joins it to the next&lt;/strong&gt;, which is the form’s reason for existing:
embedded data wants no line breaks in its value at all.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;digest&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    dead\&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    beef\&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    cafe&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;digest&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;deadbeefcafe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The joining happens in the lexer, so a block is a &lt;strong&gt;single constant&lt;/strong&gt; — where the same data assembled
with &lt;code&gt;+&lt;/code&gt; allocates and copies once per piece.&lt;/p&gt;
&lt;p&gt;Whether the value ends with a newline needs no rule of its own: a closing delimiter alone on its line
is reached &lt;em&gt;after&lt;/em&gt; the last content line’s break has been taken, and one that follows content is
reached before any break at all. A lone &lt;code&gt;&amp;quot;&lt;/code&gt; inside a block is ordinary text, which is the other thing
the form buys; a block cannot end with one, and &lt;code&gt;\&amp;quot;&lt;/code&gt; writes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The prefixes are orthogonal to the quote form.&lt;/strong&gt; &lt;code&gt;c&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;s&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt;, &lt;code&gt;f&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; and &lt;code&gt;raw&amp;quot;&amp;quot;&amp;quot;&lt;/code&gt; all compose,
since a prefix says how a literal is &lt;em&gt;read&lt;/em&gt; and the quote form says how it was &lt;em&gt;written&lt;/em&gt;. A &lt;code&gt;raw&lt;/code&gt;
block does no escape decoding, so nothing joins its lines.&lt;/p&gt;
&lt;h2 id=&quot;making-new-bytes&quot;&gt;Making new bytes&lt;/h2&gt;
&lt;p&gt;Four operations produce a string that is not a substring of one already there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;s.copy()&lt;/code&gt;&lt;/strong&gt; stops a substring holding its parent alive. Slicing is O(1) and shares the buffer,
which carries Go’s hazard with it: a small substring keeps the &lt;em&gt;whole&lt;/em&gt; parent buffer alive. Swift
addresses that with a distinct &lt;code&gt;Substring&lt;/code&gt; type you must explicitly copy out of; sysl does not add a
type for it — the operation that copies out is named, and the hazard is documented rather than
encoded.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; big = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the quick brown fox&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; piece = big[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; alone = piece.&lt;span class=&quot;hl-function&quot;&gt;copy&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(piece, alone, piece == alone)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;quick quick true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;string(c)&lt;/code&gt;&lt;/strong&gt; encodes one scalar value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;).len, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;a&apos;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;str_builder()&lt;/code&gt;&lt;/strong&gt; gathers text without rebuilding what it already has. Concatenation allocates a
fresh buffer each time, so building a string a piece at a time with &lt;code&gt;+=&lt;/code&gt; copies everything it has so
far on every step:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sb = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()

sb.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
sb.&lt;span class=&quot;hl-function&quot;&gt;push_int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)
sb.&lt;span class=&quot;hl-function&quot;&gt;push_char&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;!&apos;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sb.&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;n=42!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every way in carries the guarantee.&lt;/strong&gt; A &lt;code&gt;push&lt;/code&gt; takes a &lt;code&gt;string&lt;/code&gt;, a &lt;code&gt;push_char&lt;/code&gt; takes a &lt;code&gt;char&lt;/code&gt;, and
the four renderers take a number or a &lt;code&gt;bool&lt;/code&gt; — UTF-8 is closed under appending any of them, so
&lt;code&gt;finish&lt;/code&gt; hands back a plain &lt;code&gt;string&lt;/code&gt; rather than something a caller has to validate. That is why a
builder is &lt;strong&gt;not&lt;/strong&gt; a &lt;code&gt;Writer&lt;/code&gt;: a public &lt;code&gt;write&lt;/code&gt; taking a &lt;code&gt;[]u8&lt;/code&gt; would be &lt;code&gt;from_utf8_unchecked&lt;/code&gt; with a
longer name and none of its greppability.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;push_int&lt;/code&gt;, &lt;code&gt;push_uint&lt;/code&gt;, &lt;code&gt;push_real&lt;/code&gt; and &lt;code&gt;push_bool&lt;/code&gt; exist so that gathering a number costs no
allocation — &lt;code&gt;push(str(n))&lt;/code&gt; builds a whole counted string, copies its bytes out, and drops it, for a
value whose text is a couple of dozen bytes and is wanted only inside this buffer. They agree with
&lt;code&gt;str&lt;/code&gt; to the byte, which is the property that makes the cheap path a substitute rather than a second
rendering: a program that builds half a line with a builder and half with an interpolation must not
be able to tell which half a number came through.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;finish&lt;/code&gt; &lt;strong&gt;copies rather than lending&lt;/strong&gt;, so a builder may go on being appended to and the string
already taken out of it does not change. The alternative — handing over the storage and leaving the
builder empty — would save a copy at the cost of a form whose meaning depends on how many times it
has been called.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;cstring(s)&lt;/code&gt;&lt;/strong&gt; is the fourth, and it is the next section.&lt;/p&gt;
&lt;h2 id=&quot;c-interop&quot;&gt;C interop&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; has no terminator, so passing one to C is an explicit, allocating conversion. &lt;code&gt;CString&lt;/code&gt;
owns the copy: Go’s version hands back a raw pointer and requires a matching &lt;code&gt;free&lt;/code&gt;, and sysl has no
manual free to match, so the result is a value whose bytes go when it does. It offers two things —
&lt;code&gt;cs.ptr&lt;/code&gt;, the &lt;code&gt;*u8&lt;/code&gt; a C function takes, and &lt;code&gt;cs.len&lt;/code&gt;, the byte length &lt;em&gt;not&lt;/em&gt; counting the terminator,
so that it agrees with the &lt;code&gt;s.len&lt;/code&gt; it came from.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cs = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\u{0}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cs.len, &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(cs.ptr))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That disagreement is the whole reason the conversion is written rather than inferred.&lt;/strong&gt; For
&lt;code&gt;cstring(&amp;quot;a\u{0}b&amp;quot;)&lt;/code&gt;, &lt;code&gt;cs.len&lt;/code&gt; is 3 and C’s &lt;code&gt;strlen&lt;/code&gt; is 1. Both are right, and neither can be made to
be the other. The pointer carries a raw pointer’s rule: valid while the &lt;code&gt;CString&lt;/code&gt; is held, and
keeping it past that is the ordinary raw-pointer mistake rather than a new one. Passing
&lt;code&gt;cstring(s).ptr&lt;/code&gt; straight into a call is safe, since the temporary lives for the statement; storing
that pointer and using it later is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The literal case needs no allocation at all, and is spelled &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt;.&lt;/strong&gt; The compiler emits a NUL byte
after every string literal in read-only data — one byte, not counted in &lt;code&gt;len&lt;/code&gt; — so a literal is
already sitting in memory in exactly the shape C reads. &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt; is that constant’s address: a plain
&lt;code&gt;*u8&lt;/code&gt;, no allocation, no copy, no runtime.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a distinct literal form rather than an inferred optimization, and deliberately: whether an
expression is &lt;em&gt;literally a literal&lt;/em&gt; is not something a reader should have to work out, and a rule
that silently allocates for &lt;code&gt;s&lt;/code&gt; but not for &lt;code&gt;&amp;quot;…&amp;quot;&lt;/code&gt; hides a cost the language promises to show. It is
Rust’s &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt; and Zig’s null-terminated literal, for the reason both added it.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt; containing an interior NUL is a compile error rather than a truncation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\u{0}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a C string ends at its first NUL, so it cannot contain one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An ordinary &lt;code&gt;&amp;quot;a\u{0}b&amp;quot;&lt;/code&gt; is unaffected — it has three bytes and prints as three, because carrying a
length is the whole point — and only the free ride to C is lost, which is exactly where the
diagnostic belongs.&lt;/p&gt;
&lt;h2 id=&quot;the-allocator-free-subset&quot;&gt;The allocator-free subset&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The type is not gated; the operations that make new bytes are.&lt;/strong&gt; Legal under &lt;code&gt;no alloc&lt;/code&gt;: holding,
passing, comparing, indexing, slicing, iterating and releasing any string — including a heap-backed
one handed in from outside, which frees itself through its own deallocation hook.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/dev/console&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tail = name[&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;..]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; name.chars &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(tail, name.len, name[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], count, tail == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, name &amp;lt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/dev/null&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;console 12 47 12 true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A module-level &lt;code&gt;val&lt;/code&gt; may hold one, which is where a table of messages lives&lt;/strong&gt; — and here the point
is not that it may but that it costs nothing: a literal allocates nothing, so the table is complete
before the program starts and a module with &lt;code&gt;@no_alloc&lt;/code&gt; may carry it
(&lt;a href=&quot;/reference/declarations/&quot;&gt;declarations&lt;/a&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; messages: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;out of range&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;not permitted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no such device&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(messages[i], messages[i].len, messages[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;][&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;no such device 14 out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;const&lt;/code&gt; could not have served that: a constant is folded into its uses and has no address, so
there is nothing to index at &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Requiring an allocator: &lt;code&gt;from_utf8&lt;/code&gt;, &lt;code&gt;copy()&lt;/code&gt;, concatenation, &lt;code&gt;string(c)&lt;/code&gt;, &lt;code&gt;str_builder()&lt;/code&gt; and
&lt;code&gt;cstring&lt;/code&gt; — every operation that produces new bytes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; greeting = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; full = greeting + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; world&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(full)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the string two strings join into needs an allocator, and this module declared &apos;@no_alloc&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diagnostic finishes with the rule that makes the subset usable: such a module &lt;strong&gt;may hold and
release storage made elsewhere, and may make none of its own.&lt;/strong&gt; So a module that only ever uses
literals sees only immortal strings and its retain and release compile away entirely; one that is
handed a heap-backed string pays ordinary refcount traffic and still links no allocator.&lt;/p&gt;
&lt;h2 id=&quot;what-lives-in-the-library&quot;&gt;What lives in the library&lt;/h2&gt;
&lt;p&gt;Everything the compiler writes for itself is reachable without an import, and everything a program
writes by name is &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;. A literal, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;str(x)&lt;/code&gt;, an interpolation and
&lt;code&gt;s.chars&lt;/code&gt; are all desugarings, so they cost no import — even &lt;code&gt;s.chars&lt;/code&gt;, whose cursor is the library’s,
because the compiler names it by key rather than by resolving the word.&lt;/p&gt;
&lt;p&gt;Named at the call site, and so imported: &lt;code&gt;from_utf8&lt;/code&gt;, &lt;code&gt;char_from_u32&lt;/code&gt;, &lt;code&gt;str_builder&lt;/code&gt;, &lt;code&gt;cstring&lt;/code&gt;,
&lt;code&gt;char_indices&lt;/code&gt;, &lt;code&gt;is_char_boundary&lt;/code&gt;, the &lt;code&gt;parse_*&lt;/code&gt; family, the text operations &lt;code&gt;split&lt;/code&gt;, &lt;code&gt;fields&lt;/code&gt;,
&lt;code&gt;join&lt;/code&gt;, &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;replace_all&lt;/code&gt;, &lt;code&gt;to_upper&lt;/code&gt; and &lt;code&gt;to_lower&lt;/code&gt;, the &lt;code&gt;Search&lt;/code&gt; and &lt;code&gt;Ascii&lt;/code&gt; traits, and the
types &lt;code&gt;Utf8Error&lt;/code&gt;, &lt;code&gt;ParseError&lt;/code&gt;, &lt;code&gt;Chars&lt;/code&gt;, &lt;code&gt;CharIndices&lt;/code&gt;, &lt;code&gt;StrBuilder&lt;/code&gt; and &lt;code&gt;CString&lt;/code&gt;. The split is the
one the &lt;a href=&quot;/reference/modules/&quot;&gt;modules page&lt;/a&gt; describes: what a program cannot avoid needing arrives
free, and what it has to ask for it asks for.&lt;/p&gt;
&lt;h2 id=&quot;relationship-to-slices&quot;&gt;Relationship to slices&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is exactly an &lt;strong&gt;immutable, validated &lt;code&gt;[]u8&lt;/code&gt;&lt;/strong&gt; — the same three words, the same
retain-on-slice, one implementation underneath. Everything on this page about sharing and immortality
is the general slice rule rather than a string special case, and ownership crosses a &lt;code&gt;no alloc&lt;/code&gt;
boundary for the general reason: every counted object carries a pointer to the function that frees
it.&lt;/p&gt;
&lt;p&gt;The one string-specific addition is the validity invariant. A &lt;code&gt;[]u8&lt;/code&gt; may hold any bytes and a
&lt;code&gt;string&lt;/code&gt; is the subset that is well-formed UTF-8, which is why converting between them is checked in
one direction and free in the other.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;Go&lt;/th&gt;&lt;th&gt;Swift&lt;/th&gt;&lt;th&gt;Rust&lt;/th&gt;&lt;th&gt;sysl&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;size&lt;/td&gt;&lt;td&gt;16 B&lt;/td&gt;&lt;td&gt;16 B packed&lt;/td&gt;&lt;td&gt;24 B / 16 B&lt;/td&gt;&lt;td&gt;24 B&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;representations&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2 types&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;owns its bytes&lt;/td&gt;&lt;td&gt;the collector does&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;&lt;code&gt;String&lt;/code&gt; yes, &lt;code&gt;&amp;amp;str&lt;/code&gt; no&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;O(1) substring&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes, &lt;code&gt;Substring&lt;/code&gt;&lt;/td&gt;&lt;td&gt;yes, &lt;code&gt;&amp;amp;str&lt;/code&gt;&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;valid UTF-8 guaranteed&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;element&lt;/td&gt;&lt;td&gt;byte / &lt;code&gt;rune&lt;/code&gt;&lt;/td&gt;&lt;td&gt;grapheme cluster&lt;/td&gt;&lt;td&gt;byte / &lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;byte / &lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;comparison&lt;/td&gt;&lt;td&gt;bytes&lt;/td&gt;&lt;td&gt;canonical equivalence&lt;/td&gt;&lt;td&gt;bytes&lt;/td&gt;&lt;td&gt;bytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;NUL-terminated&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;privately&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;usable without an allocator&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;str&lt;/code&gt; yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/traits/&quot;&gt;traits&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Statements and control flow</title>
    <link href="https://sysl.sh/reference/statements/"/>
    <id>https://sysl.sh/reference/statements/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Blocks, bindings, every loop and branch form, and what each one yields — because in sysl most of them yield something.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;if&lt;/code&gt;, &lt;code&gt;match&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;loop&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt; are &lt;strong&gt;expressions&lt;/strong&gt;. Each yields a value, so each can
initialize a binding, be a function’s body, or feed a branch of another. In statement position the
value is simply unused and the same forms read as ordinary control flow.&lt;/p&gt;
&lt;p&gt;That removes the statement/expression split that forces C’s temporary-and-reassign dance
(&lt;code&gt;int label; if (…) label = …; else label = …;&lt;/code&gt;), and it makes one rule — &lt;em&gt;the last expression is
the value&lt;/em&gt; — uniform across functions, branches, arms and loops.&lt;/p&gt;
&lt;h2 id=&quot;blocks&quot;&gt;Blocks&lt;/h2&gt;
&lt;p&gt;A block is an indented run of statements, and its value is its &lt;strong&gt;trailing expression&lt;/strong&gt;. There are no
braces and no statement terminator: a newline ends a statement, and indentation opens and closes a
block. See &lt;a href=&quot;/reference/lexical/&quot;&gt;lexical structure&lt;/a&gt; for the layout rules and how a long expression is
continued across lines.&lt;/p&gt;
&lt;p&gt;Where a block’s own value is unused, the block has &lt;strong&gt;none&lt;/strong&gt; — its type is &lt;code&gt;unit&lt;/code&gt; whatever the last
line yields — and that propagates inward, into the branches of an &lt;code&gt;if&lt;/code&gt;, the arms of a &lt;code&gt;match&lt;/code&gt;, and
the &lt;code&gt;else&lt;/code&gt; of a loop. This is what lets branches merely do things without being made to agree on a
value nobody asked for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; full = &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; len = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wrapped = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; wrapped
    full = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
    len += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(full, len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without that rule, &lt;code&gt;full = true&lt;/code&gt; (a &lt;code&gt;bool&lt;/code&gt;) and &lt;code&gt;len += 1&lt;/code&gt; (an &lt;code&gt;int&lt;/code&gt;) would be two branches with
nothing to meet at. Statement position starts at a statement, at a loop body, and at the body of a
function that returns nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A block stands wherever a construct puts one, and a binding’s &lt;code&gt;=&lt;/code&gt; is one of those places&lt;/strong&gt; — see
&lt;a href=&quot;/reference/declarations/#the-value-may-be-an-indented-block&quot;&gt;the value may be an indented block&lt;/a&gt;.
The rules there are the ones above, unchanged: the trailing expression is the value, and what the
block binds goes out of scope with it.&lt;/p&gt;
&lt;h3 id=&quot;the-statement-forms&quot;&gt;The statement forms&lt;/h3&gt;
&lt;p&gt;Everything that can stand as a statement:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;an expression&lt;/td&gt;&lt;td&gt;including every control-flow form, since they are expressions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;var&lt;/code&gt; / &lt;code&gt;val&lt;/code&gt; / &lt;code&gt;const&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a binding — see &lt;a href=&quot;/reference/declarations/&quot;&gt;declarations&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ref name = place&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a second name for one place — see &lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;a, b = x, y&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a multiple assignment, which is &lt;strong&gt;not&lt;/strong&gt; an expression&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;return&lt;/code&gt;, &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;&lt;/td&gt;&lt;td&gt;transfers of control&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;defer stmt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;what to run on the way out of this block&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;require&lt;/code&gt; / &lt;code&gt;ensure&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a contract clause — see &lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;import&lt;/code&gt;, &lt;code&gt;impl&lt;/code&gt;, and the declarations&lt;/td&gt;&lt;td&gt;a declaration is a statement, so a function may be nested in one&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;if&quot;&gt;&lt;code&gt;if&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;if cond&lt;/code&gt; with an indented block, &lt;code&gt;elif&lt;/code&gt; for each further test, and an optional &lt;code&gt;else&lt;/code&gt;. The inline
form puts &lt;code&gt;then&lt;/code&gt; between the condition and a one-line body.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;even&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; n &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;80&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;label&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;95&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;85&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;70&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;even odd A B C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;elif&lt;/code&gt; is sugar: each one nests into the &lt;code&gt;else&lt;/code&gt; branch of the one before, so no separate node exists
and no rule about it has to be learned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;if&lt;/code&gt; used for a value needs an &lt;code&gt;else&lt;/code&gt;.&lt;/strong&gt; A missing one leaves the open branch at &lt;code&gt;unit&lt;/code&gt;, which
is a diagnostic wherever a value was wanted. In statement position a missing &lt;code&gt;else&lt;/code&gt; is ordinary.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;if&lt;/code&gt; may be closed with &lt;code&gt;end if&lt;/code&gt;, which is optional everywhere and reads well when the block is
long enough that its extent has stopped being obvious:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;positive&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; if&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;positive
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;end&lt;/code&gt; is a &lt;strong&gt;soft&lt;/strong&gt; word — an ordinary identifier everywhere except immediately before a construct
keyword — so &lt;code&gt;end&lt;/code&gt; remains usable as a name. The same marker closes &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;loop&lt;/code&gt;, a struct
and an enum.&lt;/p&gt;
&lt;h2 id=&quot;match&quot;&gt;&lt;code&gt;match&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;value match&lt;/code&gt;, then an indented list of &lt;code&gt;pattern -&amp;gt; body&lt;/code&gt; arms. The keyword goes &lt;strong&gt;after&lt;/strong&gt; the value,
as in Scala and for Scala’s reason: a match is a transformation of the thing to its left, so writing
it there is what lets one feed another.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Tier&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Bronze&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Silver&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Gold&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;fee&lt;/span&gt;(t: &lt;span class=&quot;hl-type&quot;&gt;Tier&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    t &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Bronze&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Silver&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Gold&lt;/span&gt;   -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;25&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fee&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Bronze&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;fee&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Silver&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;fee&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Gold&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 10 25
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A match used &lt;strong&gt;for a value must be exhaustive&lt;/strong&gt;; one written for effect need not be, which follows
the same rule the block-value discard does. Everything about the left side of an arm — the pattern
grammar, guards, alternatives, bindings — is on &lt;a href=&quot;/reference/patterns/&quot;&gt;patterns and matching&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;loops&quot;&gt;Loops&lt;/h2&gt;
&lt;p&gt;Five forms, and each is an expression.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;when&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;while cond&lt;/code&gt;&lt;/td&gt;&lt;td&gt;test before each iteration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;do … while cond&lt;/code&gt;&lt;/td&gt;&lt;td&gt;test after each iteration, so the body runs at least once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no test at all; something inside leaves it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;for x in seq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;walk a range, an array, a slice, or an &lt;code&gt;Iterate&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;for init; cond; step&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a stride, a descent, a compound test, several variables&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;for-x-in&quot;&gt;&lt;code&gt;for x in&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The ordinary walk, and preferred wherever it fits: it names one thing instead of three and cannot
get any of them wrong.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
5
6
0
1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;break-carries-a-value-and-else-supplies-the-other-one&quot;&gt;&lt;code&gt;break&lt;/code&gt; carries a value, and &lt;code&gt;else&lt;/code&gt; supplies the other one&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;break expr&lt;/code&gt; leaves the nearest loop and makes &lt;code&gt;expr&lt;/code&gt; the loop’s value. An optional &lt;strong&gt;&lt;code&gt;else&lt;/code&gt; block&lt;/strong&gt;,
written after the body as in Python, runs when the loop finishes &lt;em&gt;normally&lt;/em&gt; — the condition turned
false or the sequence ran out, with no &lt;code&gt;break&lt;/code&gt; — and its trailing expression is the loop’s value on
that path.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mixed = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; odds = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; found = &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; mixed
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; x
&lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; none = &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; odds
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; x
&lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(found, none)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That turns the most common reason to leave a loop early — &lt;em&gt;find the first element satisfying a
predicate&lt;/em&gt; — into one expression whose type states, through the mandatory &lt;code&gt;else&lt;/code&gt;, what happens when
nothing is found. It is the same discipline that gives references no null and errors a &lt;code&gt;Result&lt;/code&gt;: the
loop cannot fall through to an undefined value.&lt;/p&gt;
&lt;p&gt;With no &lt;code&gt;else&lt;/code&gt;, normal completion yields &lt;code&gt;unit&lt;/code&gt; — so a value-carrying &lt;code&gt;break&lt;/code&gt; without one is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; found = &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x == &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(found)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this loop breaks with a int but has no &apos;else&apos; to give a value when it finishes normally
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every &lt;code&gt;break&lt;/code&gt; value and the &lt;code&gt;else&lt;/code&gt; value share one type, which becomes the loop’s. A bare &lt;code&gt;break&lt;/code&gt;
with no &lt;code&gt;else&lt;/code&gt; is the ordinary statement loop, of type &lt;code&gt;unit&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;do-while&quot;&gt;&lt;code&gt;do … while&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The test goes at the foot, so the body runs before anything is asked. The body is an indented block
with the &lt;code&gt;while&lt;/code&gt; on the line that closes it, or a single statement on one line.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; rest = n
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt;
        s = &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(rest % &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;) + s
        rest /= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; rest &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    s

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4071&lt;/span&gt;), i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 4071 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written as a &lt;code&gt;while&lt;/code&gt;, &lt;code&gt;digits&lt;/code&gt; prints nothing for &lt;code&gt;0&lt;/code&gt;. The value rules are &lt;code&gt;while&lt;/code&gt;‘s: a &lt;code&gt;break&lt;/code&gt;
carries the loop’s value, and an &lt;code&gt;else&lt;/code&gt; runs when the test at the foot finally fails.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;continue&lt;/code&gt; runs the test&lt;/strong&gt;, and that is what the form is for. The shape written instead is &lt;code&gt;loop&lt;/code&gt;
with the test inverted at the bottom:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;loop
    body
    if !cond then break        // NOT the same loop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That has no test for a &lt;code&gt;continue&lt;/code&gt; to reach, so the first &lt;code&gt;continue&lt;/code&gt; added to it jumps over the exit
and the loop never leaves — the same trap the three-clause &lt;code&gt;for&lt;/code&gt; exists to avoid, where a &lt;code&gt;continue&lt;/code&gt;
skips the step.&lt;/p&gt;
&lt;p&gt;The test takes no &lt;code&gt;is&lt;/code&gt; binding, and cannot read what the body declared: it guards nothing, because
the body it belongs to has already run.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; k = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; k &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;undefined name &apos;k&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;do&lt;/code&gt; is never ambiguous with the &lt;code&gt;do&lt;/code&gt; that introduces a one-line body. That one only ever follows a
loop header on the same line, so it is never a statement’s first token; a &lt;code&gt;do&lt;/code&gt; that starts a line
opens this form and nothing else.&lt;/p&gt;
&lt;h3 id=&quot;loop&quot;&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A loop with nothing to test. It runs until something leaves it, which is what &lt;code&gt;while true&lt;/code&gt; was always
being used to say.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; stop = &lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
    n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; n * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(stop, n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;40 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things follow from the condition being &lt;em&gt;gone&lt;/em&gt; rather than merely constant. It takes &lt;strong&gt;no
&lt;code&gt;else&lt;/code&gt;&lt;/strong&gt; — an &lt;code&gt;else&lt;/code&gt; runs on normal completion, and this loop has none — so a value-carrying &lt;code&gt;break&lt;/code&gt;
needs nothing beside it, which is why the program above compiles where the &lt;code&gt;for&lt;/code&gt; above it did not.&lt;/p&gt;
&lt;p&gt;And a &lt;code&gt;loop&lt;/code&gt; &lt;strong&gt;nothing breaks out of has type &lt;code&gt;never&lt;/code&gt;&lt;/strong&gt;, so it may stand as the last thing a function
owing a value does, with nothing after it to supply one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(handle: () -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;handle&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the fact &lt;code&gt;while true&lt;/code&gt; cannot state. A condition is an expression the analyzer does not
evaluate, so a loop written that way looks like one that might finish, and the code after it looks
reachable.&lt;/p&gt;
&lt;h3 id=&quot;the-three-clause-for&quot;&gt;The three-clause &lt;code&gt;for&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;C’s counted loop without the parentheses, as Go writes it — every other header in the language is
parenthesis-free, and parentheses here would be structure rather than grouping. Each of the three
clauses may be left out.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;; i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; i % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;continue&lt;/span&gt;

    total += i

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; down = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;; i &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; i -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    down += &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(i)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(total, down)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;25 321
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The step is why the form exists, and it is not sugar for a &lt;code&gt;while&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;continue&lt;/code&gt; runs the step
before testing again, so the skipped iterations above still advance — which is the whole reason that
loop terminates. Written as a &lt;code&gt;while&lt;/code&gt; the increment sits at the foot of the body, where the first
&lt;code&gt;continue&lt;/code&gt; anybody adds later walks straight past it: a bug the shape of the code invites and nothing
about it warns of.&lt;/p&gt;
&lt;p&gt;The second loop is the other reason: a descent is not something a range says.&lt;/p&gt;
&lt;p&gt;An absent condition never turns false, so such a loop ends only through a &lt;code&gt;break&lt;/code&gt; and takes no
&lt;code&gt;else&lt;/code&gt; — exactly as &lt;code&gt;loop&lt;/code&gt; does, and &lt;code&gt;loop&lt;/code&gt; says it better.&lt;/p&gt;
&lt;h3 id=&quot;labels&quot;&gt;Labels&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;&apos;label&lt;/code&gt; written before the loop keyword names that loop, and &lt;code&gt;break &apos;label&lt;/code&gt; / &lt;code&gt;continue &apos;label&lt;/code&gt;
then act on it rather than on the nearest enclosing one. This is the only way to leave or restart an
outer loop from inside a nested one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; grid = [[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hit = &apos;outer &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; row &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; grid
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; row
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x == &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; &apos;outer x
&lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(hit)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A labeled &lt;code&gt;break&lt;/code&gt; carries a value exactly as a bare one does, meeting that loop’s other breaks and
its &lt;code&gt;else&lt;/code&gt; at one type. &lt;code&gt;continue&lt;/code&gt; takes a label but never a value.&lt;/p&gt;
&lt;p&gt;The sigil is a leading apostrophe, as in Rust, and deliberately not the &lt;code&gt;:&lt;/code&gt;-suffix some languages
use: a bare &lt;code&gt;break outer&lt;/code&gt; would be ambiguous with &lt;code&gt;break expr&lt;/code&gt; carrying a value that happens to be
named &lt;code&gt;outer&lt;/code&gt;, and the apostrophe keeps a label and a value textually distinct. It does not collide
with a character literal — &lt;code&gt;&apos;a&apos;&lt;/code&gt; closes its quote and is a character, &lt;code&gt;&apos;a&lt;/code&gt; does not and is a label.&lt;/p&gt;
&lt;p&gt;A label is in scope only inside its own loop’s body. Naming a loop that does not enclose the
&lt;code&gt;break&lt;/code&gt;, or reusing a label already in scope, is an error rather than a silent miss.&lt;/p&gt;
&lt;h2 id=&quot;return&quot;&gt;&lt;code&gt;return&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A function’s body yields its trailing expression, so &lt;code&gt;return&lt;/code&gt; is for leaving &lt;strong&gt;early&lt;/strong&gt;. It takes the
same comma list a multi-result signature declares:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; b == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    a / b, a % b

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q, r = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; z, w = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q, r, z, w)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2 0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;defer&quot;&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;ARC gives back a &lt;code&gt;&amp;amp;T&lt;/code&gt;, a &lt;code&gt;string&lt;/code&gt; and a slice’s backing without being asked. It knows nothing about
the rest: a descriptor from &lt;code&gt;open&lt;/code&gt;, a &lt;code&gt;FILE*&lt;/code&gt; from &lt;code&gt;fopen&lt;/code&gt;, a block from &lt;code&gt;malloc&lt;/code&gt;, a lock taken from
a mutex. Until those are released by hand, a correct program is one that never takes an early exit —
which &lt;code&gt;?&lt;/code&gt; makes the &lt;em&gt;normal&lt;/em&gt; way to leave a function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;defer &amp;lt;statement&amp;gt;&lt;/code&gt; runs that statement on the way out of the block containing it.&lt;/strong&gt; The resource
is released beside the call that took it, once, rather than at every exit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;work&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;work&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;body
first
second
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-runs-and-when&quot;&gt;What runs, and when&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A deferred statement belongs to its block&lt;/strong&gt; — a loop body, a branch arm, or the function body
itself — and runs when control leaves that block by any ordinary route: falling off the end,
&lt;code&gt;return&lt;/code&gt;, &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, or a &lt;code&gt;?&lt;/code&gt; taking its failure arm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Several in one block run last-registered-first&lt;/strong&gt;, as above, so they undo in the reverse of the
order they were set up — the order that lets a later one depend on an earlier one’s resource.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;defer&lt;/code&gt; runs only if control reached it.&lt;/strong&gt; It is a statement, not a declaration: one after an
early &lt;code&gt;return&lt;/code&gt; never registered, and one in a branch never taken did not either.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The whole statement runs at the exit, so everything in it is read there&lt;/strong&gt; — not where the &lt;code&gt;defer&lt;/code&gt;
stands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)

    n = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go differs here: it evaluates a deferred call’s &lt;em&gt;arguments&lt;/em&gt; where the &lt;code&gt;defer&lt;/code&gt; stands and runs the
call later, which needs somewhere to keep each captured argument until then — a slot per deferred
statement, sized and laid out per call. Reading everything at the exit needs nothing kept. This is
Zig’s rule, and it changes nothing for the form’s purpose: &lt;code&gt;defer fclose(f)&lt;/code&gt; releases the handle
bound above it, and a program that rebinds &lt;code&gt;f&lt;/code&gt; in between has changed which file is open, so closing
the one that is actually open is the behaviour wanted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trap runs nothing.&lt;/strong&gt; A trap aborts without stack cleanup, and &lt;code&gt;defer&lt;/code&gt; does not qualify that: a
broken invariant means the program’s model of itself is already wrong, and running cleanup against
that state is how a corrupt program writes its corruption to disk on the way down. &lt;code&gt;defer&lt;/code&gt; releases a
resource; it does not restore an invariant.&lt;/p&gt;
&lt;h3 id=&quot;why-the-block-and-not-the-function&quot;&gt;Why the block and not the function&lt;/h3&gt;
&lt;p&gt;Go’s &lt;code&gt;defer&lt;/code&gt; runs at &lt;strong&gt;function&lt;/strong&gt; exit. The difference is invisible for the common case — a resource
taken at the top of a body and released when the body ends, where the function &lt;em&gt;is&lt;/em&gt; the block — and
shows up in a loop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, i)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;open 0
close 0
open 1
close 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Block scope closes each iteration’s resource at the end of that iteration, so the program holds one
at a time. Function scope would hold all of them until the function returned — and, the part that
decides it, would need somewhere to record a number of pending statements that no compiler can bound.
That is a per-frame list whose length is discovered while running, which is precisely the machinery
that a freestanding target under &lt;code&gt;no alloc&lt;/code&gt; has nowhere to put. Block scope needs no runtime state at
all: the statement is emitted at each edge that leaves the block, exactly as ARC’s own releases
already are.&lt;/p&gt;
&lt;p&gt;Go has two reasons for its choice and sysl has neither. &lt;code&gt;recover&lt;/code&gt; only works inside a deferred call
and a panic unwinds one frame at a time, so the frame has to be the unit; and mutating a named result
is how Go wraps an error on the way out. sysl has no unwinding and no named results. The languages
that came later without &lt;code&gt;recover&lt;/code&gt; — Zig, Swift — both put &lt;code&gt;defer&lt;/code&gt; at the block.&lt;/p&gt;
&lt;h3 id=&quot;where-it-sits-against-the-rest-of-the-model&quot;&gt;Where it sits against the rest of the model&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A deferred statement runs before the block’s ARC releases&lt;/strong&gt;, so every local it names is still alive
when it runs, including the one holding the resource being closed. Leaving from the middle unwinds
outward: the innermost block runs its deferred statements and then gives up its counts, then the
block outside it does the same, up to the function’s own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It owns nothing and allocates nothing.&lt;/strong&gt; &lt;code&gt;defer&lt;/code&gt; takes no count, makes no box, and adds no word to
any value; a program that does not use it emits nothing for it. That is what keeps it available under
&lt;code&gt;no alloc&lt;/code&gt;, where the resources it releases are the only ones there are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it is not is a &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt;.&lt;/strong&gt; A destructor belongs to a &lt;em&gt;type&lt;/em&gt; and runs
wherever a value of that type dies; &lt;code&gt;defer&lt;/code&gt; belongs to one place in one body and runs for the
resource that body took. Both exist and neither replaces the other: &lt;code&gt;defer&lt;/code&gt; covers every site a
program can name, and a destructor covers the deaths it cannot — a resource inside a container, or
inside a struct inside a container, dies at a point with no expression in the source.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/declarations/&quot;&gt;declarations&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The slices module</title>
    <link href="https://sysl.sh/library/slices/"/>
    <id>https://sysl.sh/library/slices/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.slices` — the operations over a built-in slice: searching, comparing, reversing, two sorts that neither of them allocates, a binary search that answers where a missing value belongs, and the pointer a C binding hands across.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.slices&lt;/code&gt; is what a program does &lt;em&gt;to&lt;/em&gt; a &lt;code&gt;[]T&lt;/code&gt; once it has one. Everything here is a &lt;strong&gt;free
function&lt;/strong&gt; rather than a member of anything, which is the same call &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt;
made for &lt;code&gt;min&lt;/code&gt;: a built-in slice is indexed by the compiler walking to an address, so none of this
goes through a trait, and what each function needs is written in its own bound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing here allocates and nothing here needs a capability.&lt;/strong&gt; That is deliberate and it is load
bearing — this is the module a C binding reaches into, and it is reachable from a target with no
allocator and no operating system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.{sort, is_sorted, binary_search}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;sort&lt;/span&gt;(xs)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_sorted&lt;/span&gt;(xs))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[1, 2, 3, 5, 8, 9]
true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;looking-things-up&quot;&gt;Looking things up&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;index_of&lt;/code&gt; and &lt;code&gt;last_index_of&lt;/code&gt; answer an &lt;code&gt;Option[usize]&lt;/code&gt; rather than a sentinel — a library answering
&lt;code&gt;-1&lt;/code&gt; hands back a number that indexes when it should not, and &lt;code&gt;usize&lt;/code&gt; has no negative to spare in any
case.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.{index_of, last_index_of, contains, min_index, max_index}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;index_of&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;last_index_of&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;contains&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;contains&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min_index&lt;/span&gt;(xs).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;max_index&lt;/span&gt;(xs).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 3
true false
0 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The extremes answer an &lt;strong&gt;index&lt;/strong&gt; rather than a value, because the index answers both questions: an
element is one subscript away, and a caller that wanted to &lt;em&gt;modify&lt;/em&gt; the extreme element could not have
got there from a copy. Ties go to the first, which is the choice &lt;code&gt;min&lt;/code&gt; makes and for the same reason.&lt;/p&gt;
&lt;h2 id=&quot;comparing-and-rearranging&quot;&gt;Comparing and rearranging&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.{equal, starts_with, ends_with, reverse, fill, swap}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;equal&lt;/span&gt;(a, [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;starts_with&lt;/span&gt;(a, [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;ends_with&lt;/span&gt;(a, [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]))

&lt;span class=&quot;hl-function&quot;&gt;reverse&lt;/span&gt;(a)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;(a, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;fill&lt;/span&gt;(a, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true true
[4, 3, 2, 1]
[1, 3, 2, 4]
[7, 7, 7, 7]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;two-sorts-and-neither-of-them-allocates&quot;&gt;Two sorts, and neither of them allocates&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sort&lt;/code&gt; is &lt;strong&gt;unstable&lt;/strong&gt;, works in the slice it was given, and uses no extra storage. It is an
introsort: insertion sort below sixteen elements, a median-of-three quicksort above that, and
heapsort once the recursion has gone deeper than a well-behaved input ever would — which is what holds
the worst case at O(n log n) rather than letting a chosen input make it quadratic.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sort_stable&lt;/code&gt; keeps equal elements in the order they arrived, and merges through &lt;strong&gt;scratch the caller
supplies&lt;/strong&gt;. That is the honest shape: a stable sort needs somewhere to merge into, and a library that
allocated on your behalf would be unusable on the targets this module exists to stay available on. It
answers &lt;code&gt;false&lt;/code&gt; if the scratch is shorter than the slice.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.sort_stable

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; scratch = [(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;); &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sort_stable&lt;/span&gt;(xs, scratch))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
[(1, 1), (1, 2), (2, 1), (2, 2)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both come in a &lt;code&gt;_by&lt;/code&gt; form taking a comparison, which is where the work actually is — the &lt;code&gt;Ord&lt;/code&gt; forms
are one line handing it &lt;code&gt;&amp;lt;&lt;/code&gt;. The comparison is a &lt;a href=&quot;/reference/functions/&quot;&gt;bare arrow&lt;/a&gt;, so it is
monomorphized and inlined rather than boxed, and the pair costs nothing over one function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.sort_by

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;sort_by&lt;/span&gt;(xs, (a, b) -&amp;gt; b &amp;lt; a)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[5, 3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Which one you want is a real question.&lt;/strong&gt; &lt;code&gt;sort&lt;/code&gt; is faster and says nothing about equal elements;
&lt;code&gt;sort_stable&lt;/code&gt; promises their order survives. That only matters for a type whose equality does not mean
identity — a record ordered on one field — and when it matters, it matters a great deal.&lt;/p&gt;
&lt;h3 id=&quot;why-these-are-written-in-sysl-rather-than-calling-qsort&quot;&gt;Why these are written in sysl rather than calling qsort&lt;/h3&gt;
&lt;p&gt;It is the first question anybody arriving from C asks, and the answer is not that the C library is
slow.&lt;/p&gt;
&lt;p&gt;The binding is perfectly writable. &lt;code&gt;guide/qsort&lt;/code&gt; in the compiler’s repository writes it in a dozen
lines, and everything it needs is in the language: the address of a per-instantiation comparison, the
address of a slice’s storage, and the size of an element.&lt;/p&gt;
&lt;p&gt;What decides it is what this module &lt;strong&gt;promises&lt;/strong&gt;. &lt;code&gt;sysl.slices&lt;/code&gt; requires no capability, which is a
promise made to every machine sysl builds for — and several of those are freestanding, where there is
no C library to call at all and &lt;code&gt;qsort&lt;/code&gt; is an undefined symbol at the end of somebody’s link. On a
hosted machine the same promise fails more quietly: glibc’s &lt;code&gt;qsort&lt;/code&gt; sorts by merging into a temporary
buffer and calls &lt;code&gt;malloc&lt;/code&gt; to obtain one, while Darwin’s sorts in place. One source text therefore
allocates on one platform and not on the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Neither fact is visible to the compiler&lt;/strong&gt;, because what is behind an &lt;code&gt;extern&lt;/code&gt; is behind it. A
module whose whole selling point is that it needs nothing cannot offer a function whose needs are
unknowable.&lt;/p&gt;
&lt;p&gt;Two smaller reasons stand behind that one. There is no portable &lt;strong&gt;stable&lt;/strong&gt; sort in a C library —
&lt;code&gt;mergesort&lt;/code&gt; and &lt;code&gt;heapsort&lt;/code&gt; are BSD extensions, present on macOS and absent from glibc, and ISO C has
only the unstable &lt;code&gt;qsort&lt;/code&gt; — so a binding could have replaced &lt;code&gt;sort&lt;/code&gt; and never &lt;code&gt;sort_stable&lt;/code&gt;. And a
bound comparison is an indirect call per step, where a monomorphized &lt;code&gt;[T: Ord]&lt;/code&gt; body inlines the
same comparison.&lt;/p&gt;
&lt;h2 id=&quot;searching-a-sorted-slice&quot;&gt;Searching a sorted slice&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;binary_search&lt;/code&gt; answers a &lt;strong&gt;pair&lt;/strong&gt;: whether the value was found, and the index it is at &lt;em&gt;or would be
inserted at&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.binary_search

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (found, at) = &lt;span class=&quot;hl-function&quot;&gt;binary_search&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (missing, &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;binary_search&lt;/span&gt;(xs, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(found, at)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(missing, &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 2
false 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The insertion point is wanted on a miss and is the expensive half of the answer, so throwing it away
would mean computing it twice. An &lt;code&gt;Option[usize]&lt;/code&gt; does exactly that; a &lt;code&gt;Result[usize, usize]&lt;/code&gt; — Rust’s
spelling — keeps it but calls a miss a &lt;em&gt;failure&lt;/em&gt;, which it is not.&lt;/p&gt;
&lt;p&gt;Where several elements compare equal, the answer is the index of the &lt;strong&gt;first&lt;/strong&gt;. That makes it a
function of the values rather than of how the search happened to land, which is what lets two searches
of one slice be compared.&lt;/p&gt;
&lt;p&gt;The slice must already be sorted by the same order you are searching with. Nothing checks it — that
would cost a linear scan on every search and defeat the point — and the answer for an unsorted slice
is unspecified rather than wrong in some particular way.&lt;/p&gt;
&lt;h2 id=&quot;handing-a-slice-to-c&quot;&gt;Handing a slice to C&lt;/h2&gt;
&lt;p&gt;Every binding to a C library needs a pointer to a slice’s first element, because C’s convention is a
pointer beside a length. &lt;code&gt;as_ptr&lt;/code&gt; and &lt;code&gt;as_mut_ptr&lt;/code&gt; are that, and they exist here because every binding
was otherwise writing them.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.slices.as_ptr

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;as_ptr&lt;/span&gt;(xs))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;as_ptr&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]) == &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An empty slice answers &lt;code&gt;null&lt;/code&gt;.&lt;/strong&gt; An empty slice is a real input — a length of zero is a loop that
does not run — but &lt;code&gt;&amp;amp;xs[0]&lt;/code&gt; on one is an out-of-bounds index and traps rather than yielding the
pointer C would have accepted.&lt;/p&gt;
&lt;p&gt;The cost, said plainly: ISO C leaves passing a null pointer to &lt;code&gt;memcpy&lt;/code&gt; undefined even at a length of
zero, and a small number of libraries assert non-null on entry. Every real interface takes the pair
&lt;code&gt;(null, 0)&lt;/code&gt;, and the length is what says not to look — but a binding whose C asserts otherwise must
pass storage it owns rather than an empty slice.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slab</title>
    <link href="https://sysl.sh/guides/slab/"/>
    <id>https://sysl.sh/guides/slab/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Raw storage — reinterpreting bytes as a typed pointer, `sizeof`/`alignof`, and a free list threaded through the free blocks themselves.</summary>
    <content type="html">&lt;p&gt;One region of bytes carved into fixed blocks, with the free list threaded through the free blocks’
own storage. &lt;strong&gt;The first literate program in the set&lt;/strong&gt; — its findings ran to sixty lines of header
comment before anything executable appeared, which is the length at which a comment stops being one,
so &lt;code&gt;slab.lsysl&lt;/code&gt; is a document with the program indented inside it.&lt;/p&gt;
&lt;p&gt;It reads perfectly well unrendered, which is the point of the format — but &lt;code&gt;sysl weave guide/slab/slab.lsysl -o slab.html&lt;/code&gt; sets it as one, and &lt;code&gt;sysl tangle&lt;/code&gt; on the same file prints the
program the compiler reads out of it. See &lt;a href=&quot;/getting-started/cli/#weave&quot;&gt;the CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: raw storage&lt;/strong&gt; — reinterpreting bytes as a typed pointer, asking what a type’s storage
costs, and the address arithmetic between the two. Nothing else in the set touches any of it.
&lt;a href=&quot;/guides/kernel/&quot;&gt;kernel&lt;/a&gt; is allocator-free but never &lt;em&gt;makes&lt;/em&gt; storage; it is handed three fixed tables
and indexes them. This is the other side of that: the thing a program with no allocator would have to
write before it could have one, which is why it is written with no allocator itself.&lt;/p&gt;
&lt;p&gt;It is &lt;strong&gt;generic in what it holds&lt;/strong&gt;, and that is the point rather than a flourish. A slab over one
hardcoded struct needs no &lt;code&gt;sizeof&lt;/code&gt; at all — a literal block size would do — so the generic form is
what makes the measurement load-bearing, and it is the shape a real allocator has.&lt;/p&gt;
&lt;p&gt;The free list is &lt;strong&gt;intrusive&lt;/strong&gt;: a free block holds the address of the next free block in its own first
bytes, so the list costs no storage beside the region. That is what a slab allocator &lt;em&gt;is&lt;/em&gt;, and it is
only writable because a &lt;code&gt;*u8&lt;/code&gt; can be read as a &lt;code&gt;**u8&lt;/code&gt; and back:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; *&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(b)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; link&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;next_free&lt;/span&gt;(b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(b)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; next_free&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A region declared the obvious way is not aligned for what gets carved out of it.&lt;/strong&gt; A &lt;code&gt;[N]u8&lt;/code&gt; is
aligned to one, because that is what a byte needs, so every load through the resulting pointer is
unaligned — which x86 tolerates and which faults on some of the targets this language is for.&lt;/p&gt;
&lt;p&gt;The allocator therefore rounds its own base up, exactly as a real one does, paying up to
&lt;code&gt;alignof(T) - 1&lt;/code&gt; bytes of the region.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;When this guide was written that was the only thing a program could do, and it is not any more.&lt;/strong&gt;
&lt;code&gt;@align(n)&lt;/code&gt; asks for a boundary and gets it — on a struct declaration, or on the &lt;code&gt;var&lt;/code&gt; that holds the
region, which is the shorter way to say it for one region in particular. See
&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt;. What has not changed is that it is the right behaviour &lt;em&gt;here&lt;/em&gt;:
a slab is handed a slice it did not declare, so it cannot know what its caller’s region is aligned
to and rounding up is exactly what the rounding is for. &lt;strong&gt;The finding was that the allocator had no
choice; the answer is that its caller now does.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sizeof&lt;/code&gt; is what makes a container generic, and &lt;code&gt;alignof&lt;/code&gt; is what makes it correct.&lt;/strong&gt; With only the
first, a slab over any &lt;code&gt;T&lt;/code&gt; still lays its blocks at whatever offset the region began at. The two
arrived together for this reason rather than by tidiness.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A block has to be wide enough to hold the list that threads it.&lt;/strong&gt; &lt;code&gt;sizeof(T) &amp;gt;= sizeof(*u8)&lt;/code&gt; is a
real precondition — a slab of &lt;code&gt;u16&lt;/code&gt; cannot store an address inside a free block — and it is a
&lt;code&gt;require&lt;/code&gt; rather than a comment because both sides are constants the compiler already knows. &lt;strong&gt;A
language without &lt;code&gt;sizeof&lt;/code&gt; could not have stated it at all.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing checks a reinterpreted pointer, and nothing should.&lt;/strong&gt; &lt;code&gt;ptr_cast&lt;/code&gt; hands back a &lt;code&gt;*T&lt;/code&gt; aimed at
bytes that hold no &lt;code&gt;T&lt;/code&gt; yet; the caller writes one before reading one, and no rule here says so. That
is the &lt;a href=&quot;/reference/memory/&quot;&gt;raw tier&lt;/a&gt; behaving as specified — the same assertion an unchecked index
already is — and it is why the whole file is greppable for the three operations that take on the risk.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An allocator may call its function &lt;code&gt;alloc&lt;/code&gt;, and this one does.&lt;/strong&gt; It could not always: the
capability clause used to be written as the two ordinary words &lt;code&gt;no alloc&lt;/code&gt;, which reserved both, so
the most natural name in the whole program was the one name it could not have and this file called it
&lt;code&gt;take&lt;/code&gt;. &lt;strong&gt;Capabilities are attributes now&lt;/strong&gt; — &lt;code&gt;@no_alloc&lt;/code&gt;, &lt;code&gt;@requires(...)&lt;/code&gt; — and an attribute’s name
is an ordinary identifier, so the words came back. The general lesson is the one the old note was
groping at: &lt;strong&gt;a capability written as grammar spends a word out of every program’s namespace&lt;/strong&gt;, and
&lt;code&gt;alloc&lt;/code&gt; is the word the code that &lt;em&gt;provides&lt;/em&gt; the capability wants most.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The one thing the compiler still refuses is a &lt;code&gt;&amp;amp;T&lt;/code&gt;.&lt;/strong&gt; An early draft tried to hand back a counted
reference, on the grounds that a slab block outlives its user. It cannot: ARC would have no count to
own, and the safe subset relies on a &lt;code&gt;&amp;amp;T&lt;/code&gt; being a live object. So an allocator’s result is a &lt;code&gt;*T&lt;/code&gt; and
stays in the raw tier, which is where a caller reaching for one already is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is allocator-free and still cannot say so&lt;/strong&gt; — but not for the reason first recorded. &lt;code&gt;no alloc&lt;/code&gt;
has shipped; what keeps it out of this directory is the clause’s own shape, since a capability is a
property of the module and the checks next door render a &lt;code&gt;str&lt;/code&gt; on nearly every line.
&lt;a href=&quot;/guides/bytecode/&quot;&gt;bytecode&lt;/a&gt; is the program that got to carry it, and the difference is only that its
machine already lived in a module of its own.&lt;/p&gt;
&lt;h2 id=&quot;deliberately-not-modelled&quot;&gt;Deliberately not modelled&lt;/h2&gt;
&lt;p&gt;More than one block size, coalescing, and returning the region. The first is a different allocator,
and the other two need a heap this program is written without.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/slab&quot;&gt;Source&lt;/a&gt; ·
Back to &lt;a href=&quot;/guides/&quot;&gt;the guide programs&lt;/a&gt;, or on to the &lt;a href=&quot;/reference/&quot;&gt;reference&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>simd</title>
    <link href="https://sysl.sh/guides/simd/"/>
    <id>https://sysl.sh/guides/simd/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>One kernel compiled for more than one register width — a lane count that is a value parameter, and the four things writing a constraint solver lane-wise turned up.</summary>
    <content type="html">&lt;p&gt;Box2D’s &lt;code&gt;contact_solver.c&lt;/code&gt; writes the same solver four times — AVX2, NEON, SSE2 and a scalar
fallback, selected by &lt;code&gt;#if&lt;/code&gt; — and over half of that 2120-line file is those four copies. This program
asks whether sysl can write it once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: one body, more than one register width.&lt;/strong&gt; Every other program in the set is written for
one machine shape. This is the one where the &lt;em&gt;width&lt;/em&gt; is the variable, and the interesting part is
that the mechanism is not a vector feature at all.&lt;/p&gt;
&lt;h2 id=&quot;the-lane-count-is-an-ordinary-value-parameter&quot;&gt;The lane count is an ordinary value parameter&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/vectors/&quot;&gt;&lt;code&gt;&amp;lt;N&amp;gt;T&lt;/code&gt;&lt;/a&gt; is N lanes of T. What makes one kernel serve several widths is that
&lt;code&gt;N&lt;/code&gt; can come from a &lt;a href=&quot;/reference/generics/&quot;&gt;value parameter&lt;/a&gt;, exactly as &lt;code&gt;[N]T&lt;/code&gt; reads an array’s
length:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;solve&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](vn: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, mass: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, bias: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; impulse = (bias - vn) * mass

    &lt;span class=&quot;hl-comment&quot;&gt;// The impulse a contact applies can only push, never pull — so a negative one is clamped away.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;return&lt;/span&gt; (impulse &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;select&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;, impulse)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; solve&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in that body names a width. &lt;code&gt;W&lt;/code&gt; is read off the argument, the mask &lt;code&gt;impulse &amp;lt; 0.0&lt;/code&gt; is a
&lt;code&gt;&amp;lt;W&amp;gt;bool&lt;/code&gt; because the vector it compares is a &lt;code&gt;&amp;lt;W&amp;gt;f32&lt;/code&gt;, and &lt;code&gt;select&lt;/code&gt; chooses at whatever width the
mask has. Called with four lanes and with eight, it is two bodies holding different instructions from
one piece of source — &lt;code&gt;fmul &amp;lt;4 x float&amp;gt;&lt;/code&gt; in one and &lt;code&gt;fmul &amp;lt;8 x float&amp;gt;&lt;/code&gt; in the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The clamp is why &lt;code&gt;select&lt;/code&gt; is a method rather than an &lt;code&gt;if&lt;/code&gt;.&lt;/strong&gt; Some lanes want it and others do not,
and a branch takes one path for the whole register. Both sides are computed and the mask picks per
lane. That a mask is an ordinary value — it binds, combines with &lt;code&gt;&amp;amp;&lt;/code&gt;, and reduces with &lt;code&gt;any&lt;/code&gt; and
&lt;code&gt;all&lt;/code&gt; — is what keeps the solver’s convergence test to one word instead of a loop with an early exit.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A vector may not cross to C, and the refusal had to be built.&lt;/strong&gt; The scope said it was refused and
nothing implemented it, so an &lt;code&gt;extern&lt;/code&gt; taking a &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; emitted the declaration and made a call
whose convention nothing had checked. Which register a vector arrives in differs by target &lt;em&gt;and&lt;/em&gt; by
which extensions the other side was compiled for — so the failure mode is a call that resolves and
corrupts its arguments, not one that fails to link, which is precisely what a boundary check exists
to prevent. The shape that does cross is the one C’s own SIMD-taking functions take: a pointer to the
lanes. The &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI reference&lt;/a&gt; carries the rule.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;v += 1.0&lt;/code&gt; was refused while &lt;code&gt;v = v + 1.0&lt;/code&gt; beside it worked.&lt;/strong&gt; The compound form did not broadcast
its scalar, so two spellings defined to reach the same instruction disagreed about it. That is the
kind of gap a program finds and a suite does not: a suite tests the form it was written for, and a
program writes whichever one reads better.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A vector’s lanes could not reach memory, and that was the main finding.&lt;/strong&gt; There was no way to move
a &lt;code&gt;&amp;lt;W&amp;gt;f32&lt;/code&gt; into a &lt;code&gt;[W]f32&lt;/code&gt; or a &lt;code&gt;[]f32&lt;/code&gt;, and no way to build one from a run of a slice — so a kernel
could compute a batch of results and had nowhere to put them. At a &lt;em&gt;parameterised&lt;/em&gt; width it could not
be written at all, since a lane index must be a constant and a &lt;code&gt;[const W]&lt;/code&gt; body has no constant to
write. It was reported rather than worked around, because the workaround would have been per-width
and would have been copied.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/reference/vectors/&quot;&gt;&lt;code&gt;xs.load(i)&lt;/code&gt; and &lt;code&gt;xs.store(i, v)&lt;/code&gt;&lt;/a&gt; are what closed it, and this is the loop the
finding said could not be written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;batch&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](vn: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, mass: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, bias: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, out: []&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, relax: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i + &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt; &amp;lt;= vn.len
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = vn.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; m: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = mass.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = bias.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)

        out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(i, &lt;span class=&quot;hl-function&quot;&gt;solve&lt;/span&gt;(v, m, b) * relax)
        i += &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; vn.len
        out[i] = &lt;span class=&quot;hl-function&quot;&gt;scalar_solve&lt;/span&gt;(vn[i], mass[i], bias[i]) * relax[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; batch&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The tail is the caller’s and it is written out rather than hidden&lt;/strong&gt;, because every kernel over real
data has one: an array whose length is not a multiple of the register’s width ends with fewer
elements left than there are lanes, and a load of that run traps rather than reading past the end. A
masked load would answer it in one instruction and sysl has none; a scalar loop answers it in three
lines, which is what C’s SIMD code writes anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;relax&lt;/code&gt; is a vector rather than an &lt;code&gt;f32&lt;/code&gt;, and it is a choice rather than a workaround.&lt;/strong&gt; The
relaxation factor of a Gauss-Seidel step is a constant broadcast across the lanes, and every real
SIMD solver passes its constants as vectors for that reason — so the parameter says what the kernel
does, and &lt;code&gt;W&lt;/code&gt; falls out of it.&lt;/p&gt;
&lt;p&gt;It was also, when this program was written, the only way &lt;code&gt;W&lt;/code&gt; could enter. Both halves of that have
since moved: a load takes its width from what receives the value, and an &lt;strong&gt;operand&lt;/strong&gt; is such a place
now, so &lt;code&gt;xs.load(i) * by&lt;/code&gt; reads its lane count off &lt;code&gt;by&lt;/code&gt;; and a &lt;strong&gt;written type argument at a call&lt;/strong&gt; is
what a kernel with no vector parameter uses, so &lt;code&gt;add[8](a, b, out)&lt;/code&gt; says the width where the reader
is standing. This program’s findings are what closed both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is still no shuffle, and the gather is where that shows.&lt;/strong&gt; A real solver reads its bodies
through an index table — body 17 in lane 0, body 3 in lane 1 — and moving eight scattered velocities
into lane order costs a scratch array and a pass of scalar stores:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;gather&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, at: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; scratch: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;at.len
        scratch[i] = xs[at[i]]

    &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; scratch.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; gather&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is better than the eight written-out lane writes it replaces, and it is still not one
instruction. &lt;strong&gt;The store is what makes the loop possible&lt;/strong&gt;: a lane index has to be a constant,
because a vector has no address to bounds-check against and a computed lane would be LLVM’s &lt;code&gt;poison&lt;/code&gt;
rather than a trap — while an array index is checked and may be computed. Putting the lanes somewhere
a subscript works is how “check every lane” gets to be an ordinary &lt;code&gt;for&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is also the honest limit on the claim this program set out to test. Box2D’s four copies differ in
the &lt;strong&gt;gather-and-transpose&lt;/strong&gt; half and agree about the arithmetic, so &lt;em&gt;write it once&lt;/em&gt; is a true
statement about the solver and a weaker one about the loading.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/simd&quot;&gt;Source&lt;/a&gt; ·
Back to &lt;a href=&quot;/guides/&quot;&gt;the guide programs&lt;/a&gt;, or on to the &lt;a href=&quot;/reference/vectors/&quot;&gt;vectors reference&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>shapes</title>
    <link href="https://sysl.sh/guides/shapes/"/>
    <id>https://sysl.sh/guides/shapes/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Dynamic dispatch — a collection whose element types are forgotten, and combinators that hold what they cannot name.</summary>
    <content type="html">&lt;p&gt;A catalogue of shapes behind one trait: the dynamic half of the trait system.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: forgetting the type.&lt;/strong&gt; Every other program in the set knows the type of everything it
computes with. This one does not, and that is the whole exercise — a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; is a &lt;a href=&quot;/reference/traits/&quot;&gt;fat
pointer&lt;/a&gt; that has forgotten what it points at, and the only thing left to do with
it is ask the trait’s questions and believe the answers.&lt;/p&gt;
&lt;h2 id=&quot;why-it-needs-two-families&quot;&gt;Why it needs two families&lt;/h2&gt;
&lt;p&gt;The shapes come in two kinds, and the second is what makes the problem worth writing.&lt;/p&gt;
&lt;p&gt;Four of them are &lt;strong&gt;leaves&lt;/strong&gt; — a circle, a rectangle, a triangle, a polygon — and each answers out of
its own fields. The other three are &lt;strong&gt;combinators&lt;/strong&gt;: a group is a shape made of shapes, and a move
and a scale each wrap one shape and adjust what it says.&lt;/p&gt;
&lt;p&gt;A combinator holds &lt;code&gt;&amp;amp;Shape&lt;/code&gt;, so it holds something it &lt;strong&gt;cannot name&lt;/strong&gt;, and a group of groups is
dynamic dispatch calling itself. A trait-object design that only ever holds leaves has not been
tested; one that holds arbitrary other objects of the same trait has.&lt;/p&gt;
&lt;h2 id=&quot;what-it-exercises&quot;&gt;What it exercises&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Erasure is a coercion, applied per position.&lt;/strong&gt; Each concrete shape is constructed, boxed because a
&lt;code&gt;&amp;amp;Shape&lt;/code&gt; was expected, and then erased — the ordinary “write the construction and it is allocated”
rule with one more step. Because the coercion applies per branch, an &lt;code&gt;if&lt;/code&gt; or a &lt;code&gt;match&lt;/code&gt; whose arms are
different concrete types meets at one trait object, which is the point of having them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Object safety is what makes the trait usable this way.&lt;/strong&gt; A trait can be made into an object when
every member has a receiver and mentions &lt;code&gt;Self&lt;/code&gt; nowhere but there. &lt;code&gt;Shape&lt;/code&gt;‘s members answer questions
&lt;em&gt;about&lt;/em&gt; the shape and never hand another one back at its own type, so it qualifies — where the whole
&lt;a href=&quot;/reference/traits/&quot;&gt;operator catalogue&lt;/a&gt; does not, &lt;code&gt;add(self, rhs: Self) -&amp;gt; Self&lt;/code&gt; being the clearest
case. That exclusion is the right answer rather than a limitation: an operator over two values of one
type is a question about types known while compiling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bounding box is a plain struct rather than a shape.&lt;/strong&gt; It is the answer to a question &lt;em&gt;about&lt;/em&gt; a
shape and not another thing to dispatch on — a distinction that is easy to lose when everything in
sight is a trait object, and the reason the file says so out loud.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/shapes&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/scheduler/&quot;&gt;scheduler&lt;/a&gt; — OS shapes, and reference graphs mutated through references.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sha2</title>
    <link href="https://sysl.sh/guides/sha2/"/>
    <id>https://sysl.sh/guides/sha2/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Generic arithmetic — one implementation serving four hash functions across two word widths.</summary>
    <content type="html">&lt;p&gt;SHA-224, SHA-256, SHA-384 and SHA-512, plus HMAC over them: one implementation, two word widths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: generic arithmetic.&lt;/strong&gt; The message schedule, the round function, the padding, the
streaming buffer and the digest are written once and serve four functions. What varies by &lt;em&gt;width&lt;/em&gt; is
reached through a &lt;code&gt;Word&lt;/code&gt; bound — the width itself, the round count, the constant table and the four
mixing functions. What varies per &lt;strong&gt;digest&lt;/strong&gt; rather than per width is an argument instead: SHA-224 and
SHA-256 are the same word type, and a type may implement a trait once at a given argument list.&lt;/p&gt;
&lt;p&gt;That last sentence is the design constraint doing real work rather than a limitation being worked
around. Two things that differ per width belong in the &lt;a href=&quot;/reference/generics/&quot;&gt;bound&lt;/a&gt;; two things that
differ within one width cannot, and become parameters. The program is the demonstration that the line
falls in a usable place.&lt;/p&gt;
&lt;h2 id=&quot;what-it-exercises&quot;&gt;What it exercises&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A conversion may be written at a type parameter, in both directions.&lt;/strong&gt; &lt;code&gt;T(b)&lt;/code&gt; builds a word out of a
byte and &lt;code&gt;u8(x)&lt;/code&gt; takes one back out, each resolved once the instantiation says what the width is. The
pair being symmetric is what lets the byte-order code be written once — bytes arrive most significant
first, so a word is built by shifting each one in from the bottom, and that loop is the same code at
32 and 64 bits.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bound written at a type is inherited by every member.&lt;/strong&gt; The hash-in-progress struct declares
&lt;code&gt;Word&lt;/code&gt; once, and its members do not restate it. That is the answer to the repetition the free
functions above it show, and it is the concrete reason a container is a better place to put a bound
than a pile of functions is — a point the &lt;a href=&quot;/reference/generics/&quot;&gt;generics reference&lt;/a&gt; states as a rule
and this program measures in lines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Static tables.&lt;/strong&gt; The round constants are large fixed arrays of words, which is the other half of
what “generic arithmetic” needs: a table per width, reachable from generic code, with no allocation
and no initialization step. That is a &lt;a href=&quot;/reference/declarations/&quot;&gt;module-level &lt;code&gt;val&lt;/code&gt;&lt;/a&gt; doing exactly
what it is for.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/sha2&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/shapes/&quot;&gt;shapes&lt;/a&gt; — the dynamic half of the trait system.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>scheduler</title>
    <link href="https://sysl.sh/guides/scheduler/"/>
    <id>https://sysl.sh/guides/scheduler/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>OS shapes — a run queue, blocking and waking, priority inheritance, and `&amp;T` graphs mutated through references.</summary>
    <content type="html">&lt;p&gt;A priority scheduler: tasks, locks, and the run loop that decides who gets the next tick.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: OS territory.&lt;/strong&gt; The first program in the set where sysl has to behave like systems code
rather than like an application. A run queue, a priority, a task that blocks and a task that wakes it
are the shapes a kernel is made of, and they are made of &lt;code&gt;&amp;amp;T&lt;/code&gt; graphs mutated &lt;strong&gt;through&lt;/strong&gt; references:
a lock points at its owner, the owner points back at the lock it holds, and a waiter points at what
it is waiting for while that thing points at the waiter.&lt;/p&gt;
&lt;p&gt;The centrepiece is &lt;strong&gt;priority inheritance&lt;/strong&gt;, because it is the one place all of it has to work at
once. A low-priority task holding a lock a high-priority task wants is lent the waiter’s urgency
until it lets go — which means finding the holder in the ready queue and moving it, the decrease-key
the heap exists for. Run the same three tasks with the lending switched off and the schedule is the
classic unbounded inversion; switch it on and the urgent task waits for the critical section instead
of for an unrelated third task. Both traces can be worked out on paper, and the program asserts them
character by character.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The wait graph is a reference cycle.&lt;/strong&gt; A blocked task points at the lock and the lock’s waiter list
points back at the task; an owner and the lock it holds are a second cycle. &lt;code&gt;weak&lt;/code&gt; is exactly the
tool for it, and at the time this was written the compiler knew nothing but the reserved word. What
saved the program is that a scheduler takes its own graph apart — every wait ends in a wakeup and
every lock is released — so its last section asserts that nothing is left holding anything.&lt;/p&gt;
&lt;p&gt;That is a property worth having anyway, and here it was standing in for a guarantee the language
should have been making. &lt;a href=&quot;/reference/memory/&quot;&gt;&lt;code&gt;weak T&lt;/code&gt; has since shipped&lt;/a&gt;, and a program of this
shape can now say which edge of a cycle does not own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;Buf&lt;/code&gt; grew and shrank at its end and nowhere else — answered.&lt;/strong&gt; Every list a scheduler keeps is
one that things leave the &lt;em&gt;middle&lt;/em&gt; of, and taking a waiter out was compact-then-pop, because there
was no &lt;code&gt;remove&lt;/code&gt; and no &lt;code&gt;truncate&lt;/code&gt; to say it in one step. &lt;code&gt;Buf&lt;/code&gt; has both now, so the program’s helper
is a search and one call.&lt;/p&gt;
&lt;p&gt;What that exposed is worth more than the lines it saved: the hand-written version removed &lt;strong&gt;every&lt;/strong&gt;
copy of the value, because compacting keeps whatever does not match, while the name said one and the
callers all meant one. A scheduler never has a task in a list twice, so nothing was wrong — and
nothing was checked either. Reaching for the library function is reaching for a decision somebody
has already made carefully.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A task is fifteen fields with no names at the call site and no defaults — half answered.&lt;/strong&gt; A task
control block is exactly the shape that pays for this: mostly state that starts empty and is written
later by somebody else.&lt;/p&gt;
&lt;p&gt;The names arrived. A constructor’s fields are &lt;a href=&quot;/reference/declarations/&quot;&gt;named parameters like any
other&lt;/a&gt;, so the program writes all fifteen by name — which is worth most for
the four that are the same bare &lt;code&gt;0&lt;/code&gt; and would swap without anything noticing. The defaults did not,
and that half is a decision rather than an absence: a field declares no default, on the grounds that
what an unwritten field gets is the constructor’s business and not the field’s. So the helper stays
to spell the zeroes, and is now a body that says what it is doing rather than a row of fifteen
positional arguments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A nullary generic cannot be told what it is making.&lt;/strong&gt; &lt;code&gt;buf[&amp;amp;Mutex]()&lt;/code&gt; is not the syntax:
call-site type arguments are deliberately absent, since a type-argument list and an index are the
same grammar. Where the value lands somewhere already typed there is nothing to do — the &lt;code&gt;buf()&lt;/code&gt;
filling a task’s list takes its element type from the field — so it is a &lt;code&gt;var&lt;/code&gt; that has to say it.
The reach for the other spelling is natural enough that the compiler used to answer it with “the
thing being called must be a name”; it now names the rule and the annotation instead, which was this
program’s one change to the compiler rather than to itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No enum renders itself.&lt;/strong&gt; &lt;code&gt;str&lt;/code&gt; on one is refused — helpfully, naming the &lt;code&gt;impl Display&lt;/code&gt; that would
answer it — for a data-carrying enum and a plain one alike. So the state description is a hand-written
match from six variants to their own six names, which the compiler already knows: they are the words
the match arms are written with. Other programs write a &lt;code&gt;describe&lt;/code&gt; too, but for a &lt;em&gt;message&lt;/em&gt; built out
of a payload; this is the first whose rendering is nothing but the name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt; is &lt;code&gt;Eq&lt;/code&gt;, and that is what identity costs — nothing.&lt;/strong&gt; Address equality is what “is this the
lock you actually hold” and “did the heap take its own root off the end” are written with. Worth
recording as a &lt;strong&gt;positive&lt;/strong&gt;: a language without it forces a unique name compared as a string, which
is wrong in a way that only shows up once two objects are named alike.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/scheduler&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/kernel/&quot;&gt;kernel&lt;/a&gt; — the same machine with no heap at all.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>ring</title>
    <link href="https://sysl.sh/guides/ring/"/>
    <id>https://sysl.sh/guides/ring/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The constrained-subtype surface — and an invariant that found a redundant field rather than a bug.</summary>
    <content type="html">&lt;p&gt;A bounded ring buffer: fixed storage, indices that cannot leave it, and the whole of what “this ring
is consistent” means written into the types and the contracts rather than into the checks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: the constrained-subtype surface&lt;/strong&gt; — &lt;code&gt;within&lt;/code&gt; ranges, the &lt;code&gt;::&lt;/code&gt; attributes they expose,
&lt;code&gt;require&lt;/code&gt;/&lt;code&gt;ensure&lt;/code&gt;/&lt;code&gt;old&lt;/code&gt;, and struct invariants. &lt;a href=&quot;/guides/kernel/&quot;&gt;kernel&lt;/a&gt; gives its tables bounded
identities and then never asks one a question; until this program nothing in the set had read an
attribute or written a contract at all. A ring buffer is the smallest subject needing all of them at
once, because every bug a ring buffer has is an index that went somewhere it should not have — and
those are the bugs a range type exists to make unwritable.&lt;/p&gt;
&lt;p&gt;Like &lt;a href=&quot;/guides/kernel/&quot;&gt;kernel&lt;/a&gt; against &lt;a href=&quot;/guides/scheduler/&quot;&gt;scheduler&lt;/a&gt;, it is &lt;strong&gt;written to be
compared&lt;/strong&gt;: two buffers under the same scenarios, one keeping the fact of where the ring ends once and
the other keeping it twice. Every check runs both and asserts they agree, so the difference between
the two implementations is the measurement.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A derived subtype’s attributes handed back its base&lt;/strong&gt;, which made the whole &lt;code&gt;::&lt;/code&gt; surface unusable by
the only kind of subtype that needs it. &lt;code&gt;Slot::Last&lt;/code&gt; was a &lt;code&gt;byte&lt;/code&gt;, &lt;code&gt;Slot::Succ&lt;/code&gt; took one, and the loop
variable of &lt;code&gt;Slot::Range&lt;/code&gt; was one — so every use of an attribute had to be cast back into &lt;code&gt;Slot&lt;/code&gt;,
undoing the &lt;code&gt;new&lt;/code&gt; that made it a type at all. The sibling surface next door had it right all along: a
simple enum’s &lt;code&gt;First&lt;/code&gt;, &lt;code&gt;Last&lt;/code&gt;, &lt;code&gt;Succ&lt;/code&gt; and &lt;code&gt;Pred&lt;/code&gt; are the enum.&lt;/p&gt;
&lt;p&gt;It was invisible until this program because a &lt;em&gt;transparent&lt;/em&gt; subtype &lt;strong&gt;is&lt;/strong&gt; its base, and every test
the attributes had used a transparent one. Fixed in the compiler — &lt;a href=&quot;/reference/errors/&quot;&gt;the attributes are the
subtype&lt;/a&gt;, and &lt;code&gt;Valid&lt;/code&gt; alone takes the base, because asking whether a value is a
&lt;code&gt;Slot&lt;/code&gt; is only a question about something that is not one yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The successor of the last slot is a trap, not a wrap.&lt;/strong&gt; &lt;code&gt;Slot::Succ&lt;/code&gt; steps within the range and
refuses at &lt;code&gt;Last&lt;/code&gt;, which is exactly right for a counter and exactly wrong for a ring — the one
operation a ring buffer is &lt;em&gt;made&lt;/em&gt; of is the step that goes round. So the modular successor is written
by hand out of &lt;code&gt;%&lt;/code&gt;. &lt;strong&gt;That is not a defect&lt;/strong&gt;; it is what the attributes mean. &lt;code&gt;Succ&lt;/code&gt; is the step that
stays inside a range, and a ring’s step does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An invariant relating two fields is a claim about the representation, not about the code.&lt;/strong&gt; The
tracked buffer keeps head, tail and count, so &lt;code&gt;tail == (head + count) % capacity&lt;/code&gt; — and a push that
writes &lt;code&gt;tail&lt;/code&gt; and then &lt;code&gt;count&lt;/code&gt; traps at the first of the two, on a state that was on its way to a
perfectly good one.&lt;/p&gt;
&lt;p&gt;The reflex is to call that a wart and reach for a way to suspend the check. It is not a wart: &lt;strong&gt;the
invariant is the compiler pointing out that the struct carries one fact twice.&lt;/strong&gt; The other buffer —
head and count, with tail computed — has no invariant to break because there is nothing left to
disagree. The mid-update trap found a redundant field, which is what it is for.&lt;/p&gt;
&lt;p&gt;There are &lt;strong&gt;two&lt;/strong&gt; honest two-field designs and the clause rules out neither: this one, and the
embedded classic that keeps head and tail and derives the count, paying one unused slot to tell a full
ring from an empty one. That second is what an interrupt-driven ring wants, because a producer and a
consumer then write disjoint fields and neither has to touch a shared count. What the clause refuses
is only the third design that keeps all three.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where the fields genuinely cannot be ordered, the way out costs the whole struct.&lt;/strong&gt; The only form
that moves two fields without being seen between them is whole-struct assignment, which restates the
buffer to move two bytes — thirty-two bytes copied per push against three written here, and for a ring
sized like a real one the entire storage, per element. &lt;strong&gt;An invariant across two fields makes the
container’s own update cost the size of the container.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ordering the writes is enough more often than it looks.&lt;/strong&gt; A watermark relates two fields too, and
needs none of the above, because raising the ceiling before the floor keeps every intermediate state
legal. The whole-struct form is the last resort, not the first: ask whether an order exists, and only
then whether the representation is redundant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A program’s own run cannot check its contracts; a test can.&lt;/strong&gt; A violated &lt;code&gt;require&lt;/code&gt;
&lt;a href=&quot;/reference/errors/&quot;&gt;traps&lt;/a&gt;, so no check in the run can be the one that breaks it — the program would
die rather than report, and the run would look truncated instead of failed. Every refusal the run
asserts therefore comes from a total operation that answers instead of trapping.&lt;/p&gt;
&lt;p&gt;What the trap itself needs is somewhere that outlives the process it ends, and that is a
&lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;@test(should_trap)&lt;/code&gt;&lt;/a&gt; function: it runs in a process of its own and passes by
not coming back. This is the program that first needed them, and they live beside the code they are
about rather than being restated in a language the ring is not written in.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/ring&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/slab/&quot;&gt;slab&lt;/a&gt; — raw storage, and the first of the two literate programs in the set.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Regular expressions</title>
    <link href="https://sysl.sh/library/regex/"/>
    <id>https://sysl.sh/library/regex/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.regex` — POSIX Extended Regular Expressions, matched by a Pike VM whose cost is the input length times the pattern length and never anything worse.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.regex&lt;/code&gt; compiles a POSIX Extended Regular Expression and matches it against text. Two types are
the whole of the surface: a &lt;code&gt;Regex&lt;/code&gt;, which is a compiled pattern, and a &lt;code&gt;Match&lt;/code&gt;, which is what one
found.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; re = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;([a-z]+)@([a-z.]+)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

re.&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;write to ed@example.com today&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(m) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;(), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, m.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, m.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no address&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ed@example.com from ed at example.com
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-it-costs&quot;&gt;What it costs&lt;/h2&gt;
&lt;p&gt;Matching is a &lt;a href=&quot;https://swtch.com/~rsc/regexp/regexp2.html&quot;&gt;Pike VM&lt;/a&gt; — Ken Thompson’s 1968 NFA
simulation, extended by Rob Pike to carry capture positions. Every branch of the pattern is followed
at once rather than one at a time with backtracking, so the work is &lt;strong&gt;the input length times the
pattern length&lt;/strong&gt;, and no pattern makes it worse than that.&lt;/p&gt;
&lt;p&gt;That is a guarantee rather than a typical case. &lt;code&gt;(a|a)*b&lt;/code&gt; against a run of &lt;code&gt;a&lt;/code&gt;s with no &lt;code&gt;b&lt;/code&gt; is the
standard demonstration: a backtracking engine has to try every way of splitting the run between two
identical alternatives, which at forty characters is a trillion attempts and will not finish.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; re = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(a|a)*b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hay = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; hay += &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(re.&lt;span class=&quot;hl-function&quot;&gt;is_match&lt;/span&gt;(hay))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The price of that guarantee is the feature backtracking buys and this cannot have: there are &lt;strong&gt;no
backreferences&lt;/strong&gt;. &lt;code&gt;(a)\1&lt;/code&gt; is not a pattern that matches a doubled character; &lt;code&gt;\1&lt;/code&gt; is an escaped &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The bound is on &lt;em&gt;matching&lt;/em&gt;, and the other end needs bounding too. An interval is expanded into that
many copies of what precedes it, so intervals stack multiplicatively: &lt;code&gt;a{200}{200}{200}&lt;/code&gt; is sixteen
characters and eight million instructions, and one more factor is a billion. A pattern is therefore
refused if it would lay out more than a hundred thousand — far past anything written on purpose, and
what keeps a pattern arriving from somewhere untrusted from exhausting memory before it ever runs.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.{regex, describe}

&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a{200}{200}{200}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(_) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(e))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the pattern expands past 100000 instructions
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;compiling&quot;&gt;Compiling&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;regex&lt;/code&gt; answers a &lt;code&gt;Result&lt;/code&gt;, because a pattern is text and text can be wrong. Compiling is separated
from matching on purpose — it is the expensive half, and a program matching in a loop should compile
once outside it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.{regex, describe}

&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(_) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;compiled&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(e))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a group is never closed, opened at 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every refusal carries the offset in the pattern where the trouble is, and &lt;code&gt;RegexError&lt;/code&gt; is an enum, so
a program that wants to treat one case differently from another can match on it rather than reading
a message.&lt;/p&gt;
&lt;h2 id=&quot;what-a-match-reports&quot;&gt;What a match reports&lt;/h2&gt;
&lt;p&gt;Spans, as &lt;strong&gt;byte offsets into the input&lt;/strong&gt; — always on character boundaries, so one is directly what
&lt;code&gt;s[a..&amp;lt;b]&lt;/code&gt; takes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[0-9]+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;order 1234 shipped&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;(), m.&lt;span class=&quot;hl-function&quot;&gt;end&lt;/span&gt;(), m.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 10 1234
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A capture group is asked for by number, and the answer is an &lt;code&gt;Option&lt;/code&gt;. That is not caution: there is
a real difference between a group that took no part in the match and one that matched the empty
string, and a span alone cannot tell them apart.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; either = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(a)|(b)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; empty = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(a*)b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(either.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), either.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(empty.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;empty.&lt;span class=&quot;hl-function&quot;&gt;group&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false b
true []
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Group 0 is the whole match and always took part, which is why &lt;code&gt;text()&lt;/code&gt; unwraps it for you.&lt;/p&gt;
&lt;h2 id=&quot;walking-a-text&quot;&gt;Walking a text&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;find_all&lt;/code&gt; gives every match, left to right and not overlapping.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; words = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[a-z]+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; all = words.&lt;span class=&quot;hl-function&quot;&gt;find_all&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the quick brown fox&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;all.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(all.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i).&lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;(), all.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i).&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 the
4 quick
10 brown
16 fox
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A pattern that can match the empty string would otherwise be found at the same place for ever, so
the walk resumes one character past an empty match. &lt;code&gt;a*&lt;/code&gt; over &lt;code&gt;&amp;quot;bb&amp;quot;&lt;/code&gt; therefore finds three: before
each &lt;code&gt;b&lt;/code&gt;, and after the last.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a*&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find_all&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bb&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The anchors keep speaking about the whole text&lt;/strong&gt;, not about where a search resumed. That is why
&lt;code&gt;find_all&lt;/code&gt; takes a starting position rather than searching a shortened input — the obvious way to
write it would hand &lt;code&gt;^&lt;/code&gt; a fresh beginning to match against at every step.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;^ab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find_all&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;replacing-and-splitting&quot;&gt;Replacing and splitting&lt;/h2&gt;
&lt;p&gt;Both are written in terms of &lt;code&gt;find_all&lt;/code&gt;, so all three agree about what the matches are.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; assign = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;([a-z]+)=([0-9]+)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(assign.&lt;span class=&quot;hl-function&quot;&gt;replace_all&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x=1, yy=22&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2:&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1:x, 22:yy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The replacement is not a pattern, but it may name the groups the match found: &lt;code&gt;\1&lt;/code&gt; through &lt;code&gt;\9&lt;/code&gt; for
those groups, &lt;code&gt;\0&lt;/code&gt; for the whole match, &lt;code&gt;\\&lt;/code&gt; for a backslash. A group that took no part contributes
nothing rather than the two characters that named it.&lt;/p&gt;
&lt;p&gt;Note the doubling. &lt;code&gt;\2&lt;/code&gt; is not one of sysl’s &lt;a href=&quot;/reference/lexical/&quot;&gt;string escapes&lt;/a&gt; and the compiler
refuses it, so a replacement naming group 2 is written &lt;code&gt;&amp;quot;\\2&amp;quot;&lt;/code&gt; — the same doubling a pattern needs
for &lt;code&gt;&amp;quot;\\.&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;split&lt;/code&gt; answers the pieces between the matches, empty ones included — a splitter that drops them
loses a field.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; parts = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;split&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a,b,,c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(parts.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())
&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;parts.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;parts.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i)&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
[a]
[b]
[]
[c]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-pattern-syntax&quot;&gt;The pattern syntax&lt;/h2&gt;
&lt;p&gt;POSIX ERE, in full.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;means&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;a&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the character itself&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;&lt;td&gt;any one character, newline included&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt; &lt;code&gt;$&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the beginning and the end of the text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[abc]&lt;/code&gt; &lt;code&gt;[a-z]&lt;/code&gt; &lt;code&gt;[^a-z]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a bracket expression, a range, a negated one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[[:alpha:]]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a named class — see below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;(e)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a capture group, numbered by where its &lt;code&gt;(&lt;/code&gt; is&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e*&lt;/code&gt; &lt;code&gt;e+&lt;/code&gt; &lt;code&gt;e?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;zero or more, one or more, zero or one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e{n}&lt;/code&gt; &lt;code&gt;e{n,}&lt;/code&gt; &lt;code&gt;e{n,m}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;exactly, at least, between&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ab&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;a&lt;/code&gt; then &lt;code&gt;b&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;a\|b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;a&lt;/code&gt; or &lt;code&gt;b&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\x&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the character &lt;code&gt;x&lt;/code&gt;, ordinary whatever it usually means&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The twelve named classes are &lt;code&gt;alpha&lt;/code&gt;, &lt;code&gt;digit&lt;/code&gt;, &lt;code&gt;alnum&lt;/code&gt;, &lt;code&gt;upper&lt;/code&gt;, &lt;code&gt;lower&lt;/code&gt;, &lt;code&gt;space&lt;/code&gt;, &lt;code&gt;blank&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;,
&lt;code&gt;graph&lt;/code&gt;, &lt;code&gt;cntrl&lt;/code&gt;, &lt;code&gt;punct&lt;/code&gt; and &lt;code&gt;xdigit&lt;/code&gt;. Each is the corresponding member of
&lt;a href=&quot;/library/&quot;&gt;&lt;code&gt;sysl.text.Ascii&lt;/code&gt;&lt;/a&gt;, so each answers over the ASCII range and &lt;code&gt;false&lt;/code&gt; above it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; word = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[[:alpha:]][[:alnum:]_]*&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(word.&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;  n42_ok!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;n42_ok
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two positional rules inside a bracket expression are worth knowing because they are the way to
include the awkward characters. A &lt;code&gt;]&lt;/code&gt; &lt;strong&gt;first&lt;/strong&gt; is an ordinary &lt;code&gt;]&lt;/code&gt;, and a &lt;code&gt;-&lt;/code&gt; &lt;strong&gt;first or last&lt;/strong&gt; is an
ordinary &lt;code&gt;-&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[]-]+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a]-]b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;]-]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A backslash inside a bracket expression is an ordinary character, as POSIX requires — so &lt;code&gt;[\t]&lt;/code&gt; is
the two characters backslash and &lt;code&gt;t&lt;/code&gt;, not a tab.&lt;/p&gt;
&lt;h2 id=&quot;characters-not-bytes&quot;&gt;Characters, not bytes&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; in sysl is UTF-8 by construction, and this engine matches over its characters. So &lt;code&gt;.&lt;/code&gt; is
one character however many bytes it occupies, and the span it reports is one a slice can cut — where
a byte-stepping matcher would hand back half of a character.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;(), m.&lt;span class=&quot;hl-function&quot;&gt;end&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hé 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same holds in a pattern: &lt;code&gt;[é-ü]&lt;/code&gt; is a range between two characters, not between four bytes.&lt;/p&gt;
&lt;h2 id=&quot;leftmost-then-longest&quot;&gt;Leftmost, then longest&lt;/h2&gt;
&lt;p&gt;POSIX asks for the match that begins earliest, and among those the one that runs longest. Both hold
here, and the second is where POSIX and Perl part company: given &lt;code&gt;a|ab&lt;/code&gt; against &lt;code&gt;&amp;quot;ab&amp;quot;&lt;/code&gt;, Perl takes
the first alternative that works and answers &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;regex&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a|ab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ab&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ab
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What is not implemented is POSIX’s rule for the subexpressions.&lt;/strong&gt; The whole match is leftmost and
longest; a capture group inside it holds what the preferred path through the pattern gave it, which
is the greedy reading rather than the one POSIX derives for each group in turn. Go and Rust make the
same choice, and it shows on patterns like &lt;code&gt;(a|ab)(c|bcd)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-not-here&quot;&gt;What is not here&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Basic Regular Expressions.&lt;/strong&gt; &lt;code&gt;\(&lt;/code&gt; opens a group in BRE and is a literal parenthesis here, which
is the opposite convention. Only ERE is implemented.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backreferences&lt;/strong&gt;, for the reason above: they are what makes matching NP-hard, and the whole point
of this engine is that it cannot be made slow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lazy quantifiers.&lt;/strong&gt; &lt;code&gt;a*?&lt;/code&gt; is not a lazy star; ERE has no such thing, and it reads as a star made
optional again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt; — no case-insensitive mode, no multiline mode. &lt;code&gt;[[:alpha:]]&lt;/code&gt; and an explicit &lt;code&gt;\n&lt;/code&gt; say
both, at the cost of saying them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;looking-at-what-a-pattern-became&quot;&gt;Looking at what a pattern became&lt;/h2&gt;
&lt;p&gt;The tree and the program are both public, and both render, for a caller asking why their pattern does
what it does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.regex.{parse, compile_pattern, show, dump}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a(b|c)*&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;dump&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;compile_pattern&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a?&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;seq(lit(a), star(group1(alt(lit(b), lit(c)))))
0: save 0
1: split 2, 3
2: char a
3: save 1
4: accept
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;sysl.buf&lt;/code&gt;&lt;/a&gt; — the growable sequence everything here builds on.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The rand module</title>
    <link href="https://sysl.sh/library/rand/"/>
    <id>https://sysl.sh/library/rand/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.rand` — PCG32, seeded by the caller and reproducible; a bounded integer with no modulo bias, a shuffle that is Fisher-Yates, and OS seeding kept in a module of its own so a freestanding target need never import it.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.rand&lt;/code&gt; is a named, seedable, reproducible pseudo-random generator and the distributions that are
easy to get wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is not a source of unpredictability, and nothing here should be used as one.&lt;/strong&gt; The generator is
completely determined by its seed — which is exactly what a test that must reproduce, a simulation
that must replay, and a shuffle all want, and exactly what a key, a token, a nonce or a password reset
must not have. Anyone who can see a handful of outputs can compute the state and every output that
follows. A cryptographic generator is a different thing with a different implementation, and it is not
in this module under any name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.rand.rng

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;54&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g.&lt;span class=&quot;hl-function&quot;&gt;below&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;), g.&lt;span class=&quot;hl-function&quot;&gt;below&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;), g.&lt;span class=&quot;hl-function&quot;&gt;below&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g.&lt;span class=&quot;hl-function&quot;&gt;boolean&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 3 2
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those numbers are not illustrative — they are what that seed produces, every run, on every machine.
That is the whole point of the module.&lt;/p&gt;
&lt;h2 id=&quot;the-algorithm-is-named-so-it-can-be-checked&quot;&gt;The algorithm is named so it can be checked&lt;/h2&gt;
&lt;p&gt;It is &lt;strong&gt;PCG32&lt;/strong&gt; — PCG-XSH-RR with a 64-bit state and 32-bit output, from M. E. O’Neill’s &lt;em&gt;PCG: A
Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation&lt;/em&gt;
(2014). The library’s own tests pin it against the reference implementation’s first outputs, because
a generator nobody can identify is one nobody can verify.&lt;/p&gt;
&lt;p&gt;The state advances by an ordinary linear congruential step, and the &lt;em&gt;output&lt;/em&gt; is a permutation of the
state’s high bits rather than the state itself. That second step is what a bare congruential generator
lacks, and it is why its low bits are notoriously poor — here every bit of the output is a product of
the whole state.&lt;/p&gt;
&lt;h2 id=&quot;seeding-is-the-caller-s-and-that-is-what-keeps-it-portable&quot;&gt;Seeding is the caller’s, and that is what keeps it portable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;rng(seed, seq)&lt;/code&gt; takes two arguments because &lt;strong&gt;the stream is not the seed&lt;/strong&gt;. Two generators with the
same seed and different &lt;code&gt;seq&lt;/code&gt; produce different, equally good sequences — which is what a program
wanting several independent streams from one seed needs, and what seeding from consecutive seeds does
&lt;em&gt;not&lt;/em&gt; reliably give.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.rand.rng

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;next_u32&lt;/span&gt;() == b.&lt;span class=&quot;hl-function&quot;&gt;next_u32&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;next_u32&lt;/span&gt;() == c.&lt;span class=&quot;hl-function&quot;&gt;next_u32&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in &lt;code&gt;sysl.rand&lt;/code&gt; reads a clock or asks the operating system for anything, so it compiles and
runs on a freestanding target.&lt;/p&gt;
&lt;h2 id=&quot;taking-a-seed-from-the-host-sysl-posix-rand&quot;&gt;Taking a seed from the host — &lt;code&gt;sysl.posix.rand&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A program that wants a different sequence each run needs entropy, and that needs an operating system.
It is a &lt;strong&gt;module of its own&lt;/strong&gt; so that importing the generator cannot drag one in behind it — the same
split &lt;a href=&quot;/library/term/&quot;&gt;&lt;code&gt;sysl.term&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;sysl.posix.tty&lt;/code&gt; already make.&lt;/p&gt;
&lt;p&gt;It sits under &lt;code&gt;sysl.posix&lt;/code&gt; rather than under &lt;code&gt;sysl.rand&lt;/code&gt; because &lt;code&gt;getentropy(2)&lt;/code&gt; is what it is, and
that is the rule the whole namespace follows: a module there is one a freestanding target does not
get, and the path says so without the file having to be opened.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.rand.rng
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.posix.rand.seed_from_os

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;seed_from_os&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g.&lt;span class=&quot;hl-function&quot;&gt;below&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;) &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It answers an &lt;code&gt;Option&lt;/code&gt; rather than trapping: a program that cannot get entropy usually has a
reasonable fallback — a fixed seed and a line in its log saying so — and a library that aborted would
take that choice away. It requires &lt;code&gt;posix&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;below-is-where-this-module-earns-its-keep&quot;&gt;&lt;code&gt;below&lt;/code&gt; is where this module earns its keep&lt;/h2&gt;
&lt;p&gt;The obvious &lt;code&gt;next_u64() % n&lt;/code&gt; is &lt;strong&gt;not uniform&lt;/strong&gt; whenever &lt;code&gt;n&lt;/code&gt; does not divide 2⁶⁴: the low residues
come up more often, by a margin that is invisible in a handful of draws and is a real defect in a
simulation or a shuffle. &lt;code&gt;below&lt;/code&gt; rejects the unfair tail of the range instead, which is exact,
terminates with probability one, and expects under two draws.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.rand.rng

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counts: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;6000&lt;/span&gt;
    counts[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;(g.&lt;span class=&quot;hl-function&quot;&gt;below&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))] += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counts[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;850&lt;/span&gt; &amp;amp;&amp;amp; counts[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;1150&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counts[&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;] &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;850&lt;/span&gt; &amp;amp;&amp;amp; counts[&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;] &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;1150&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;range(lo, hi)&lt;/code&gt; is the same thing over a signed interval, half-open at the top. &lt;code&gt;unit()&lt;/code&gt; answers a
&lt;code&gt;real&lt;/code&gt; in &lt;code&gt;[0, 1)&lt;/code&gt; from &lt;strong&gt;53&lt;/strong&gt; bits — the width of a &lt;code&gt;real&lt;/code&gt;‘s mantissa, so no representable value is
unreachable and none is thrown away — and never returns &lt;code&gt;1.0&lt;/code&gt;, which is the property every caller
scaling by a range depends on.&lt;/p&gt;
&lt;h2 id=&quot;shuffling&quot;&gt;Shuffling&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.rand.rng

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = &lt;span class=&quot;hl-function&quot;&gt;rng&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

g.&lt;span class=&quot;hl-function&quot;&gt;shuffle&lt;/span&gt;(xs)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fisher-Yates, walking down: each position from the end takes a uniformly chosen element from those at
or below it. The whole difficulty is drawing that index without bias, which is &lt;code&gt;below&lt;/code&gt;‘s job — the
loop itself is three lines.&lt;/p&gt;
&lt;p&gt;It lives here rather than in &lt;a href=&quot;/library/slices/&quot;&gt;&lt;code&gt;sysl.slices&lt;/code&gt;&lt;/a&gt; because it is a fact about a
&lt;em&gt;generator&lt;/em&gt;, and because &lt;code&gt;sysl.slices&lt;/code&gt; is the module a C binding reaches into: acquiring a
random-number generator by asking for a slice operation would be a poor trade.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>qsort</title>
    <link href="https://sysl.sh/guides/qsort/"/>
    <id>https://sysl.sh/guides/qsort/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The C boundary in the direction nothing else goes — a C routine that calls back into sysl, and the trampoline, slice address and element size it takes.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;qsort&lt;/code&gt; is handed a slice’s storage, the width of an element, and a comparison — and then it calls
that comparison back, once per step, for as long as the sort runs. This program binds it and checks
its answers against &lt;a href=&quot;/library/slices/&quot;&gt;&lt;code&gt;sysl.slices&lt;/code&gt;&lt;/a&gt;‘ own sort on the same data.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: a callback across the C boundary.&lt;/strong&gt; Every other program in the set either stays inside
sysl or reaches out to C and gets an answer back. This is the one where C reaches &lt;em&gt;in&lt;/em&gt;. It is the
smallest honest example of the shape, and it needs three things at once — the address of a function
that is generic in the element type, the address of a slice’s storage, and the size of an element.&lt;/p&gt;
&lt;h2 id=&quot;the-binding-in-full&quot;&gt;The binding, in full&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;qsort&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_qsort&lt;/span&gt;(base: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, size: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, cmp: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;compare&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(a)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; y: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(b)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;x &amp;lt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;y &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;y &amp;lt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;x &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; compare&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;sort_libc&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;](xs: []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; xs.len &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;c_qsort&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;as_mut_ptr&lt;/span&gt;(xs)), xs.len, &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;compare[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;])
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; sort_libc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;compare&lt;/code&gt; is &lt;strong&gt;one function per element type&lt;/strong&gt;, and that is the whole trick. &lt;code&gt;qsort&lt;/code&gt; is told the
width of an element and otherwise moves anonymous bytes; the only thing that knows what those bytes
&lt;em&gt;are&lt;/em&gt; is that body, and it knows because the compiler made a copy of it for each &lt;code&gt;T&lt;/code&gt; a program
sorted. A C programmer does the same thing by hand and writes the cast themselves — which is exactly
what the two lines at the top of the body are.&lt;/p&gt;
&lt;p&gt;The two comparisons are not clumsiness either. C’s convention has three answers — negative, zero,
positive — and &lt;code&gt;&amp;lt;&lt;/code&gt; has two, so there is no third answer to read off a single test.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The obvious trampoline had no address, and now it has one.&lt;/strong&gt; The natural shape is C’s own signature
with the cast inside it — &lt;code&gt;compare[T: Ord](a: *u8, b: *u8) -&amp;gt; int&lt;/code&gt; — and &lt;code&gt;T&lt;/code&gt; appears in neither
parameter nor result. An address settles a generic function’s instantiation from the &lt;strong&gt;expected
type&lt;/strong&gt;, and the expected type here is &lt;code&gt;*extern(*u8, *u8) -&amp;gt; int&lt;/code&gt;, which does not mention &lt;code&gt;T&lt;/code&gt; at all.
There was nothing to read, and no annotation written anywhere else could have supplied it.&lt;/p&gt;
&lt;p&gt;So the argument is written where the address is taken: &lt;code&gt;&amp;amp;compare[T]&lt;/code&gt;, which was the &lt;strong&gt;first&lt;/strong&gt;
position in the language to take written type arguments and the case that earned them anywhere.
&lt;strong&gt;This program is why they exist.&lt;/strong&gt; What it had to be written as before was a trampoline over &lt;code&gt;*T&lt;/code&gt; rather than &lt;code&gt;*u8&lt;/code&gt;, a second &lt;code&gt;ptr_cast&lt;/code&gt; of the function
pointer, and a &lt;code&gt;val&lt;/code&gt; whose only job was to be somewhere to put the type — a shape imposed by the
language rather than chosen, and one every C callback would have copied, since every one of them
fixes its signature and leaves the payload type to its caller. The
&lt;a href=&quot;/reference/ffi/&quot;&gt;FFI reference&lt;/a&gt; has the form and what its brackets can hold.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no clock, and now there is.&lt;/strong&gt; &lt;a href=&quot;/library/time/&quot;&gt;&lt;code&gt;sysl.time&lt;/code&gt;&lt;/a&gt; had &lt;code&gt;Instant&lt;/code&gt;, &lt;code&gt;Duration&lt;/code&gt; and
the calendar between them, and nothing in the library read one — no monotonic counter and no wall
clock. So this program could compare the two sorts for &lt;em&gt;correctness&lt;/em&gt; and not for &lt;em&gt;cost&lt;/em&gt;, which was
half of why it was written. Binding &lt;code&gt;clock_gettime&lt;/code&gt; here would have answered the question and put a
hand-rolled clock into the reading material, which is the thing a guide program is least allowed to
teach, so it was reported instead and the answer is
&lt;a href=&quot;/library/time/#reading-a-clock-sysl-posix-time&quot;&gt;&lt;code&gt;sysl.posix.time&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The program’s last section uses &lt;code&gt;monotonic&lt;/code&gt;, and the type is the part worth noticing: it answers a
&lt;code&gt;Duration&lt;/code&gt; rather than an &lt;code&gt;Instant&lt;/code&gt;, so one reading means nothing and only the difference of two
does. That is the clock a measurement wants — the wall clock is the one somebody can set, and a sort
timed across an &lt;code&gt;ntpd&lt;/code&gt; adjustment would come out negative. On a hundred thousand pseudo-random &lt;code&gt;int&lt;/code&gt;s
the library’s &lt;code&gt;sort&lt;/code&gt; runs in roughly &lt;strong&gt;seventy per cent&lt;/strong&gt; of C &lt;code&gt;qsort&lt;/code&gt;‘s time, which is the comparison
this program was written to make: sysl’s is monomorphized against the element type, and &lt;code&gt;qsort&lt;/code&gt;‘s
comparison is reached through a pointer it cannot see through.&lt;/p&gt;
&lt;h2 id=&quot;why-this-is-not-in-the-standard-library&quot;&gt;Why this is not in the standard library&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sysl.slices&lt;/code&gt; requires no capability, which is a promise made to every machine sysl builds for —
including the freestanding ones, where there is no C library and &lt;code&gt;qsort&lt;/code&gt; is an undefined symbol at
the end of somebody’s link. The &lt;a href=&quot;/library/slices/#why-these-are-written-in-sysl-rather-than-calling-qsort&quot;&gt;slices page&lt;/a&gt;
has the rest of the argument, including the part that has nothing to do with speed: glibc’s &lt;code&gt;qsort&lt;/code&gt;
allocates a merge buffer and Darwin’s does not, and &lt;strong&gt;the compiler cannot see through an &lt;code&gt;extern&lt;/code&gt;&lt;/strong&gt;
to know which it got.&lt;/p&gt;
&lt;p&gt;That is why the binding lives here, where a reader can see the whole of what it costs on one screen,
rather than in a module whose selling point is that it needs nothing.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/qsort&quot;&gt;Source&lt;/a&gt; ·
Back to &lt;a href=&quot;/guides/&quot;&gt;the guide programs&lt;/a&gt;, or on to the &lt;a href=&quot;/reference/&quot;&gt;reference&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>png</title>
    <link href="https://sysl.sh/guides/png/"/>
    <id>https://sysl.sh/guides/png/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The byte level — three byte orders, four length units, two checksums, and a format someone else defined.</summary>
    <content type="html">&lt;p&gt;A PNG reader: the chunk layer, the checksum, the filters, and the pixels underneath them — including
its own &lt;code&gt;inflate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: the byte level.&lt;/strong&gt; Everything here is arithmetic on bytes somebody else laid out. A PNG is
a signature, then a sequence of chunks, each one a big-endian length, a four-letter name, that many
bytes, and a CRC of the name and the bytes together. The pixels are in the chunks named &lt;code&gt;IDAT&lt;/code&gt;,
concatenated and then deflated; what comes out is not the image but one &lt;strong&gt;filter byte&lt;/strong&gt; per row
followed by a row of differences, and the image is what is left after each row is reconstructed from
the row above it and the pixel to its left.&lt;/p&gt;
&lt;p&gt;Which is to say: three separate byte orders, four separate length units — bytes, samples, pixels,
rows — and a checksum over each of the two layers. Being wrong by one anywhere in that produces an
image, just not the right one. That is what the problem is for.&lt;/p&gt;
&lt;h2 id=&quot;what-it-exercises&quot;&gt;What it exercises&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Naming what a file can be wrong about.&lt;/strong&gt; A reader of somebody else’s format needs a lot of error
cases, and naming them individually is the difference between “this file is broken” and a report that
says where and what. That is an enum with a variant per failure, carried in a
&lt;a href=&quot;/reference/errors/&quot;&gt;&lt;code&gt;Result&lt;/code&gt;&lt;/a&gt; — the shape the language pushes you toward, and the one a byte-level
reader wants anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;unit&lt;/code&gt; as a payload.&lt;/strong&gt; This program and &lt;a href=&quot;/guides/bytecode/&quot;&gt;bytecode&lt;/a&gt; have nothing in common and
both paid for the same missing thing: a fallible step that yields no value. Two independent programs
reporting one absence is what moved it from a nuisance to a language change, and it is the clearest
example in the set of why findings are written down rather than worked around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The one piece of mathematics is the Paeth predictor&lt;/strong&gt;, and the magnitude it needs comes from
&lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt; rather than from a private helper this file writes. The integers are an
open family, so &lt;code&gt;Signed&lt;/code&gt; is a trait the compiler supplies membership for at &lt;strong&gt;every&lt;/strong&gt; width — which
is what stops a byte-level program from having to write its own &lt;code&gt;abs&lt;/code&gt; for the width it happens to be
using.&lt;/p&gt;
&lt;h2 id=&quot;worth-noticing&quot;&gt;Worth noticing&lt;/h2&gt;
&lt;p&gt;The program carries its own fixtures rather than reading a file, so the whole thing is checkable with
no filesystem and no &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;os&lt;/code&gt; capability&lt;/a&gt;. That is not incidental to a guide
program: the set has to keep passing across compiler changes, and a test that needs a file on disk is
a test that fails for a reason unrelated to the language.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/png&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/fft/&quot;&gt;fft&lt;/a&gt; — a type the program defined, and floating point.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Patterns and matching</title>
    <link href="https://sysl.sh/reference/patterns/"/>
    <id>https://sysl.sh/reference/patterns/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Every pattern form, how arms are chosen, what guards do to exhaustiveness, and why alternatives may not bind.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;match&lt;/code&gt; is an expression: it yields a value in value position and reads as ordinary control flow in
statement position. Its shape is a scrutinee and a sequence of arms, each an ordered list of
patterns, an optional guard, and a body.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;         -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;     -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;medium&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;         &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;large&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;zero small medium large
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The keyword goes after the value.&lt;/strong&gt; A match is a transformation of the thing to its left, and
writing it there is what lets one feed another: &lt;code&gt;x match … match …&lt;/code&gt; reads in the order the values
flow. It binds &lt;strong&gt;looser than every operator&lt;/strong&gt;, so the scrutinee is the whole expression written
before it — &lt;code&gt;a &amp;lt; b match&lt;/code&gt; chooses on the comparison, and parentheses are what narrow it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;else&lt;/code&gt; arm carries no &lt;code&gt;-&amp;gt;&lt;/code&gt;.&lt;/strong&gt; The arrow separates a &lt;em&gt;pattern&lt;/em&gt; from what to do when it matches,
and &lt;code&gt;else&lt;/code&gt; is not a pattern — it is the fallback, and it takes its body the way an &lt;code&gt;if&lt;/code&gt;‘s &lt;code&gt;else&lt;/code&gt;
does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the &apos;else&apos; arm takes its body directly, with no &apos;-&amp;gt;&apos; — &apos;else&apos; names no pattern to separate one from
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two evaluation guarantees:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The scrutinee is evaluated exactly once.&lt;/strong&gt; A side-effecting scrutinee runs one time, and the arms
test against the resulting value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arms are tried top to bottom&lt;/strong&gt;, and the first whose pattern matches — and whose guard, if any,
holds — wins. That first-match rule is what makes a specific arm above a general one behave as
written.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-pattern-forms&quot;&gt;The pattern forms&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;pattern&lt;/th&gt;&lt;th&gt;example&lt;/th&gt;&lt;th&gt;matches&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;wildcard&lt;/td&gt;&lt;td&gt;&lt;code&gt;_&lt;/code&gt;&lt;/td&gt;&lt;td&gt;anything, binds nothing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;else&lt;/code&gt; arm&lt;/td&gt;&lt;td&gt;&lt;code&gt;else …&lt;/code&gt;&lt;/td&gt;&lt;td&gt;anything; the catch-all spelling in tail position&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;literal&lt;/td&gt;&lt;td&gt;&lt;code&gt;0&lt;/code&gt;, &lt;code&gt;&apos;a&apos;&lt;/code&gt;, &lt;code&gt;&amp;quot;hi&amp;quot;&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value equal to the literal&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;range&lt;/td&gt;&lt;td&gt;&lt;code&gt;3..7&lt;/code&gt;, &lt;code&gt;0..&amp;lt;10&lt;/code&gt;, &lt;code&gt;&apos;a&apos;..&apos;z&apos;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value in the range&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;bind&lt;/td&gt;&lt;td&gt;&lt;code&gt;r&lt;/code&gt;, &lt;code&gt;other&lt;/code&gt;&lt;/td&gt;&lt;td&gt;anything, and binds it to the name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;variant&lt;/td&gt;&lt;td&gt;&lt;code&gt;Circle(r)&lt;/code&gt;, &lt;code&gt;Empty&lt;/code&gt;, &lt;code&gt;Shape.Empty&lt;/code&gt;&lt;/td&gt;&lt;td&gt;that variant, binding each sub-pattern to a field&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;nested&lt;/td&gt;&lt;td&gt;&lt;code&gt;Wrap(Val(v))&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a variant whose payload itself matches a sub-pattern&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;struct, positional&lt;/td&gt;&lt;td&gt;&lt;code&gt;Point(a, b)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a struct, binding every field by position&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;struct, named&lt;/td&gt;&lt;td&gt;&lt;code&gt;Point{x, y}&lt;/code&gt;, &lt;code&gt;Point{x: a}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a struct, binding fields by name; unlisted fields unconstrained&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;tuple&lt;/td&gt;&lt;td&gt;&lt;code&gt;(a, b)&lt;/code&gt;, &lt;code&gt;(a, _)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a tuple, by position&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;named&lt;/td&gt;&lt;td&gt;&lt;code&gt;c @ Circle(r)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;what the sub-pattern matches, binding the &lt;strong&gt;whole&lt;/strong&gt; value too&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Literal patterns match any type with equality; range patterns need a contiguous order.&lt;/strong&gt; The two
gates are deliberately different. A literal pattern works on the integers, &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, and
&lt;code&gt;bool&lt;/code&gt; — matching a boolean by pattern is the natural spelling, and it is exhaustive with both arms
present and no catch-all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;word&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    b &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;  -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;word&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;word&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;yes no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A range pattern is restricted to the numeric types and &lt;code&gt;char&lt;/code&gt;, the types over which a contiguous
interval is meaningful. &lt;code&gt;string&lt;/code&gt; is deliberately excluded: &lt;code&gt;&amp;quot;a&amp;quot;..&amp;quot;z&amp;quot;&lt;/code&gt; has no useful meaning. A
&lt;code&gt;string&lt;/code&gt; is matched by literal or by binding.&lt;/p&gt;
&lt;h3 id=&quot;the-bare-name-rule&quot;&gt;The bare-name rule&lt;/h3&gt;
&lt;p&gt;A bare identifier in pattern position is a &lt;strong&gt;nullary-variant pattern&lt;/strong&gt; when it names a nullary
variant of the scrutinee’s enum, and a &lt;strong&gt;binding&lt;/strong&gt; otherwise.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;     -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;circle &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(r)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;empty circle 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A bare name that happens to be a &lt;strong&gt;data&lt;/strong&gt; variant is a diagnostic rather than a silent binding, which
closes the classic trap where a misspelled or payload-carrying variant quietly becomes a catch-all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;  -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;variant &apos;Circle&apos; carries data — match it as &apos;Circle(…)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rust and Swift reach the same resolution; sysl makes the data-variant case a hard error rather than a
lint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A qualified name is a pattern wherever a bare one is.&lt;/strong&gt; &lt;code&gt;Shape.Empty&lt;/code&gt; matches exactly as &lt;code&gt;Empty&lt;/code&gt;
does — the scrutinee’s type already settled which enum is meant. What a qualified name cannot be is a
&lt;em&gt;binding&lt;/em&gt;: no program declares a name with a dot in it, so one that resolves to neither a variant nor
a constant is a diagnostic rather than a new local.&lt;/p&gt;
&lt;h3 id=&quot;a-backticked-name-references-rather-than-binds&quot;&gt;A backticked name references rather than binds&lt;/h3&gt;
&lt;p&gt;The rule above resolves a bare name against a narrow set — the scrutinee’s nullary variants, then the
constants — and binds otherwise. Everything outside that set is therefore unreachable by a bare name:
a &lt;code&gt;val&lt;/code&gt;, a local, a parameter. Each is storage read while the program runs, so there is no value for
a compile-time pattern to compare against.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;a href=&quot;/reference/lexical/#quoted-identifiers&quot;&gt;backtick-quoted name&lt;/a&gt; says the test was meant&lt;/strong&gt;, and the arm
becomes an ordinary equality against whatever the name holds when the match runs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, limit: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;`limit`&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at the limit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;elsewhere&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;at the limit elsewhere
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written bare, &lt;code&gt;limit&lt;/code&gt; would bind — matching everything, and leaving the second arm unreachable. The
two spellings are the whole of the difference, and that is the point: a reader does not have to know
what is in scope to know which was meant.&lt;/p&gt;
&lt;p&gt;Three things follow. A quoted name that resolves to nothing is a diagnostic, not a new local. A
&lt;code&gt;const&lt;/code&gt; still folds to its literal, so quoting one changes nothing but the reader’s certainty. And a
runtime equality tells exhaustiveness nothing, so an arm written this way never discharges a case and
a catch-all stays required.&lt;/p&gt;
&lt;p&gt;It cannot stand at a binding, where there is no other arm to take when the value differs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (&lt;span class=&quot;hl-variable&quot;&gt;`limit`&lt;/span&gt;, b) = (&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a binding cannot test a value
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;alternatives-may-not-bind&quot;&gt;Alternatives may not bind&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;1 | 2 | 3&lt;/code&gt; is one arm matching any of three literals. An arm whose alternatives &lt;strong&gt;bind&lt;/strong&gt; is
rejected, because the body cannot know which alternative matched and therefore cannot know a
binding’s origin:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;One&lt;/span&gt;(v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Two&lt;/span&gt;(v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;One&lt;/span&gt;(v) | &lt;span class=&quot;hl-type&quot;&gt;Two&lt;/span&gt;(v) -&amp;gt; v

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;One&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;alternative patterns joined by &apos;|&apos; cannot bind a name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is stricter than Rust, which permits &lt;code&gt;A(x) | B(x)&lt;/code&gt; when every alternative binds the same names
at the same types. The rule here is simple and unambiguous: an arm with &lt;code&gt;|&lt;/code&gt; binds nothing.&lt;/p&gt;
&lt;h3 id=&quot;a-name-may-be-bound-twice-in-one-match-but-not-in-one-pattern&quot;&gt;A name may be bound twice in one match, but not in one pattern&lt;/h3&gt;
&lt;p&gt;Each arm is its own scope, so two arms may reuse a name freely. &lt;strong&gt;Inside one pattern a repeat is
refused&lt;/strong&gt;, because a pattern binds once however deeply it nests, and a second binding of the name
would quietly stand for a different part of the value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

p &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Point&lt;/span&gt;(v, v) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;v&apos; is bound twice in one pattern, and the second would quietly stand for a different part of the value — rename it, or compare the two in a guard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reading it stops is the tempting one: &lt;code&gt;Point(v, v)&lt;/code&gt; looks like a test that the two fields are
&lt;em&gt;equal&lt;/em&gt;, and it is not one — no pattern here compares two parts of the value. That is what a
&lt;a href=&quot;#guards&quot;&gt;guard&lt;/a&gt; is for. Scala, Rust, OCaml and Haskell all refuse it for the same reason.&lt;/p&gt;
&lt;h3 id=&quot;n-pat-matching-and-naming-at-once&quot;&gt;&lt;code&gt;n @ pat&lt;/code&gt; — matching and naming at once&lt;/h3&gt;
&lt;p&gt;A pattern that takes a value apart leaves the arm holding only the parts. Where the arm wants the
whole as well — to hand it on, to store it, to return it — &lt;code&gt;@&lt;/code&gt; binds it beside them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; r * r * &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w, h) -&amp;gt; w * h

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        c @ &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;circle r=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(r) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; area=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(c))
        other -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other, area=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(other))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;circle r=2 area=12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without it the arm has to choose: destructure and lose the value, or bind it and test the shape a
second time inside the body.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A binding is not a test&lt;/strong&gt;, so a named arm covers exactly what the sub-pattern covers — no &lt;code&gt;else&lt;/code&gt; is
owed that would not have been owed anyway, and none becomes unreachable. It nests, the part after
the &lt;code&gt;@&lt;/code&gt; being an ordinary pattern: &lt;code&gt;whole @ One(part @ Val(n))&lt;/code&gt; names three things at three depths.
It is also read at an &lt;a href=&quot;/reference/expressions/#is-a-pattern-where-a-condition-is-wanted&quot;&gt;&lt;code&gt;is&lt;/code&gt; test&lt;/a&gt; and at a &lt;a href=&quot;#a-pattern-at-a-binding&quot;&gt;binding&lt;/a&gt;, where
&lt;code&gt;var whole @ Point{x, y} = p&lt;/code&gt; gives the value a name alongside its fields.&lt;/p&gt;
&lt;p&gt;The name must be one a program could declare, so a qualified name is refused — what a binding
introduces is a local, and a name with a dot in it is not one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This &lt;code&gt;@&lt;/code&gt; and an &lt;a href=&quot;/reference/attributes/&quot;&gt;annotation’s&lt;/a&gt; are the same character and never compete.&lt;/strong&gt;
An annotation’s is a prefix, on its own line above a declaration; this one is infix, between a name
and a pattern. No declaration may stand where a pattern is read, so neither position is reachable by
the other form — the arrangement Scala has carried for twenty years.&lt;/p&gt;
&lt;h3 id=&quot;struct-patterns&quot;&gt;Struct patterns&lt;/h3&gt;
&lt;p&gt;A struct is destructured two ways, and they are a &lt;strong&gt;division of labour&lt;/strong&gt; rather than two spellings of
one thing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    p &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{x: a} -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x is &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;origin x is 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Positional (&lt;code&gt;Point(a, b)&lt;/code&gt;) is total.&lt;/strong&gt; It mirrors construction — sysl builds a struct positionally,
so tearing it apart positionally is symmetric — and it must name &lt;strong&gt;every&lt;/strong&gt; field, with &lt;code&gt;_&lt;/code&gt; to skip
one. Adding a field to the struct therefore turns each positional match into a checked arity error,
the way a new enum variant does. This is the &lt;em&gt;handle-everything&lt;/em&gt; tool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Named-field (&lt;code&gt;Point{x, y}&lt;/code&gt;) is partial by default.&lt;/strong&gt; It binds by field name, so it is
order-independent, supports renaming (&lt;code&gt;{x: a}&lt;/code&gt; binds field &lt;code&gt;x&lt;/code&gt; to &lt;code&gt;a&lt;/code&gt;), and matches a subset — any
field left unlisted is simply unconstrained. Adding a field never breaks a named pattern. This is the
&lt;em&gt;grab-what-I-need&lt;/em&gt; tool. There is no &lt;code&gt;..&lt;/code&gt; token, because positional already covers the total case.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Point(a, b)&lt;/code&gt; is textually identical to a variant pattern but not ambiguous: the compiler resolves it
by what &lt;code&gt;Point&lt;/code&gt; denotes. A struct type is a struct pattern; an enum variant is a variant pattern —
the same name resolution the bare-name rule uses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A tuple pattern is a struct pattern with the name left off.&lt;/strong&gt; &lt;code&gt;(a, b)&lt;/code&gt; binds both components,
&lt;code&gt;(a, _)&lt;/code&gt; binds one, and nesting works. A tuple has one shape, so a tuple pattern is irrefutable and
discharges its column for exhaustiveness exactly as a struct pattern does.&lt;/p&gt;
&lt;p&gt;Both forms compose with everything else: a struct pattern nests inside a variant pattern and vice
versa, and each bound sub-pattern is itself any pattern in this table.&lt;/p&gt;
&lt;h2 id=&quot;a-pattern-at-a-binding&quot;&gt;A pattern at a binding&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;match&lt;/code&gt; is not the only place a pattern stands. A &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt;
&lt;a href=&quot;/reference/declarations/#by-pattern-when-the-shape-matters&quot;&gt;binding&lt;/a&gt; takes one too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Counter&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;pair&lt;/span&gt;(c: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;) -&amp;gt; (&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    c.n = c.n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;once&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; ((p, q), r) = (&lt;span class=&quot;hl-function&quot;&gt;pair&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;c), &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p, q, r, c.n)

&lt;span class=&quot;hl-function&quot;&gt;shape&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; ((x, y), _) = ((&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;var&lt;/span&gt; (lo, hi) = (&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

    hi += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x, y, lo, hi)

&lt;span class=&quot;hl-function&quot;&gt;once&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;shape&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 3 1
3 4 0 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The value is evaluated exactly once&lt;/strong&gt;, which is the same guarantee a scrutinee gets and for the
same reason: it is analyzed into a temporary no program can name, and every part is a field read of
that. &lt;code&gt;pair()&lt;/code&gt; runs one time above however many names come out of it — the &lt;code&gt;1&lt;/code&gt; on the end of the
first line is the count.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;var&lt;/code&gt; pattern makes every name it binds assignable and a &lt;code&gt;val&lt;/code&gt; pattern makes each write-once,
exactly as the single-name forms do. A &lt;code&gt;_&lt;/code&gt; binds nothing and skips its part.&lt;/p&gt;
&lt;p&gt;That once-only rule is also what makes the obvious swap correct, since both parts of the right-hand
side are read before either name is bound:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;var&lt;/span&gt; (a, b) = (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (c, d) = (b, a)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b, c, d)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 2 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;only-an-irrefutable-pattern-may-stand-there&quot;&gt;Only an irrefutable pattern may stand there&lt;/h3&gt;
&lt;p&gt;A binding has &lt;strong&gt;no other arm to take&lt;/strong&gt;. So the patterns allowed at one are exactly those that cannot
fail — a tuple pattern, &lt;strong&gt;either struct form&lt;/strong&gt;, a name, a wildcard, and those nested inside one
another — and everything in the table above that is a &lt;em&gt;test&lt;/em&gt; is refused by name.&lt;/p&gt;
&lt;p&gt;A struct qualifies because it has exactly one shape, which is the same property that makes a tuple
pattern irrefutable, and both spellings of it stand here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    both: (&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{y, x} = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(a, b) = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{x: px}, k) = (&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;((lo, hi)) = &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;))

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x, y, a, b, px, k, lo, hi)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 4 5 6 7 9 10 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The two forms differ in what they must account for, and it is the difference they have in a
&lt;code&gt;match&lt;/code&gt;.&lt;/strong&gt; The named form may leave fields out, and an unlisted one simply binds nothing — there is
no exhaustiveness to discharge at a binding, so nothing has to stand in for it. The positional form
names every field, so a struct that grows one turns each positional binding into a checked to-do
rather than a binding that quietly goes on binding the same names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    z: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(x, y) = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;struct &apos;Point&apos; has 3 fields, but 2 sub-patterns were given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That &lt;code&gt;Name(…)&lt;/code&gt; is a struct pattern here at all is the ordinary resolution rule: the spelling reads as
a variant pattern until the value’s type settles it, exactly as it does in an arm.&lt;/p&gt;
&lt;p&gt;A literal is a test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b) = (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a binding cannot test a value — this pattern matches only some values, and a binding has no other arm to take when it does not match
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So is a range, and the diagnostic is the same one, because it is the same objection.&lt;/p&gt;
&lt;p&gt;A variant is a &lt;strong&gt;choice among shapes&lt;/strong&gt;, which is a different objection and gets its own words:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Shape&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(r), b) = (&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r, b)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a binding cannot choose among variants — this pattern matches one of several shapes, and a binding has no other arm to take when the value has another
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of those belongs in a &lt;code&gt;match&lt;/code&gt;, where the arm that does not match has somewhere to fall through
to.&lt;/p&gt;
&lt;h3 id=&quot;the-shape-has-to-line-up&quot;&gt;The shape has to line up&lt;/h3&gt;
&lt;p&gt;A tuple pattern is irrefutable &lt;em&gt;for the tuple it describes&lt;/em&gt;, so the arity is checked where it is
written rather than at run time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (a, b, c) = (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this pattern takes 3 parts, and a (int, int) has 2 parts to give it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Taking apart something that is not a tuple at all is refused in its own words, because the mistake is
a different one — there is no shape to disagree about:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (a, b) = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;one int is not something to take apart — only a tuple is
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a name may appear once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (a, a) = (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;a&apos; is named twice in one binding
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;guards&quot;&gt;Guards&lt;/h2&gt;
&lt;p&gt;An arm may carry an &lt;code&gt;if&lt;/code&gt; guard, evaluated &lt;strong&gt;after&lt;/strong&gt; its pattern matches.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;band&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;          -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;              &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;band&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;band&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;band&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;high low out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A guard runs only when its pattern has already matched&lt;/strong&gt;, never for an arm that was ruled out, so
a side-effecting guard fires exactly on the arms whose shape fits.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A failed guard falls through to a later overlapping arm.&lt;/strong&gt; The two &lt;code&gt;1..10&lt;/code&gt; arms above are the
first-match rule plus fallthrough, not a partition into disjoint cases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A guarded arm does not count toward exhaustiveness.&lt;/strong&gt; The compiler cannot prove a guard holds, so
a guarded arm never discharges a variant’s obligation — a &lt;code&gt;match&lt;/code&gt; covered &lt;em&gt;only&lt;/em&gt; by guarded arms
still needs a catch-all. This is Rust’s rule, and it is what keeps exhaustiveness a real guarantee
rather than a formality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;exhaustiveness&quot;&gt;Exhaustiveness&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;match&lt;/code&gt; on a data enum must cover every value or carry an unguarded catch-all&lt;/strong&gt;, and a gap names
what is missing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; r * r

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;match on &apos;Shape&apos; is not exhaustive; missing Rect (add an &apos;else&apos; arm)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the central payoff of a closed sum type: adding a variant turns every non-catch-all match on
it into a checked to-do list.&lt;/p&gt;
&lt;p&gt;Four rules decide what counts as covered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Coverage is about which values are guaranteed handled, not which tags appear&lt;/strong&gt;, and the arms answer
that together. &lt;code&gt;Some(Halt)&lt;/code&gt;, &lt;code&gt;Some(Push)&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt; cover an &lt;code&gt;Option[Op]&lt;/code&gt; between them even though
none of them covers a variant on its own — and &lt;code&gt;Some(0)&lt;/code&gt; alone does &lt;em&gt;not&lt;/em&gt; cover &lt;code&gt;Some&lt;/code&gt;, because a
&lt;code&gt;Some&lt;/code&gt; holding a non-zero value slips through.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is missing is named at the depth it is missing at.&lt;/strong&gt; A gap inside a payload reports as
&lt;code&gt;missing Some(Push)&lt;/code&gt; rather than as &lt;code&gt;missing Some&lt;/code&gt;, and a column no arm narrowed stays a &lt;code&gt;_&lt;/code&gt; standing
for all its values, rather than expanding into one line per combination behind it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A type is covered by listing its values only when it has a finite, known set of them&lt;/strong&gt; — an enum’s
variants, a struct’s single shape, &lt;code&gt;bool&lt;/code&gt;‘s two. Everything else is covered by a wildcard or a
binding and by nothing shorter, which is why &lt;code&gt;1 -&amp;gt; …&lt;/code&gt; and &lt;code&gt;2 -&amp;gt; …&lt;/code&gt; on an &lt;code&gt;int&lt;/code&gt; still need an &lt;code&gt;else&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A scalar match must be exhaustive only when it is used for a value.&lt;/strong&gt; In statement position a
non-exhaustive scalar match is fine — the unmatched case is a no-op. An &lt;strong&gt;enum&lt;/strong&gt; match is
exhaustive-checked in &lt;em&gt;both&lt;/em&gt; positions, because falling off the end of one has no defined result even
for effect. That asymmetry is what &lt;code&gt;is&lt;/code&gt; exists to relieve; see &lt;a href=&quot;/reference/expressions/&quot;&gt;expressions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A catch-all is a wildcard or a bind in tail position, carried by an unguarded arm. &lt;code&gt;else&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt; are
the same thing to the analyzer; &lt;code&gt;else&lt;/code&gt; is the conventional spelling in tail position, &lt;code&gt;_&lt;/code&gt; the one
that reads inside a &lt;code&gt;|&lt;/code&gt; or a nested pattern.&lt;/p&gt;
&lt;h2 id=&quot;what-a-match-is-worth&quot;&gt;What a match is worth&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A match used for a value takes the common type of its arms.&lt;/strong&gt; When every arm yields the same
non-unit type, that is the match’s type; a match whose arms only do things is &lt;code&gt;unit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An arm that does not finish constrains nothing.&lt;/strong&gt; An arm that aborts or returns has type &lt;code&gt;never&lt;/code&gt;,
so it is set aside before the others are compared:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(o: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    o &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(v) -&amp;gt; v
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;)) + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Exhaustiveness is unaffected — a diverging arm still has to be &lt;em&gt;reachable&lt;/em&gt; by a pattern that covers
something.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disagreeing arm types are a diagnostic, not a silent &lt;code&gt;unit&lt;/code&gt;.&lt;/strong&gt; When the arms yield different
non-unit types and nothing unifies them, the match is a type error reported at the match rather than
a quiet fallback that surfaces later as a confusing error at the use site.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;&amp;amp;T&lt;/code&gt; context reaches each arm, not the whole match.&lt;/strong&gt; Under a &lt;code&gt;&amp;amp;Point&lt;/code&gt; expectation, an arm
yielding a bound &lt;code&gt;&amp;amp;Point&lt;/code&gt; payload and an arm building a fresh &lt;code&gt;Point&lt;/code&gt; meet at &lt;code&gt;&amp;amp;Point&lt;/code&gt; — the value
arm is boxed on its own and the reference arm passes through untouched. Boxing the whole match
instead would fail, because an arm that is already &lt;code&gt;&amp;amp;Point&lt;/code&gt; cannot un-become a value.&lt;/p&gt;
&lt;h2 id=&quot;refcounts-survive-destructuring&quot;&gt;Refcounts survive destructuring&lt;/h2&gt;
&lt;p&gt;Pattern matching obeys the memory model with no special rule, and both obligations are exactly where
a hand-written tagged union in C leaks or double-frees.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Binding a &lt;code&gt;&amp;amp;T&lt;/code&gt; payload out of an enum retains it.&lt;/strong&gt; &lt;code&gt;Full(p) -&amp;gt; p&lt;/code&gt; hands the bound reference past
the frame of the enum it came from, so the payload is retained on bind and released once when the
binding dies — the extracted reference outlives the enum, and the count is exact.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A binding under a failed guard is released exactly once.&lt;/strong&gt; When &lt;code&gt;Full(p) if p.x &amp;gt; 100&lt;/code&gt; fails and
control falls through, the &lt;code&gt;p&lt;/code&gt; bound for the guard is released before the next arm is tried, with no
double free and no leak.&lt;/p&gt;
&lt;h2 id=&quot;matching-through-a-reference&quot;&gt;Matching through a reference&lt;/h2&gt;
&lt;p&gt;Selection auto-dereferences one level, but &lt;code&gt;match&lt;/code&gt; does not: matching a &lt;code&gt;&amp;amp;Enum&lt;/code&gt; or a &lt;code&gt;*Enum&lt;/code&gt; against
its variants is written &lt;strong&gt;&lt;code&gt;match *e&lt;/code&gt;&lt;/strong&gt; — the same explicit one-level dereference Go asks for on a
type switch.&lt;/p&gt;
&lt;p&gt;That keeps “am I matching the reference or the thing” a visible question, and it is the one place a
reference to an enum needs the &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Packages</title>
    <link href="https://sysl.sh/reference/packages/"/>
    <id>https://sysl.sh/reference/packages/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>package.hocon, dependencies on other people&apos;s code, version selection, and what a fetched package&apos;s modules are called here.</summary>
    <content type="html">&lt;p&gt;A project’s configuration and its list of dependencies are &lt;strong&gt;one file, &lt;code&gt;package.hocon&lt;/code&gt;, at the
project root&lt;/strong&gt;. It says who this package is, what machines it is built for, what those machines
provide, and what it depends on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The file is optional.&lt;/strong&gt; A single-file program has none, and gets the defaults: the project root is
the directory the compiler was given, the target is the machine it is running on, and that target
provides everything. &lt;code&gt;sysl run hello.sysl&lt;/code&gt; needs no ceremony.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;package {
  name    = &amp;quot;geom&amp;quot;
  version = &amp;quot;1.4.2&amp;quot;
}

targets {
  default = &amp;quot;aarch64-macos&amp;quot;
}

capabilities { heap = false }

requires { os = true }

dependencies {
  json  { git = &amp;quot;github.com/edadma/sysl-json&amp;quot;, version = &amp;quot;1.4.0&amp;quot; }
  regex { git = &amp;quot;github.com/edadma/sysl-regex&amp;quot;, version = &amp;quot;0.4.0&amp;quot;, mount = &amp;quot;re&amp;quot; }
  local { path = &amp;quot;../experiment&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-a-project-is-called&quot;&gt;What a project is called&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;package.name&lt;/code&gt; is what a directory project’s executable is called.&lt;/strong&gt; A directory is a project
because it holds &lt;code&gt;.sysl&lt;/code&gt; files, not because anybody said so, so a project has no identity of its own
unless this block gives it one. Without a name the output takes the directory’s:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;myproj/main.sysl        -&amp;gt;  myproj/myproj
myproj/package.hocon    -&amp;gt;  myproj/tool
  package { name = &amp;quot;tool&amp;quot; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Requiring the file was the other way to answer this, and it is deliberately not what happens: it
would give every project an identity and charge every project the ceremony, when a scratch directory
holding one &lt;code&gt;.sysl&lt;/code&gt; file is the cheapest thing in the toolchain and worth keeping cheap.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;file&lt;/strong&gt; project is outside this. &lt;code&gt;sysl build foo.sysl&lt;/code&gt; writes &lt;code&gt;foo&lt;/code&gt; beside the caller, whatever a
&lt;code&gt;package.hocon&lt;/code&gt; sitting in the same directory says — the name came from the path you typed, and a
config quietly moving the executable would be a worse surprise than anything it fixed.&lt;/p&gt;
&lt;p&gt;The name reaches the filesystem, so it has to be a single path segment. &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;..&lt;/code&gt;, anything holding a
separator, and the empty string are refused when the file is read, rather than being sanitized into
something that would build a differently-named executable without saying so.&lt;/p&gt;
&lt;h2 id=&quot;capabilities&quot;&gt;Capabilities&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Whether the machine has a heap, an operating system or POSIX is a project engineering
decision, and this is where it is stated.&lt;/strong&gt; The compiler’s registry of targets deliberately carries no
capabilities: a target’s ABI is measured and its capabilities are policy, so the ABI is the registry’s
and the policy is yours.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;capabilities { heap = false }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the project’s own statement and it applies to &lt;strong&gt;every&lt;/strong&gt; target the project builds for. A
capability the file does not mention is provided — the prior is that a machine can do everything,
which is what every build had before there was a file to say otherwise, so what a config records is
what a machine &lt;em&gt;cannot&lt;/em&gt; do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A target block layers over it, per capability, for the one machine that differs:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;capabilities { heap = false }

targets {
  default = &amp;quot;thumbv7em-freestanding&amp;quot;
  aarch64-macos { capabilities { heap = true } }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only the capabilities a target block names are overridden; everything else still comes from the
project’s own block. Writing the statement only inside target blocks — which was once the only place
it could go — keys it to a machine’s name, so a project building for three targets says it three
times and cannot say it at all for a target the registry already has without a block that reads as
redefining the machine.&lt;/p&gt;
&lt;h3 id=&quot;capabilities-against-requires&quot;&gt;&lt;code&gt;capabilities&lt;/code&gt; against &lt;code&gt;requires&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The two blocks point in opposite directions and neither substitutes for the other:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;block&lt;/th&gt;&lt;th&gt;says&lt;/th&gt;&lt;th&gt;about&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;capabilities&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this machine &lt;strong&gt;has&lt;/strong&gt; these&lt;/td&gt;&lt;td&gt;the target being built for&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;requires&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this package &lt;strong&gt;cannot be built without&lt;/strong&gt; these&lt;/td&gt;&lt;td&gt;the host it needs&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;requires { heap = true }&lt;/code&gt; buys one clean error when the package is built for a machine without one,
instead of an error at every &lt;code&gt;&amp;amp;T&lt;/code&gt;. A &lt;code&gt;false&lt;/code&gt; there says nothing — a package does not need a facility
&lt;em&gt;not&lt;/em&gt; to exist — and is refused rather than quietly dropped, naming the two places that do mean it.&lt;/p&gt;
&lt;h3 id=&quot;heap-and-the-module-s-own-no-alloc&quot;&gt;&lt;code&gt;heap&lt;/code&gt;, and the module’s own &lt;code&gt;@no_alloc&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The capability is &lt;code&gt;heap&lt;/code&gt;, a &lt;strong&gt;facility&lt;/strong&gt; the machine either has or has not. A module’s promise that
its own code does not use one is spelled &lt;a href=&quot;/reference/modules/#capabilities-are-a-module-property&quot;&gt;&lt;code&gt;@no_alloc&lt;/code&gt;&lt;/a&gt;,
a &lt;strong&gt;conduct&lt;/strong&gt;. They are two words because they are two statements, and each is refused where the other
belongs.&lt;/p&gt;
&lt;p&gt;For compatibility with packages already published, &lt;code&gt;alloc&lt;/code&gt; is still accepted in this file and read as
&lt;code&gt;heap&lt;/code&gt;. Write &lt;code&gt;heap&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;one-heap-and-the-package-that-names-it&quot;&gt;One heap, and the package that names it&lt;/h2&gt;
&lt;p&gt;Having a heap is one question; &lt;strong&gt;which&lt;/strong&gt; heap is another. A program allocates through one pair of C
functions, and a package that brings its own says which:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;allocator {
  alloc = &amp;quot;pvPortMalloc&amp;quot;
  free  = &amp;quot;vPortFree&amp;quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Saying it settles the pair for the whole program, not for the package that said it. Every allocation
the compilation emits calls that pair — a string concatenation, a &lt;code&gt;Buf&lt;/code&gt; growing, a box the reference
counter builds — and every release gives the storage back to it. Declare nothing anywhere and the pair
is libc’s &lt;code&gt;malloc&lt;/code&gt; and &lt;code&gt;free&lt;/code&gt;, which is what a program depending on nothing that says otherwise gets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is the program’s pair rather than the package’s, because there is one heap.&lt;/strong&gt; Ownership is
settled by reference count, so which code frees a thing is not knowable when a package is written: a
&lt;code&gt;Buf&lt;/code&gt; filled inside an RTOS package and handed back is freed by the application, and one built by the
application and passed in is freed by the package. Two allocators would make every one of those
crossings a heap boundary that no signature marks.&lt;/p&gt;
&lt;p&gt;A package declares it rather than a target, and that is deliberate. The obvious alternative is a
target fact — the machine knows it is a Cortex-M — and it does not survive contact: &lt;code&gt;thumbv7em&lt;/code&gt; does
not imply FreeRTOS, two RTOSes on one chip want different pairs, and a bare-metal program on that chip
wants libc’s. What knows the answer is the package carrying the heap.&lt;/p&gt;
&lt;h3 id=&quot;two-that-disagree-and-two-that-agree&quot;&gt;Two that disagree, and two that agree&lt;/h3&gt;
&lt;p&gt;Two packages naming different pairs is refused when the dependency graph is resolved:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;two packages name different allocators, and a program has one heap — &apos;freertos&apos; names
pvPortMalloc / vPortFree; &apos;arena&apos; names arena_alloc / arena_free. Drop one of the
declarations, or depend on only one of them
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Refused there rather than at the link, because the link will not refuse it: both symbols resolve, the
program builds, and it hands one allocator’s storage to the other’s &lt;code&gt;free&lt;/code&gt; at run time.&lt;/p&gt;
&lt;p&gt;Two packages naming the &lt;strong&gt;same&lt;/strong&gt; pair unify to it. That is the ordinary case rather than a coincidence
— a kernel package and a driver built on it both name the kernel’s allocator, and neither has to know
whether the other did.&lt;/p&gt;
&lt;p&gt;Both halves are said or neither is; half a pair is refused, since storage taken from one heap and
given back to another is the one outcome worse than not building. The project’s own manifest may
declare a pair too, which covers an application with its own arena and no dependency that has one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Whichever road the package arrived by.&lt;/strong&gt; A package named in &lt;code&gt;dependencies&lt;/code&gt; and the same package
handed over as a &lt;code&gt;--lib&lt;/code&gt; source root declare the same thing and settle the same question — this is a
property of the package, not of the flag that reached it.&lt;/p&gt;
&lt;h3 id=&quot;a-library-artifact-is-built-for-one-allocator&quot;&gt;A library artifact is built for one allocator&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;.syslib&lt;/code&gt;‘s object half is compiled code, and it calls the pair by name. So an artifact is built for
one allocator exactly as it is built for one machine, and a program that allocates another way refuses
it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;geom.syslib allocates through malloc / free and this program allocates through
pvPortMalloc / vPortFree — a program has one heap, so a library compiled against
another cannot be linked into it. Rebuild the library against this one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That refusal is sharper than the one for a mismatched target, and deliberately so: an artifact for the
wrong machine is eventually refused by a linker that cannot read the object at all, while an artifact
for the wrong allocator is refused by nothing. Recording the name is the only place it can be caught.&lt;/p&gt;
&lt;p&gt;The standard module is under the same rule and needs nothing done about it — its cache is keyed by the
pair among the other things it is keyed by, so a program that names an allocator gets a standard
module built for that allocator, built on demand and announced on stderr.&lt;/p&gt;
&lt;h3 id=&quot;what-it-does-not-do&quot;&gt;What it does not do&lt;/h3&gt;
&lt;p&gt;Naming the pair says which functions the program uses. It says nothing about &lt;strong&gt;where&lt;/strong&gt; the program may
use them, and that distinction matters on a real RTOS: &lt;code&gt;pvPortMalloc&lt;/code&gt; suspends the scheduler and is
not usable from an interrupt handler, while sysl allocates implicitly — a string operation, a growing
buffer, a box. Code reachable from a handler is the caller’s to bound, and &lt;code&gt;@no_alloc&lt;/code&gt; is how it is
bounded.&lt;/p&gt;
&lt;h2 id=&quot;headers-a-package-needs-and-does-not-carry&quot;&gt;Headers a package needs and does not carry&lt;/h2&gt;
&lt;p&gt;A capability is answered by the target, and there is nothing for anybody to go and do. &lt;strong&gt;A header is
answered by a path on a machine the package has never seen&lt;/strong&gt;, and that is the other thing a package
may need of its environment.&lt;/p&gt;
&lt;p&gt;Most bindings carry the C they include — sqlite3, qcbor, monocypher and termbox2 all vendor their
library’s source, so a relative include resolves and no flag is involved. A package binding something
the &lt;em&gt;consumer’s&lt;/em&gt; build system owns cannot do that. &lt;code&gt;pico2&lt;/code&gt; is the case: lwIP’s headers live in an
81 MB pico-sdk clone that only the consuming project has, and vendoring a copy would be vendoring the
thing the package exists not to reimplement.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;requires {
  headers { lwip = &amp;quot;lwIP&apos;s headers — the pico-sdk carries them at lib/lwip/src/include&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The consumer says where they are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl build . --include-path lwip=$PICO_SDK_PATH/lib/lwip/src/include
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The package names the requirement and the driver supplies the path.&lt;/strong&gt; That is the same split as
&lt;a href=&quot;/reference/ffi/#where-the-library-is-where-its-headers-are-and-what-they-are-configured-with&quot;&gt;&lt;code&gt;@link(&amp;quot;png&amp;quot;)&lt;/code&gt; and &lt;code&gt;--link-path&lt;/code&gt;&lt;/a&gt;:
a path in a committed file would be one machine’s directory layout published as though it were a
property of the package, and an environment variable read out of the consumer’s shell would be a
build that works for whoever wrote it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The value is the reason, not a path.&lt;/strong&gt; It is prose for a person — what the headers are and where
they come from — quoted back at whoever has to find them. A name on its own would report that
something called &lt;code&gt;lwip&lt;/code&gt; is missing and leave the reader to work out what that is.&lt;/p&gt;
&lt;h3 id=&quot;what-it-buys-is-the-refusal&quot;&gt;What it buys is the refusal&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;--include-path&lt;/code&gt; always worked, and a consumer who passed it always built. What did not exist was any
way for the &lt;em&gt;package&lt;/em&gt; to say it needed one, so a build without the flag failed inside a C compiler
that names the header and knows nothing about sysl, the package, or the flag:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fatal error: &apos;lwip/tcp.h&apos; file not found
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the build stops before clang runs, naming all three:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;github.com/sysl-lang/pico2 needs the &apos;lwip&apos; headers and nothing supplied them — lwIP&apos;s headers,
the pico-sdk carries them at lib/lwip/src/include. Say where they are with
&apos;--include-path lwip=&amp;lt;dir&amp;gt;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;bare&lt;/strong&gt; &lt;code&gt;--include-path&lt;/code&gt; is not an answer, deliberately. The check is about what a build says it
has rather than what it might happen to find; reading a bare path as an answer would let a consumer
satisfy the requirement by accident and never learn they had.&lt;/p&gt;
&lt;p&gt;It is asked only where C is actually compiled, so &lt;code&gt;emit-llvm&lt;/code&gt; and &lt;code&gt;prove&lt;/code&gt; are not held up by a path
they would never open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;build-lib&lt;/code&gt; compiles C, so it is asked too — and it is asked for its own manifest and nothing
else.&lt;/strong&gt; That is the narrowest scope of any command here, and it follows from the same rule rather
than being an exception to it: &lt;code&gt;build-lib&lt;/code&gt; compiles the C of the tree it was handed and no other, so
a &lt;code&gt;--lib&lt;/code&gt; source root’s declaration is not charged to a library built against it. That build never
opens the root’s header, and the root is asked for it when the root is built itself.&lt;/p&gt;
&lt;p&gt;This is the road a package is &lt;em&gt;packaged&lt;/em&gt; by, so it is the one that matters most to whoever is
publishing one — and it was the last to be asked. Until it was, building a declaring package into an
artifact answered with &lt;code&gt;fatal error: &apos;lwip/tcp.h&apos; file not found&lt;/code&gt; out of the package’s own shim, and,
worse, a &lt;strong&gt;bare&lt;/strong&gt; &lt;code&gt;--include-path&lt;/code&gt; satisfied the requirement in effect, because nothing was asking.
A requirement that can be met by accident on the machine that built the artifact and nowhere else is
exactly what the paragraph above exists to prevent.&lt;/p&gt;
&lt;h3 id=&quot;it-is-asked-whichever-way-the-package-arrived&quot;&gt;It is asked whichever way the package arrived&lt;/h3&gt;
&lt;p&gt;A package reaches a build by three roads, and the declaration is worth the same on each — though they
do not all need the same thing from it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;how the package arrived&lt;/th&gt;&lt;th&gt;what happens&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;named in &lt;code&gt;dependencies&lt;/code&gt;&lt;/td&gt;&lt;td&gt;its manifest comes with the graph, and the requirement is asked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;handed over as a &lt;code&gt;.syslib&lt;/code&gt;&lt;/td&gt;&lt;td&gt;nothing is asked, because nothing is needed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;given as a &lt;code&gt;--lib&lt;/code&gt; source root&lt;/td&gt;&lt;td&gt;its manifest is read for this, and the requirement is asked&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The artifact needs no header at all&lt;/strong&gt;, which is worth knowing before going to look for a flag to
pass. &lt;code&gt;build-lib&lt;/code&gt; measures a &lt;code&gt;c const&lt;/code&gt; and a &lt;code&gt;c type&lt;/code&gt; while it builds and stores the &lt;strong&gt;answer&lt;/strong&gt; —
the value, and the integer a typedef turned out to be — rather than the C that produced it, so a
consumer of a &lt;code&gt;.syslib&lt;/code&gt; needs neither a clang nor the library’s headers. There is nothing left to
require.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The header requirements, the allocator and the &lt;code&gt;dependencies&lt;/code&gt; are read from a &lt;code&gt;--lib&lt;/code&gt; root.&lt;/strong&gt; That
flag names a &lt;em&gt;source root&lt;/em&gt;, which need not be a package at all, and one that is not has nothing to
declare — so a root with no &lt;code&gt;package.hocon&lt;/code&gt; goes on building exactly as it always did.&lt;/p&gt;
&lt;p&gt;All three are read for one reason: each is a property of the &lt;em&gt;package&lt;/em&gt; rather than of the road the
package arrived by. A directory handed over with &lt;code&gt;--lib&lt;/code&gt; is the same package as one named by a
coordinate, so it brings its heap, its header requirements and what it is written against either way.&lt;/p&gt;
&lt;p&gt;The allocator used to be read only from a coordinate, and the two roads then disagreed &lt;strong&gt;in silence&lt;/strong&gt;:
the package’s own objects came out of its heap and every string, &lt;code&gt;Buf&lt;/code&gt; and box in the same program out
of libc’s, with nothing said at any point. A silent mixed heap is worse than a rule somebody has to
know, which is what decided it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;dependencies&lt;/code&gt; were the last of the three. Read only by coordinate, the same directory gave a
build the package’s sysl and nothing it was written against, and what came back was a page of
unresolved names pointing into a package you did not write — naming neither the missing dependency nor
a flag. They are fetched now, into the &lt;strong&gt;same&lt;/strong&gt; graph the project’s own go through, so version
selection sees every claim at once and a package two roots share is one copy at one version. What a
root’s manifest binds is reachable from your own files as well, which is no more true of a
dependency’s name than it always was of the root’s own modules.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;build-lib&lt;/code&gt; is the one command that refuses them instead, and that is not an inconsistency: it
compiles one tree into an artifact for one machine and does not reach the network, so it has nothing
to fetch &lt;strong&gt;with&lt;/strong&gt;. It says so, and names &lt;code&gt;--lib&lt;/code&gt; as what to write instead.&lt;/p&gt;
&lt;p&gt;What is still not read is the rest of the manifest. A root’s capabilities are the program’s to state,
and they have none of the one-answer-per-program character that makes the allocator settle for
everybody.&lt;/p&gt;
&lt;h2 id=&quot;a-library-the-machine-already-has-found-by-asking-it&quot;&gt;A library the machine already has, found by asking it&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;headers&lt;/code&gt; requirement puts the path in your hands, which is right when the headers belong to your
build — lwIP’s live in your pico-sdk clone and nothing else could know where that is. &lt;strong&gt;It is more
than is needed for an ordinary installed library&lt;/strong&gt;, because most of them answer the question
themselves. &lt;code&gt;pkg-config&lt;/code&gt; is how: a &lt;code&gt;.pc&lt;/code&gt; file installed beside the library says where its headers are
and what its link line is, on this machine.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;requires {
  pkg_config { sdl3 = &amp;quot;SDL3 — brew install sdl3, or Debian&apos;s libsdl3-dev&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;sysl run .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole command. Before this, the same program wanted the layout of your machine typed out —
and typed out correctly, which for the box2d demo meant knowing that cairo’s headers are in
&lt;code&gt;include/cairo&lt;/code&gt; while SDL3’s want the directory &lt;em&gt;above&lt;/em&gt; &lt;code&gt;SDL3&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl run . --link-path /opt/homebrew/lib \
           --include-path cairo=/opt/homebrew/include/cairo \
           --include-path sdl3=/opt/homebrew/include
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The split is the same one as before: the package names the requirement and something else supplies
the path.&lt;/strong&gt; What changed is who that something else is — the machine, rather than a person copying its
layout onto a command line. Nothing the package wrote is a path, and no code the package supplied is
run; the compiler asks a well-known tool a question, exactly as it already asks clang what a
&lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c const&lt;/code&gt;&lt;/a&gt; measures to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One declaration answers both halves.&lt;/strong&gt; A package binding an installed library needs its headers to
compile &lt;em&gt;and&lt;/em&gt; its library to link, and having one of those is not a build. &lt;code&gt;--cflags&lt;/code&gt; feeds every C
compilation in the tree and &lt;code&gt;--libs&lt;/code&gt; feeds the link line — including the &lt;code&gt;-Wl,-rpath&lt;/code&gt; that decides
whether a dynamically-linked program finds its library at &lt;strong&gt;run&lt;/strong&gt; time, which is the part a
hand-written &lt;code&gt;--link-path&lt;/code&gt; quietly leaves out.&lt;/p&gt;
&lt;h3 id=&quot;the-name-is-the-one-pkg-config-files-it-under&quot;&gt;The name is the one pkg-config files it under&lt;/h3&gt;
&lt;p&gt;It cannot be derived, and the two things it might have been derived from are both wrong. The &lt;code&gt;@link&lt;/code&gt;
directive is one: the sdl3 package writes &lt;code&gt;@link(&amp;quot;SDL3&amp;quot;)&lt;/code&gt; and the module is &lt;code&gt;sdl3&lt;/code&gt;, because &lt;code&gt;-lSDL3&lt;/code&gt;
and &lt;code&gt;sdl3.pc&lt;/code&gt; are two naming conventions that happen to share a word. A &lt;code&gt;headers&lt;/code&gt; requirement’s name is
the other, and worse: a name that happened to match some &lt;code&gt;.pc&lt;/code&gt; file on your machine would satisfy a
requirement nobody answered — met by accident on the machine that built it and nowhere else.&lt;/p&gt;
&lt;h3 id=&quot;what-happens-when-it-cannot-be-answered&quot;&gt;What happens when it cannot be answered&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Your own flags win and stop the probe.&lt;/strong&gt; &lt;code&gt;--include-path &amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt; answers this exactly as it
answers a header requirement, so a hermetic build, a hand-built prefix or a machine with a broken &lt;code&gt;.pc&lt;/code&gt;
is never at the mercy of what happens to be installed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A build for another machine is not asked at all.&lt;/strong&gt; &lt;code&gt;pkg-config&lt;/code&gt; answers for the machine it runs on,
and a cross build’s headers and library are the target’s. A freestanding program compiled against your
laptop’s &lt;code&gt;/opt/homebrew&lt;/code&gt; would link and be wrong somewhere you cannot see it, so a target that is not
this machine is refused rather than answered:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;this project needs the &apos;sdl3&apos; library and this is a build for &apos;thumbv7m-freestanding&apos; rather than
for this machine, so there is nothing to ask where it is — SDL3 — brew install sdl3. Say where it
is with &apos;--include-path sdl3=&amp;lt;dir&amp;gt;&apos; and &apos;--link-path &amp;lt;dir&amp;gt;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A machine without &lt;code&gt;pkg-config&lt;/code&gt; is exactly where it was before&lt;/strong&gt;, with the refusal the previous
section describes plus a sentence naming what was looked for. The two failures are told apart, because
they send you to different places: &lt;code&gt;pkg-config&lt;/code&gt; missing is one install away and says nothing about the
library, where a &lt;code&gt;pkg-config&lt;/code&gt; that does not know the module means the library itself is not there.&lt;/p&gt;
&lt;p&gt;macOS ships no &lt;code&gt;pkg-config&lt;/code&gt; and the libraries do not bring one — &lt;code&gt;brew deps cairo&lt;/code&gt; lists fifteen
packages and it is not among them — so &lt;code&gt;brew install sysl&lt;/code&gt; installs it as a dependency of the compiler.&lt;/p&gt;
&lt;h2 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h2&gt;
&lt;p&gt;A dependency is &lt;strong&gt;a git repository and a version&lt;/strong&gt;. There is no registry, no account to create, and
no name to reserve.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;dependencies {
  json { git = &amp;quot;github.com/edadma/sysl-json&amp;quot;, version = &amp;quot;1.4.0&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The coordinate is cloned over HTTPS and the tag &lt;code&gt;v1.4.0&lt;/code&gt; is what gets read. A &lt;code&gt;path&lt;/code&gt; dependency names
a directory instead, for a package being developed alongside its consumer:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;dependencies {
  helper { path = &amp;quot;../helper&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sysl build&lt;/code&gt; fetches whatever the machine has not got, so adding a dependency is an edit to this file
and nothing else. Fetched packages are cached under the machine’s cache directory and shared by every
project on it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A coordinate is identity, not a URL.&lt;/strong&gt; &lt;code&gt;https://&lt;/code&gt; on the front is refused rather than stripped:
the coordinate is what a package’s module names are derived from, so two spellings of one package
would link as two incompatible copies of it.&lt;/p&gt;
&lt;h3 id=&quot;the-major-version-rides-in-the-coordinate&quot;&gt;The major version rides in the coordinate&lt;/h3&gt;
&lt;p&gt;From the second major version on, a breaking change makes a &lt;strong&gt;new coordinate&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;dependencies {
  json { git = &amp;quot;github.com/edadma/sysl-json/v2&amp;quot;, version = &amp;quot;2.1.0&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A module’s name is part of every symbol it emits, so two versions of a module named &lt;code&gt;json&lt;/code&gt; would emit
the same symbol names for different code. One version per module is where the linker puts things
whether or not anyone plans for it, and &lt;code&gt;/v2&lt;/code&gt; is what planning for it looks like. &lt;code&gt;0.x&lt;/code&gt; and &lt;code&gt;1.x&lt;/code&gt;
ride in the bare path.&lt;/p&gt;
&lt;h3 id=&quot;which-version-you-get&quot;&gt;Which version you get&lt;/h3&gt;
&lt;p&gt;The version chosen for a package is &lt;strong&gt;the highest minimum anybody asked for&lt;/strong&gt; — not the newest that
exists:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;your project     depends on json 2.1.0
       json 2.1.0 depends on buf  1.2.0
       text 3.0.0 depends on buf  1.4.0
                                  ------
                       buf resolves to 1.4.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things follow from that, and they are the reason for it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Adding a dependency cannot silently upgrade an unrelated one.&lt;/strong&gt; The only versions in play are
ones some manifest names.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Builds are reproducible without a lockfile&lt;/strong&gt;, because the selection is a pure function of the
manifests.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upgrading is an edit.&lt;/strong&gt; Nothing quietly walks everything forward; you raise a minimum here and
the graph is recomputed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The cost is the honest one: you do not automatically get the newest patch release.&lt;/p&gt;
&lt;h2 id=&quot;what-a-dependency-s-modules-are-called&quot;&gt;What a dependency’s modules are called&lt;/h2&gt;
&lt;p&gt;A package is a tree of modules, and &lt;strong&gt;its modules come in under their own names&lt;/strong&gt;. A module is a
directory of source files, so a package holding &lt;code&gt;sqlite/&lt;/code&gt; is reached exactly as its own documentation
shows it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sqlite.open(&amp;quot;db.sqlite&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The name is the &lt;em&gt;module’s&lt;/em&gt;, not the package’s — sqlite3’s package is called &lt;code&gt;sqlite3&lt;/code&gt; and its module
is &lt;code&gt;sqlite&lt;/code&gt;, and reaching the second does not mean saying the first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A name is a module path, not a first segment.&lt;/strong&gt; Every package published under &lt;code&gt;sysl-lang&lt;/code&gt; puts its
source under a reverse-DNS prefix, so what it offers is a dotted path:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;sh/sysl/table/table.sysl       →  sh.sysl.table
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sh/&lt;/code&gt; and &lt;code&gt;sh/sysl/&lt;/code&gt; hold no source, so neither is a module and neither is a name that package
offers. Two packages laid out this way therefore do not collide, which is the point of the
convention: a project may depend on &lt;code&gt;sqlite3&lt;/code&gt;, &lt;code&gt;linenoise&lt;/code&gt; and &lt;code&gt;table&lt;/code&gt; at once and import all three
under the names their own documentation shows.&lt;/p&gt;
&lt;p&gt;A binding covers the module it names and everything below it, so &lt;code&gt;sh.sysl.table.Style&lt;/code&gt; reaches the
same package and keeps its tail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two packages cannot quietly share a name.&lt;/strong&gt; If two dependencies both offer a &lt;code&gt;json&lt;/code&gt;, or one offers
a &lt;code&gt;json&lt;/code&gt; and your own project has a &lt;code&gt;json/&lt;/code&gt; directory of source, the build stops and says so rather
than picking one. So does one offering a path &lt;em&gt;inside&lt;/em&gt; another’s — a package offering &lt;code&gt;sh.sysl&lt;/code&gt; and
one offering &lt;code&gt;sh.sysl.table&lt;/code&gt; share no name, but an import of &lt;code&gt;sh.sysl.table&lt;/code&gt; could be read as either,
and resolving it to the longer would be a rule nobody wrote down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“Your own modules” includes every &lt;code&gt;--lib&lt;/code&gt; source root&lt;/strong&gt;, since a root’s modules are filed under your
project’s names rather than under a prefix of their own. So a root that declares a dependency offering
a name the root itself declares is refused in the same words, and the message names the root as you
gave it. Without that, the root’s own module answered, its dependency’s was unreachable, and the build
was green — the silent winner the whole rule exists to refuse.&lt;/p&gt;
&lt;p&gt;Write a &lt;code&gt;mount&lt;/code&gt; to say what one of them is called here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-hocon&quot;&gt;dependencies {
  theirs { git = &amp;quot;github.com/edadma/sysl-json&amp;quot;, version = &amp;quot;1.4.0&amp;quot;, mount = &amp;quot;ejson&amp;quot; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which hangs that whole package under one segment, so its &lt;code&gt;json&lt;/code&gt; is &lt;code&gt;ejson.json&lt;/code&gt; and your own &lt;code&gt;json&lt;/code&gt;
is untouched. A mount is yours alone: another project may mount the same package differently, and
both still link one copy of it.&lt;/p&gt;
&lt;h2 id=&quot;sysl-sum&quot;&gt;&lt;code&gt;sysl.sum&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sysl.sum&lt;/code&gt; sits beside &lt;code&gt;package.hocon&lt;/code&gt; and &lt;strong&gt;should be committed&lt;/strong&gt;. It records a content hash for
each package and version the project resolved, and a fetch whose content does not match is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;github.com/edadma/sysl-json v1.4.0 sha256:6f1b…
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What it protects against is the class of change a version number cannot describe — a tag moved to
point at different commits, a repository rewritten, a mirror serving something other than what the
author published. In all three the version number is exactly what it was.&lt;/p&gt;
&lt;p&gt;It is &lt;strong&gt;not a lockfile&lt;/strong&gt;: version selection is already a function of the manifests, so there is
nothing to record about which versions were chosen. The first time a package is seen it is trusted
and recorded; reviewing the line that appears is the part a person does. A &lt;code&gt;path&lt;/code&gt; dependency gets no
entry, because a directory beside you is expected to change.&lt;/p&gt;
&lt;h2 id=&quot;no-build-scripts-ever&quot;&gt;No build scripts, ever&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A package cannot run code at build time.&lt;/strong&gt; Not a hook, not a script, not a plugin. &lt;code&gt;sysl add&lt;/code&gt; and
&lt;code&gt;sysl build&lt;/code&gt; read and write files and run nothing.&lt;/p&gt;
&lt;p&gt;Most of what other ecosystems need build scripts for is compiling vendored C, and sysl already
compiles a library’s C declaratively — the linker inputs a package needs are &lt;code&gt;@link&lt;/code&gt; attributes in
its source, not a program that computes them. What that buys is most of the supply-chain story: a
package that cannot execute during installation cannot exfiltrate anything during installation.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Modules and the library</title>
    <link href="https://sysl.sh/tour/modules/"/>
    <id>https://sysl.sh/tour/modules/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A module is a directory, an import only shortens a name you could always write in full, and the standard library is one auto-imported module with ten submodules under it.</summary>
    <content type="html">&lt;p&gt;Every program on this site so far has been one file with no header, and that is not a special form —
it is a module that happens to be unnamed. This chapter is what happens when there is more than one.&lt;/p&gt;
&lt;h2 id=&quot;a-module-is-a-directory&quot;&gt;A module is a directory&lt;/h2&gt;
&lt;p&gt;The files under &lt;code&gt;oskit/arch/&lt;/code&gt; make up the module &lt;code&gt;oskit.arch&lt;/code&gt;; the files under &lt;code&gt;std/fs/&lt;/code&gt; make up
&lt;code&gt;std.fs&lt;/code&gt;. Every declaration in every file of the directory is a member of the one module, so
splitting a growing module into more files adds no new module and changes no import.&lt;/p&gt;
&lt;p&gt;Each file states which module it contributes to, and the compiler checks the name against where the
file sits:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch

&lt;span class=&quot;hl-function&quot;&gt;halt&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;halted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is Scala’s &lt;code&gt;package&lt;/code&gt; and Go’s directory-package, and it pays off directly for the target: an OS
subsystem &lt;em&gt;is&lt;/em&gt; a directory — an arch layer, a server, a driver — so the module is the subsystem, and
the subsystem is the unit an importer depends on.&lt;/p&gt;
&lt;p&gt;A file with no header at all is in the &lt;strong&gt;anonymous root module&lt;/strong&gt;, whose name is the empty path.
Nothing can name it, so its declarations are visible to its own files and to nothing else — which is
the right way round for the place a program starts, and it is why a one-file program’s names sit
exactly where they always did.&lt;/p&gt;
&lt;h2 id=&quot;where-a-program-starts&quot;&gt;Where a program starts&lt;/h2&gt;
&lt;p&gt;A top-level &lt;em&gt;statement&lt;/em&gt; is not a declaration. A declaration is hoisted and belongs to the module as a
whole; a statement runs, and running happens in an order — so &lt;strong&gt;one file of a program carries the
statements it runs&lt;/strong&gt;, and a second that carries any is an error naming both.&lt;/p&gt;
&lt;p&gt;That file is the program’s &lt;strong&gt;entry file&lt;/strong&gt;, and its top level is a &lt;strong&gt;body&lt;/strong&gt;: a &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt; there is
a local initialized where it stands, and a function there reads the bindings above it.&lt;/p&gt;
&lt;p&gt;A program may instead declare &lt;code&gt;main&lt;/code&gt;, which is the other way of writing the place a program starts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the work runs here, with&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, args.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the work runs here, with 1 argument
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A program starts in one place&lt;/strong&gt;, so it writes one or the other and never both. What &lt;code&gt;main&lt;/code&gt; gets at
that a statement cannot is &lt;strong&gt;the arguments&lt;/strong&gt;: a statement has nowhere to receive them, because it is
not a call and has no parameter list.&lt;/p&gt;
&lt;p&gt;A program in which no file carries a statement is a complete program that does nothing. That is what
a tree of pure declarations compiles to, which is what it should compile to — a library is not an
error.&lt;/p&gt;
&lt;h2 id=&quot;visibility&quot;&gt;Visibility&lt;/h2&gt;
&lt;p&gt;A top-level declaration is &lt;strong&gt;public by default&lt;/strong&gt;. Two modifiers restrict it, and they are one keyword
with an optional scope:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;visible to&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private[own_module]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every file of this module&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private[ancestor]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the named ancestor module and its whole subtree&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;(unmarked)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;any module that imports it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch

&lt;span class=&quot;hl-function&quot;&gt;exported&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lookup&lt;/span&gt;(fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = fd

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[arch] &lt;span class=&quot;hl-function&quot;&gt;reset&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;reset&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, c)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bare form being &lt;strong&gt;file&lt;/strong&gt;-scoped is a deliberate divergence from Scala, and it costs nothing:
module-private is exactly &lt;code&gt;private[own_module]&lt;/code&gt;, the degenerate case of the scoped form. What it buys
is the one level that provably never crosses a file boundary, which is the level at which a
declaration can be fully inferred and given internal linkage.&lt;/p&gt;
&lt;p&gt;The honest cost is that the everyday module-internal helper is now the wordier &lt;code&gt;private[arch]&lt;/code&gt; rather
than a bare &lt;code&gt;private&lt;/code&gt;. The alternative spends a whole keyword to save a bracket.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A restriction is about naming, not existence.&lt;/strong&gt; A file-private declaration still belongs to its
module and still spends its name there, so a sibling file cannot declare something else of that name.&lt;/p&gt;
&lt;h3 id=&quot;hiding-the-shape-is-a-different-axis&quot;&gt;Hiding the shape is a different axis&lt;/h3&gt;
&lt;p&gt;Visibility decides who may say a &lt;strong&gt;name&lt;/strong&gt;. It does nothing about a type’s &lt;strong&gt;layout&lt;/strong&gt;: a &lt;code&gt;private&lt;/code&gt;
field still occupies its place, counts toward the size, shifts the fields after it, and takes part in
the ABI. Anyone who can name the type can still be built against its shape.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;opaque&lt;/code&gt; is the other axis. Inside the declaring module the struct is ordinary:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;opaque &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;
    fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    live: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Conn&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;(n, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(c: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;fd &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(c.fd)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;c), c.live)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;fd 7 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Outside it, the type is &lt;strong&gt;incomplete&lt;/strong&gt; — the same thing C’s &lt;code&gt;struct foo;&lt;/code&gt; is — and the only thing
anyone may say about it is &lt;code&gt;*Conn&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; net.&lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;        &lt;span class=&quot;hl-comment&quot;&gt;// refused: no size out here&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;       &lt;span class=&quot;hl-comment&quot;&gt;// fine — a pointer needs no shape&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything refused outside is refused for one reason: constructing, reading a field, taking an
element, a by-value parameter or result, &lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt;, &lt;code&gt;offsetof&lt;/code&gt;, a by-value &lt;code&gt;self&lt;/code&gt; method.
Each needs a size or an offset, and the size is exactly what is being withheld — so it is one rule
rather than fifteen.&lt;/p&gt;
&lt;p&gt;The by-value &lt;code&gt;self&lt;/code&gt; method is the case worth pointing at, because it looks like an ordinary call and
is not. The &lt;em&gt;function&lt;/em&gt; was compiled by the library, but what crosses the boundary is the &lt;strong&gt;caller’s
copy&lt;/strong&gt;, laid out as the fields stood when that caller was built — so adding a field would break it
silently, which is the failure the modifier exists to prevent. &lt;code&gt;*self&lt;/code&gt; and &lt;code&gt;&amp;amp;self&lt;/code&gt; need no shape, and
are what an opaque type’s methods use.&lt;/p&gt;
&lt;p&gt;A struct may also be opaque with &lt;strong&gt;no body at all&lt;/strong&gt;, which is how a C handle is bound: nothing in
sysl lays a &lt;code&gt;Dir&lt;/code&gt; out, and the storage is libc’s.&lt;/p&gt;
&lt;p&gt;The payoff is that a field may move with nothing downstream recompiled. The reach is the declaring
module exactly — not a subtree, the way &lt;code&gt;private[M]&lt;/code&gt; widens — because the files of a module already
share one scope and are already the unit that recompiles together.&lt;/p&gt;
&lt;h2 id=&quot;imports&quot;&gt;Imports&lt;/h2&gt;
&lt;p&gt;A public member is &lt;strong&gt;always&lt;/strong&gt; reachable fully-qualified — &lt;code&gt;sysl.math.max(2, 7)&lt;/code&gt; needs no import at
all. Nothing is required to &lt;em&gt;see&lt;/em&gt; a member; an import exists only to shorten the reference:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max, min}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; m

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sysl.math.&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9 3
7
4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An import is a dotted path through the module tree, and &lt;strong&gt;how the path ends decides what you get&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max              &lt;span class=&quot;hl-comment&quot;&gt;// max(a, b)      — one member, unqualified&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max, min}       &lt;span class=&quot;hl-comment&quot;&gt;// several&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.*                &lt;span class=&quot;hl-comment&quot;&gt;// every public member&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math                  &lt;span class=&quot;hl-comment&quot;&gt;// math.max(a, b) — the module itself&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; bigger}  &lt;span class=&quot;hl-comment&quot;&gt;// a member, renamed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; m             &lt;span class=&quot;hl-comment&quot;&gt;// m.max(a, b)    — the module, renamed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ending the path at a &lt;strong&gt;member&lt;/strong&gt; binds that member under its own name, so calls to it lose their
qualifier entirely. The braces do that for several members at once, and &lt;code&gt;*&lt;/code&gt; for every public member
of the module.&lt;/p&gt;
&lt;p&gt;Ending it at the &lt;strong&gt;module&lt;/strong&gt; binds the module’s last name segment instead — so &lt;code&gt;sysl.math&lt;/code&gt; becomes
&lt;code&gt;math&lt;/code&gt;, and calls keep exactly one level of qualification. That is the self-documenting middle
ground: &lt;code&gt;math.max&lt;/code&gt; says at the call site where the name came from without listing members up top,
where the wildcard says nothing and the explicit list has to be maintained.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;as&lt;/code&gt; renames whatever the path ended at, member or module. It is what you reach for when two modules
offer the same name, and the only way to resolve that collision without writing the full path at
every use.&lt;/p&gt;
&lt;p&gt;If you happen to know Scala 3, these are its import forms unchanged — including &lt;code&gt;as&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Imports usually sit just below the header, but one may also appear &lt;strong&gt;inside a block&lt;/strong&gt;, scoped to it,
for a name wanted in one function only.&lt;/p&gt;
&lt;p&gt;Resolution is innermost-first: a local binding shadows an imported name, and the fully-qualified path
is always available to break a tie. Two wildcard imports offering the same name make an &lt;em&gt;unqualified&lt;/em&gt;
use of it an error naming both — including when one of them is the standard library, which is
auto-imported into every file. That is deliberate: the alternative is a precedence tier that makes the
library quietly lose to whatever a program imported, which is the silent capture the error exists to
prevent.&lt;/p&gt;
&lt;h2 id=&quot;capabilities-ride-along&quot;&gt;Capabilities ride along&lt;/h2&gt;
&lt;p&gt;A capability clause narrows a module, and it is written in the header on a line of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;halt&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;halted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the module is the directory, the clause is a property of the directory — so it must appear in
&lt;strong&gt;every&lt;/strong&gt; file of the module, and the compiler rejects a module whose files disagree. The redundancy
is the point: you can never open a file in a &lt;code&gt;no alloc&lt;/code&gt; module and fail to see that it is.&lt;/p&gt;
&lt;p&gt;The other direction is &lt;code&gt;requires&lt;/code&gt;, and the standard library uses it: &lt;code&gt;sysl.fs&lt;/code&gt; is &lt;code&gt;requires os&lt;/code&gt;,
because a filesystem is something the environment either has or does not, and everything under
&lt;code&gt;sysl.posix&lt;/code&gt; — threads, &lt;code&gt;tty&lt;/code&gt;, &lt;code&gt;rand&lt;/code&gt; — is &lt;code&gt;requires posix&lt;/code&gt;, because pthreads, &lt;code&gt;termios&lt;/code&gt; and
&lt;code&gt;getentropy&lt;/code&gt; are what those modules are made of. A freestanding target importing either is told so at
the import, and the namespace is that same fact put where a reader meets it first.&lt;/p&gt;
&lt;p&gt;That is also why the atomics live apart from the threads. &lt;code&gt;sysl.sync&lt;/code&gt; requires &lt;strong&gt;nothing&lt;/strong&gt;, so a
module that has given up both its allocator and its operating system can still import it — which is
the point, since a spinlock and an atomic counter are what a kernel has before it has anything else.
A module’s requirement is module-wide, so one type in there needing a scheduler would have taken the
whole module out of the kernel’s reach.&lt;/p&gt;
&lt;p&gt;Propagation is over the module graph, which is acyclic — so a module’s effective requirement is
computed in a single sweep rather than an iterated fixpoint, and a &lt;code&gt;no alloc&lt;/code&gt; module importing one
that requires an allocator is an error &lt;strong&gt;at the import&lt;/strong&gt;, not deep in code generation.&lt;/p&gt;
&lt;h2 id=&quot;naming-a-library-the-linker-needs&quot;&gt;Naming a library the linker needs&lt;/h2&gt;
&lt;p&gt;The header has one other inhabitant. An &lt;code&gt;extern&lt;/code&gt; says which symbol it wants and never where that
symbol lives, so a module binding a C library says it with &lt;code&gt;link&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;image&lt;/span&gt;.png
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;png&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;png_create_read_struct&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;create&lt;/span&gt;(ver: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, err: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, fn: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A directive names a library, never a flag&lt;/strong&gt;, and that is the whole design. Where a library lives is
a property of the machine being built for: the mathematics is a separate file on Linux, part of
&lt;code&gt;libSystem&lt;/code&gt; on macOS, inside the CRT on Windows, and absent entirely from a freestanding target that
has no libc to hold it. A directive spelling &lt;code&gt;-lm&lt;/code&gt; would be right on one of those and wrong on three,
and the author could not be told so by any compiler running on the machine that wrote it — the link
that fails is somewhere else. So the file names &lt;code&gt;m&lt;/code&gt; and the driver decides what that becomes,
including deciding it becomes nothing.&lt;/p&gt;
&lt;p&gt;Unlike a capability, &lt;code&gt;link&lt;/code&gt; is &lt;strong&gt;not&lt;/strong&gt; required to agree across a module’s files, because it
describes something narrower: a capability is a property of the whole module, while a link
requirement belongs to the &lt;code&gt;extern&lt;/code&gt;s in one file — and a module that keeps its foreign declarations
together has nothing for its other files to repeat.&lt;/p&gt;
&lt;h2 id=&quot;the-standard-library&quot;&gt;The standard library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The library is a module, not a set of names threaded in beside your program.&lt;/strong&gt; &lt;code&gt;sysl&lt;/code&gt; itself is
auto-imported into every file, which is why nothing so far has had to import anything to call
&lt;code&gt;print&lt;/code&gt; — and what earns that is that it holds what the language desugars onto, which a program
cannot avoid needing. Everything else is a submodule you ask for by name, because a submodule is an
offer rather than part of the language.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;module&lt;/th&gt;&lt;th&gt;what is in it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;print&lt;/code&gt;, &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;Display&lt;/code&gt;, &lt;code&gt;Writer&lt;/code&gt;, &lt;code&gt;Iterate&lt;/code&gt;, the operator traits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.buf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Buf[T]&lt;/code&gt;, the growable sequence, and &lt;code&gt;ByteSink&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;from_utf8&lt;/code&gt;, &lt;code&gt;StrBuilder&lt;/code&gt;, &lt;code&gt;Chars&lt;/code&gt;, &lt;code&gt;CString&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.io&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Reader&lt;/code&gt;, &lt;code&gt;stdin()&lt;/code&gt;, &lt;code&gt;lines()&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.fs&lt;/code&gt;&lt;/td&gt;&lt;td&gt;files and paths — &lt;code&gt;read_text&lt;/code&gt;, &lt;code&gt;write_bytes&lt;/code&gt;, &lt;code&gt;exists&lt;/code&gt;, &lt;code&gt;rename&lt;/code&gt;, and &lt;code&gt;IoError&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;max&lt;/code&gt;, &lt;code&gt;min&lt;/code&gt;, &lt;code&gt;pi&lt;/code&gt;, the float functions, the integer traits &lt;code&gt;Signed&lt;/code&gt; and &lt;code&gt;Bits&lt;/code&gt;, and the integer arithmetic above them — &lt;code&gt;pow&lt;/code&gt;, &lt;code&gt;gcd&lt;/code&gt;, &lt;code&gt;lcm&lt;/code&gt;, &lt;code&gt;divmod&lt;/code&gt;, &lt;code&gt;is_power_of_two&lt;/code&gt;, &lt;code&gt;next_power_of_two&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.regex&lt;/code&gt;&lt;/td&gt;&lt;td&gt;POSIX Extended Regular Expressions — &lt;code&gt;regex&lt;/code&gt;, &lt;code&gt;Regex&lt;/code&gt;, &lt;code&gt;Match&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.sync&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Atomic[T]&lt;/code&gt;, &lt;code&gt;SpinLock&lt;/code&gt;, and the five memory orderings — requires nothing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.posix.threads&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;spawn&lt;/code&gt;, &lt;code&gt;Thread.join&lt;/code&gt;, &lt;code&gt;yield_now&lt;/code&gt;, and &lt;code&gt;Mutex[T]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.args&lt;/code&gt;&lt;/td&gt;&lt;td&gt;command-line options — &lt;code&gt;Scan&lt;/code&gt;, &lt;code&gt;Cli&lt;/code&gt;, and &lt;code&gt;args_of&lt;/code&gt; for a raw &lt;code&gt;argv&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl.sys&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the platform seam — what a freestanding target replaces&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The split is one rule: &lt;strong&gt;what a program cannot avoid needing arrives free, and what it has to ask for
it asks for.&lt;/strong&gt; An array literal and a &lt;code&gt;for&lt;/code&gt; loop are in the language, so nothing imports them. A
sequence that grows is a thing a program decides it wants, so it says so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.str_builder
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; widths: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

widths.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
widths.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;)
widths.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; widest = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;widths.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; widest = &lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(widest, widths[i])

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;str_builder&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;widest of &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(widths.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;()))
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; is &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(widest))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;widest of 3 is 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing there is a language feature. &lt;code&gt;Buf&lt;/code&gt; is ordinary sysl over a slice it replaces when it runs
out; &lt;code&gt;StrBuilder&lt;/code&gt; is ordinary sysl over a &lt;code&gt;Buf[u8]&lt;/code&gt;; and both are importable rather than free because
a program that wants neither should link neither.&lt;/p&gt;
&lt;h3 id=&quot;reading-input&quot;&gt;Reading input&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sysl.io&lt;/code&gt; is the one that needs a word, because it is where the iteration protocol earns its keep:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{stdin, lines}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; src = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;src)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, line)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lines&lt;/code&gt; hands back a cursor, and &lt;code&gt;for&lt;/code&gt; walks anything implementing &lt;code&gt;Iterate&lt;/code&gt; — so the loop reads a
line at a time out of a 4 KiB chunk rather than pulling the file into memory. A &lt;code&gt;Reader&lt;/code&gt; is a trait
with one method, so the same loop reads a socket, a ring buffer, or a test fixture, and a freestanding
target substitutes one body.&lt;/p&gt;
&lt;h2 id=&quot;separate-compilation&quot;&gt;Separate compilation&lt;/h2&gt;
&lt;p&gt;A module is compiled once and linked, which is what the acyclic import graph buys. The standard
library itself is an artifact — a real &lt;code&gt;ar&lt;/code&gt; archive — and the compiler builds it for you when nothing
usable is at the default path, announced on stderr and in well under a second. It lives in your cache
directory under a fingerprint of the library it was built from, so every project on the machine shares
one and a new compiler makes its own without disturbing the old. There is no bootstrap step to run and
none to remember.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/contracts/&quot;&gt;contracts&lt;/a&gt; — types that carry a rule, and functions that state what they
require.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Modules</title>
    <link href="https://sysl.sh/reference/modules/"/>
    <id>https://sysl.sh/reference/modules/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A module is a directory — visibility, imports, the acyclic graph, where a program starts, and separate compilation.</summary>
    <content type="html">&lt;p&gt;&lt;strong&gt;A module is a directory&lt;/strong&gt; of source files, and its name is that directory’s path relative to the
project root, with the separators read as dots. The files under &lt;code&gt;oskit/arch/&lt;/code&gt; make up the module
&lt;code&gt;oskit.arch&lt;/code&gt;; those under &lt;code&gt;std/fs/&lt;/code&gt; make up &lt;code&gt;std.fs&lt;/code&gt;. Every declaration in every file of the
directory is a member of the one module, so &lt;strong&gt;splitting a growing module into more files adds no new
module and changes no import.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Each file states which module it contributes to, in a header, and the compiler checks the declared
name against where the file sits:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch

&lt;span class=&quot;hl-function&quot;&gt;halt&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;halted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is Scala’s &lt;code&gt;package&lt;/code&gt; and Go’s directory-package. It pays off directly for the target: an OS
subsystem &lt;em&gt;is&lt;/em&gt; a directory — an arch layer, a server, a driver — so the module is the subsystem, and
the subsystem is the unit an importer depends on and the unit a capability clause narrows.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The files of one module must all name it the same way&lt;/strong&gt;, because the module is the directory, so
its name is a property of the directory rather than of any file in it. Each file is held to the name
its &lt;em&gt;location&lt;/em&gt; gives it, which is the stronger rule: the file that strayed is reported on its own
line rather than as a disagreement with whichever sibling happened to be read first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A file with no header is in the anonymous root module&lt;/strong&gt;, whose name is the empty path. That is what
lets a program be one file with no ceremony — the one-file case is not a special form, it is a module
that happens to be unnamed. And because its name is empty, &lt;strong&gt;nothing can name it&lt;/strong&gt;: its declarations
are visible to its own files and to nothing else. That is the right way round for the place a program
starts — the root reaches down into the modules it is built out of, and they do not reach back up.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A module and a type of its parent may not spell one path.&lt;/strong&gt; A dotted reference takes the longest
prefix that names a module, so a module &lt;code&gt;geom.Point&lt;/code&gt; alongside a type &lt;code&gt;Point&lt;/code&gt; in &lt;code&gt;geom&lt;/code&gt; would take
&lt;code&gt;geom.Point.dist&lt;/code&gt; outright and leave the type’s member no spelling at all. The two stay distinct
declarations either way — what collides is the path a program writes — so the second is refused with
a diagnostic rather than settled by a silent choice.&lt;/p&gt;
&lt;h2 id=&quot;visibility&quot;&gt;Visibility&lt;/h2&gt;
&lt;p&gt;A top-level declaration is &lt;strong&gt;public by default&lt;/strong&gt;. Two modifiers restrict it, and they are one keyword
with an optional scope:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;visible to&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private[own_module]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every file of this module&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private[ancestor]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the named ancestor module and its whole subtree&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;(unmarked)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;any module that imports it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch

&lt;span class=&quot;hl-function&quot;&gt;exported&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lookup&lt;/span&gt;(fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = fd

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[arch] &lt;span class=&quot;hl-function&quot;&gt;reset&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = c

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt;[oskit] &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;FrameHeader&lt;/span&gt;
    magic: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; FrameHeader&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;M&lt;/code&gt; resolves innermost-outward.&lt;/strong&gt; The argument is a &lt;strong&gt;simple name&lt;/strong&gt;, not a path, matched against the
enclosing module names from the declaring module outward, first hit winning — so &lt;code&gt;private[geom]&lt;/code&gt;
inside &lt;code&gt;geom/mesh/geom/tri&lt;/code&gt; binds to the nearer &lt;code&gt;geom&lt;/code&gt;. A name matching no enclosing module is an
error; there is no way to name an unrelated module, so a visibility scope is always a &lt;strong&gt;contiguous
subtree containing the declaration&lt;/strong&gt;. Because the name is resolved where it is declared, moving a
subtree elsewhere does not change what its internal annotations mean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why file-scoped and not module-scoped.&lt;/strong&gt; This is a deliberate divergence from Scala, where &lt;code&gt;private&lt;/code&gt;
means the enclosing class or package. Making the bare form file-scoped costs nothing in
expressiveness — module-private is exactly &lt;code&gt;private[own_module]&lt;/code&gt;, the degenerate case of the scoped
form — and it buys the one level that provably &lt;strong&gt;never crosses a file boundary&lt;/strong&gt;, which is the level
at which a declaration can be fully inferred and LLVM &lt;code&gt;internal&lt;/code&gt; linkage applies. The cost is honest:
the everyday module-internal helper is &lt;code&gt;private[arch]&lt;/code&gt; rather than a bare &lt;code&gt;private&lt;/code&gt;, so the common
case is the wordier one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;pub&lt;/code&gt; keyword.&lt;/strong&gt; Rust makes a declaration private until &lt;code&gt;pub&lt;/code&gt;; Scala and Kotlin make it
public until restricted, and that is the precedent here. The low-ceremony common case — a small module
whose declarations are meant to be used — writes no modifier, and encapsulation is the deliberate act.&lt;/p&gt;
&lt;h3 id=&quot;a-restriction-is-about-naming-not-about-existence&quot;&gt;A restriction is about naming, not about existence&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A modifier decides who may write a name; it never makes a second namespace.&lt;/strong&gt; A file-private
declaration still belongs to its module and still spends its name there, so a sibling file cannot
declare something else of that name. The five declaration forms take a modifier; an &lt;code&gt;impl&lt;/code&gt; takes
none, having no name for one to restrict; and an &lt;strong&gt;enum’s variants carry the enum’s own&lt;/strong&gt;, since a
type nobody outside may name is not one whose variants they may construct.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A name a file may not reach is not a candidate for it.&lt;/strong&gt; Resolution passes over one and goes on
through the file’s imports rather than stopping there — a file that wrote &lt;code&gt;import util.width&lt;/code&gt; said
which &lt;code&gt;width&lt;/code&gt; it meant, and a sibling file’s private helper of that name is not an answer to it.
Where nothing else answers at all, the restriction is then reported, because at that point it is the
whole story and a better one than an undefined name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A wildcard offers only what is visible; a selector is refused where it is not.&lt;/strong&gt; A wildcard has
claimed nothing, so a name it cannot see is simply not among what it brings in, and cannot make
another module’s name ambiguous either. Naming something deliberately is the opposite case, and being
told at the import that it is private is more use than an undefined name at every shorter spelling it
would have bound.&lt;/p&gt;
&lt;h3 id=&quot;a-declaration-may-not-be-more-visible-than-the-types-it-names&quot;&gt;A declaration may not be more visible than the types it names&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;What a declaration says about itself has to be as nameable as the declaration is.&lt;/strong&gt; A private struct
beside a public function returning it would hand every module a value of a type none of them may
name: they could hold it, pass it on, and read its fields, and the one thing they could not do is
write the type down.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;().x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;make&apos; is public, but its result names &apos;Point&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The comparison is between two &lt;strong&gt;reaches&lt;/strong&gt;, and every reach is a contiguous region because
&lt;code&gt;private[M]&lt;/code&gt; may only name an enclosing module: a type restricted to a subtree may stand in a
signature restricted to that subtree or to anything inside it, and never the other way round. A
bare-&lt;code&gt;private&lt;/code&gt; declaration is exempt in every case — it is read in one file, and a type it can name at
all is visible there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“Signature” is the shorter word for it, and the rule is not about signatures.&lt;/strong&gt; It is about
everything a declaration says about itself, so it reaches the forms that have no signature at all: a
field, an enum variant’s payload, a type parameter’s bound and its default, and the declarations that
are a &lt;strong&gt;name and one type&lt;/strong&gt; — a &lt;code&gt;const&lt;/code&gt;, a module-level &lt;code&gt;val&lt;/code&gt; and an &lt;code&gt;extern&lt;/code&gt; variable. It reaches everything a
caller has to be able to write: a struct’s fields and a variant’s payload, since neither has a
visibility of its own; a &lt;strong&gt;type argument&lt;/strong&gt;, since &lt;code&gt;Box[Point]&lt;/code&gt; names &lt;code&gt;Point&lt;/code&gt; as much as a bare &lt;code&gt;Point&lt;/code&gt;
does; a trait behind a memory mode; a member of a type or a trait; and a &lt;strong&gt;bound&lt;/strong&gt;, since a trait a
caller cannot name leaves it unable to say what is being asked of it.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;const&lt;/code&gt; was not always among them: a constant was held to being a scalar, and every scalar is a
builtin nobody may restrict, so there was nothing to reach the question with. A &lt;strong&gt;transparent
subtype&lt;/strong&gt; of a scalar is a constant’s type now, and that is a declared type somebody may make private
— so the rule stated in advance for a hole that did not yet exist is the rule that closes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;impl&lt;/code&gt; block is outside the rule, in both directions.&lt;/strong&gt; Implementing a private trait for a public
type adds a member nobody outside can ask for by trait; implementing a public trait for a private
type makes a public promise about a type that stays unnameable. Neither leaks a name, and a private
type reaching a caller &lt;em&gt;through&lt;/em&gt; a trait’s signature is a leak in the trait, which is where it is
reported.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rust refuses this and Scala allows it; this follows Rust.&lt;/strong&gt; The refusal is what makes &lt;code&gt;private&lt;/code&gt; mean
something a reader can rely on, and it is additive in the safe direction: forbidding it now rules out
nothing a later rule would have had to keep allowing, while allowing it and tightening later would
break programs.&lt;/p&gt;
&lt;h3 id=&quot;anything-visible-outside-its-file-states-its-types&quot;&gt;Anything visible outside its file states its types&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A declaration visible beyond the file that declares it carries explicit types.&lt;/strong&gt; Inference is
available only at the bare-&lt;code&gt;private&lt;/code&gt; level — the one level that provably never crosses a file boundary
— which is why the two rules are really one.&lt;/p&gt;
&lt;p&gt;Most of it the syntax already enforces: parameter and field types are mandatory, and a return type is
written or its absence &lt;em&gt;means&lt;/em&gt; &lt;code&gt;unit&lt;/code&gt;. What the rule genuinely binds is the two declarations that are
a name and a type — a &lt;code&gt;const&lt;/code&gt; and a module-level &lt;code&gt;val&lt;/code&gt;, both below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why: it makes interface extraction parse-only.&lt;/strong&gt; A file’s exported surface can be read off its
syntax tree without resolving a name, checking a body, or having compiled anything the file imports.
That is what a fast, parallel, and eventually incremental build rests on. Scala infers types for
public members and pays for it with a far heavier extraction step; this is a deliberate divergence,
and it is cheap here precisely because sysl’s signatures were already explicit for other reasons.&lt;/p&gt;
&lt;h2 id=&quot;imports&quot;&gt;Imports&lt;/h2&gt;
&lt;p&gt;A module reaches another module’s members two ways, and &lt;strong&gt;the first needs no import at all.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max, min}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), sysl.math.&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 2 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A member is always reachable fully-qualified&lt;/strong&gt; by its module path. Nothing is required to &lt;em&gt;see&lt;/em&gt; a
public member; an import exists only to &lt;strong&gt;shorten&lt;/strong&gt; the reference.&lt;/p&gt;
&lt;p&gt;An import is a dotted path through the module tree, and &lt;strong&gt;how the path ends decides what you get&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max              &lt;span class=&quot;hl-comment&quot;&gt;// max(a, b)      — one member, unqualified&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max, min}       &lt;span class=&quot;hl-comment&quot;&gt;// several&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.*                &lt;span class=&quot;hl-comment&quot;&gt;// every public member&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{max &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; bigger}  &lt;span class=&quot;hl-comment&quot;&gt;// a member, renamed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; bigger    &lt;span class=&quot;hl-comment&quot;&gt;// the same, unbraced&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math                  &lt;span class=&quot;hl-comment&quot;&gt;// math.max(a, b) — the module itself&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; m             &lt;span class=&quot;hl-comment&quot;&gt;// m.max(a, b)    — the module, renamed&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those are Scala 3’s import forms unchanged. The &lt;strong&gt;unbraced &lt;code&gt;as&lt;/code&gt;&lt;/strong&gt; belongs to the bare-path form alone,
where exactly one thing is being named: after a wildcard there is nothing for one word to rename, and
a selector list carries its own &lt;code&gt;as&lt;/code&gt; per name, so both are refused rather than quietly ignored. It
renames whatever the path turned out to name — a member or a module — because which of the two it is
is settled by the same longest-prefix rule everything else uses, and a reader wanting a shorter word
should not have to know the answer first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A module brought in by name is a prefix wherever a written path is:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math &lt;span class=&quot;hl-keyword&quot;&gt;as&lt;/span&gt; m

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;import sysl.math&lt;/code&gt; makes &lt;code&gt;math.max(p)&lt;/code&gt;, &lt;code&gt;math.Float&lt;/code&gt;, and &lt;code&gt;[T: math.Float]&lt;/code&gt; all work, because the
leading segment of a dotted reference is read through the imports where it is not already a module.
Two rules keep those from ever both applying: a module reached by the name it already has asks for
what is already true and binds nothing, and &lt;strong&gt;an import may not be given a name that a module path
already begins with&lt;/strong&gt;. The second is a refusal rather than a precedence rule on purpose — a binding
that is both would make &lt;code&gt;fs.read&lt;/code&gt; mean one thing in a file that imported &lt;code&gt;fs&lt;/code&gt; and another in the file
beside it, and &lt;code&gt;as&lt;/code&gt; costs one word.&lt;/p&gt;
&lt;h3 id=&quot;resolution&quot;&gt;Resolution&lt;/h3&gt;
&lt;p&gt;An unqualified name is looked for &lt;strong&gt;in the module it is written in, then among the file’s imports,
then in the library&lt;/strong&gt;, and nowhere else. A sibling module’s names are not in scope unqualified, and
neither are the root module’s, which have no path to be reached by at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Resolution is innermost-first.&lt;/strong&gt; A local binding shadows an imported name; the fully-qualified path
is always available to break a tie or reach a name deliberately not imported.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The three steps rank a name by where it was written, not by what kind of thing it is.&lt;/strong&gt; A function,
a &lt;code&gt;const&lt;/code&gt;, a module-level &lt;code&gt;val&lt;/code&gt;, an &lt;code&gt;extern&lt;/code&gt; variable and an enum variant are different kinds of
declaration, and a bare name may be any of them — a program’s own answers before an import’s, and an
import’s before the library’s, whichever kind each one is. The library declares a &lt;code&gt;stdout()&lt;/code&gt;; a
program that declares storage of that name reaches its own, and the library’s is still there under
the path that names it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; stdout: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

sysl.&lt;span class=&quot;hl-function&quot;&gt;stdout&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the library&apos;s&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(stdout + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the library&apos;s
8
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;situation&lt;/th&gt;&lt;th&gt;result&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a wildcard offers a name that is also defined locally or imported selectively&lt;/td&gt;&lt;td&gt;the more specific one wins&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;two wildcards both offer one name&lt;/td&gt;&lt;td&gt;an &lt;em&gt;unqualified&lt;/em&gt; use is a compile error naming both&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;two selectors bind one name, or two statements do&lt;/td&gt;&lt;td&gt;reported at the second import&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A wildcard offers a name; a selector binds one.&lt;/strong&gt; That is the whole of the difference: a wildcard
neither collides with a selective import of a name it also offers, nor with a second wildcard over the
same module, because it has claimed nothing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.*

&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Binding one name twice &lt;strong&gt;is&lt;/strong&gt; a mistake, and is reported at the second import rather than at whichever
use first found two answers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;max&apos; is already imported
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The standard module counts as one of those wildcards.&lt;/strong&gt; &lt;code&gt;sysl&lt;/code&gt; is auto-imported into every file, so
a written &lt;code&gt;import a.*&lt;/code&gt; where &lt;code&gt;a&lt;/code&gt; declares an &lt;code&gt;Option&lt;/code&gt; of its own is the two-wildcard case, and an
unqualified &lt;code&gt;Option&lt;/code&gt; in that file is a compile error naming both — it does not shadow the library’s.
That is deliberate: the alternative is a precedence tier that makes the library quietly lose to
whatever a program imported, which is the same silent-capture problem an explicit conflict is being
reported to avoid.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every step is filtered by visibility, the library’s included.&lt;/strong&gt; A member the library keeps to itself
is not an answer to a program’s bare name, exactly as a sibling file’s private helper is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A dotted reference names a module by the longest prefix of it that is one.&lt;/strong&gt; A program holding both
&lt;code&gt;a&lt;/code&gt; and &lt;code&gt;a.b&lt;/code&gt; reads &lt;code&gt;a.b.f&lt;/code&gt; as &lt;code&gt;a.b&lt;/code&gt;‘s &lt;code&gt;f&lt;/code&gt; rather than as &lt;code&gt;a&lt;/code&gt;‘s &lt;code&gt;b&lt;/code&gt;. Everything left of the module
prefix is the ordinary form — &lt;code&gt;read(…)&lt;/code&gt;, &lt;code&gt;Point(…)&lt;/code&gt;, &lt;code&gt;Shape.Circle(…)&lt;/code&gt; — which is why qualified access
needed no second resolution path beside the unqualified one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An import binds a name, not a kind.&lt;/strong&gt; The same spelling may be a type in one module and a function
in another, so what an import records is which path a name stands for; which of them a use meant is
settled by what that position asks for. One import therefore serves a type, a function, a trait, and
an enum variant without saying which it expected to be.&lt;/p&gt;
&lt;h3 id=&quot;where-an-import-may-stand&quot;&gt;Where an import may stand&lt;/h3&gt;
&lt;p&gt;Imports normally sit just below the &lt;code&gt;module&lt;/code&gt; header, but — following Scala — &lt;strong&gt;an import may also
appear inside a block&lt;/strong&gt;, scoped to it, for the case where a name is wanted in one function only:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.max

    &lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(a, b), c)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A block import lasts as long as the block’s local bindings do and shadows whatever the file imported
under the same name. It &lt;strong&gt;takes effect where it is written&lt;/strong&gt;: the statements above it have imported
nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An import is not an executable statement&lt;/strong&gt;, whatever it looks like — it binds a name and runs
nothing, so a file may import freely without becoming the one file of the program that carries its
statements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A file’s imports are not its dependency list.&lt;/strong&gt; Because a qualified reference needs no import, a
file can depend on a module without naming it in any header — the dependency appears only in a body.
Two consequences follow, and they are the price of the convenience above: building the module graph
requires &lt;strong&gt;parsing&lt;/strong&gt; rather than a header scan, and the cycle check below needs real &lt;strong&gt;resolution&lt;/strong&gt;
rather than a textual match, since a local named &lt;code&gt;std&lt;/code&gt; makes &lt;code&gt;std.fs&lt;/code&gt; a field access and not a module
reference.&lt;/p&gt;
&lt;h2 id=&quot;capabilities-are-a-module-property&quot;&gt;Capabilities are a module property&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;capability annotation narrows the module&lt;/strong&gt;, and it is written in the file header below &lt;code&gt;module&lt;/code&gt;,
each on a line of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;oskit&lt;/span&gt;.arch
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the module is the directory and the capability is a property of the module, &lt;strong&gt;a narrowing
must appear consistently in every file of the module&lt;/strong&gt; — a module whose files disagree is rejected.
The redundancy buys local legibility: you can never open a file in a &lt;code&gt;@no_alloc&lt;/code&gt; module and fail to
see that it is one. A file that declares no module may still carry one, since the anonymous root
module is a module like any other.&lt;/p&gt;
&lt;p&gt;The other direction is &lt;code&gt;@requires(...)&lt;/code&gt;, which takes a &lt;strong&gt;list&lt;/strong&gt; because a module often needs more
than one capability at once — the POSIX regex binding is &lt;code&gt;@requires(heap, posix)&lt;/code&gt;, since a &lt;code&gt;regex_t&lt;/code&gt;
is caller-allocated and &lt;code&gt;regcomp&lt;/code&gt; is POSIX.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The heap has two names, and they say different things.&lt;/strong&gt; The capability is &lt;code&gt;heap&lt;/code&gt; and the clause
that gives it up is &lt;code&gt;@no_alloc&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;heap&lt;/code&gt; names a facility&lt;/strong&gt; — whether the machine being built for &lt;em&gt;has&lt;/em&gt; one. It sits beside &lt;code&gt;os&lt;/code&gt;
and &lt;code&gt;posix&lt;/code&gt;, and it is what a project states in
&lt;a href=&quot;/reference/packages/#capabilities&quot;&gt;&lt;code&gt;package.hocon&lt;/code&gt;&lt;/a&gt;, because whether there is a heap is a project
engineering decision.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@no_alloc&lt;/code&gt; names conduct&lt;/strong&gt; — a promise this module’s code does not &lt;em&gt;allocate&lt;/em&gt;, and so does not
need a heap to exist. A promise is about an action, which is why it reads as a verb.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So &lt;code&gt;@no_alloc&lt;/code&gt; narrows away &lt;code&gt;heap&lt;/code&gt;: &lt;em&gt;I do not allocate, therefore I do not need one.&lt;/em&gt; Each spelling is
refused where the other belongs, naming it, since somebody who wrote one meant the other. The other
three capabilities need only one word, because for them giving the facility up and not using it are
the same act.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What &lt;code&gt;@no_alloc&lt;/code&gt; promises, exactly: no execution that begins in this module’s own code makes heap
storage.&lt;/strong&gt; It is a &lt;em&gt;portability claim&lt;/em&gt; — this module can be compiled into a project that has no heap —
and its worth is that the compiler holds you to it while you are developing on a machine that does
have one, rather than at the far end when you first build for the board.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;They are annotations rather than grammar&lt;/strong&gt;, which is what keeps &lt;code&gt;alloc&lt;/code&gt;, &lt;code&gt;no&lt;/code&gt; and &lt;code&gt;requires&lt;/code&gt;
available as ordinary names; see &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@link&lt;/code&gt; is the header’s other inhabitant and is deliberately not held to agreeing.&lt;/strong&gt; &lt;code&gt;@link(&amp;quot;z&amp;quot;)&lt;/code&gt; names
a library the file’s &lt;code&gt;extern&lt;/code&gt;s need, and the files of a module may each name their own — because what
is being described differs. A capability is a property of the whole module, so files that disagreed
would describe different modules, while a link requirement is a property of the &lt;code&gt;extern&lt;/code&gt;s in &lt;em&gt;one&lt;/em&gt;
file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Propagation is over the module graph.&lt;/strong&gt; A module’s effective requirement is its own uses plus the
requirements of every module it imports, transitively, and the whole graph must fit the target. A
&lt;code&gt;@no_alloc&lt;/code&gt; module importing a &lt;code&gt;@requires(heap)&lt;/code&gt; module is an error &lt;strong&gt;at the import&lt;/strong&gt;, not deep in
codegen. Because the graph is acyclic, propagation is a &lt;strong&gt;single sweep in reverse topological order&lt;/strong&gt;
— each module’s requirement set is final before any importer of it is visited — rather than an
iterated fixpoint.&lt;/p&gt;
&lt;p&gt;Two of the capabilities are checked differently, and the difference is worth knowing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;heap&lt;/code&gt; is finer than the declaration&lt;/strong&gt;, and the standard library is why. Inferring it per module
would put the whole of &lt;code&gt;sysl&lt;/code&gt; on one side of a line that runs through the middle of it, since
&lt;code&gt;print&lt;/code&gt; allocates nothing and &lt;code&gt;from_utf8&lt;/code&gt; does — so the inferred half is asked of &lt;strong&gt;what a module
calls&lt;/strong&gt; rather than of which modules it depends on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;os&lt;/code&gt; and &lt;code&gt;posix&lt;/code&gt; are exactly the declaration&lt;/strong&gt;, since they gate which modules &lt;em&gt;exist&lt;/em&gt; rather than
what the language allows. The edge the rule is stated over is the &lt;strong&gt;reference&lt;/strong&gt; graph rather than
the import graph, which is load-bearing: a qualified path reaches another module with no import at
all, so a rule about imports would have missed the shorter of the two ways to write the mistake.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-target-s-half-needs-no-clause-at-all&quot;&gt;The target’s half needs no clause at all&lt;/h3&gt;
&lt;p&gt;A module’s effective set is the target’s intersected with its own narrowing, so a capability is out of
reach whichever of the two removed it — and both are answered at the same edge. &lt;code&gt;@no_os&lt;/code&gt; is the half
you can see in the file. The other half is the machine: on a target whose
&lt;a href=&quot;/reference/packages/#capabilities&quot;&gt;&lt;code&gt;package.hocon&lt;/code&gt;&lt;/a&gt; says &lt;code&gt;os = false&lt;/code&gt;, &lt;strong&gt;every&lt;/strong&gt; module of the
program is one that may not reach &lt;code&gt;sysl.fs&lt;/code&gt;, with nothing written anywhere. A &lt;code&gt;print(exists(&amp;quot;/tmp&amp;quot;))&lt;/code&gt;
in a program with no clause at all is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;error: this reaches &apos;sysl.fs&apos;, which requires &apos;os&apos;, and &apos;aarch64-none-elf&apos; does not provide it — a
target&apos;s capabilities are what &apos;package.hocon&apos; declares, so either this reference cannot be made on
this machine or the config is understating it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The message names the config rather than a clause, because that is where the answer is. Where the
module &lt;em&gt;did&lt;/em&gt; write &lt;code&gt;@no_os&lt;/code&gt;, that is what it hears about instead — a reader sent to the config over
something they said in their own header would go and change the wrong file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A library’s own modules are exempt, and that is what makes the rule usable.&lt;/strong&gt; The modules this
question is asked of are the ones the compilation is &lt;em&gt;producing&lt;/em&gt;: your program’s own. The standard
module’s are not, and neither are a &lt;code&gt;--lib&lt;/code&gt; source root’s or a
&lt;a href=&quot;/reference/packages/#dependencies&quot;&gt;fetched package’s&lt;/a&gt;. A library holding one POSIX module is not a
library a POSIX-less target cannot use — it is a library one module of which your program cannot
reach, and refusing at that module’s own
&lt;code&gt;@requires&lt;/code&gt; would refuse your build over a file you did not write and cannot change. So the refusal
lands at the reference, which is a line somebody chose to write, and a program that never names the
module hears nothing.&lt;/p&gt;
&lt;h3 id=&quot;a-generic-answers-for-what-it-wrote-not-for-what-its-caller-chose&quot;&gt;A generic answers for what it wrote, not for what its caller chose&lt;/h3&gt;
&lt;p&gt;A generic has no execution until a type is chosen, and whoever chose it is usually somebody else. So
the promise is asked of the generic’s body &lt;strong&gt;as written&lt;/strong&gt;, and a monomorphized instance answers for
nothing at all. An allocator-free library may therefore be instantiated at a type whose &lt;code&gt;impl&lt;/code&gt;
allocates: the library promised nothing about a type it never saw.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;lib&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;S&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt;](s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;S&lt;/span&gt;, msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    s.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(msg)
    s.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(msg)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;put&lt;/code&gt; is the caller’s choice, so the program below is accepted although its &lt;code&gt;impl&lt;/code&gt; allocates on every
call — and it is accepted whether or not &lt;code&gt;lib&lt;/code&gt; carries the clause, which is the point of it being a
promise about &lt;code&gt;lib&lt;/code&gt;‘s own conduct.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; lib.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sink&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(s)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; l = &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;l, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(l.n)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What the generic itself constructs is unchanged by the type argument&lt;/strong&gt;, so it is charged where it
is written, at every instantiation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;boxed&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;boxed&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a reference needs an allocator, and this module declared &apos;@no_alloc&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same rule answers the two cases that look like ways around it. A trait’s &lt;strong&gt;default&lt;/strong&gt; body is
written once, in the trait’s own file, so a default that allocates is that module’s conduct however
the implementing type is chosen. And a generic that reaches an allocator through &lt;strong&gt;another generic&lt;/strong&gt;
is still its own module’s, since a call in a generic body leads to the body that was written.&lt;/p&gt;
&lt;p&gt;Nothing is given up where the promise is load-bearing. On a target with no heap every module is
allocator-free with no clause written anywhere, so the module that chose the type is itself checked,
and the walk from its body goes straight through the instance to whatever the type argument dragged
in. What the rule gives up is a refusal aimed at the wrong file.&lt;/p&gt;
&lt;h2 id=&quot;platform-selection-os&quot;&gt;Platform selection — &lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A module’s implementation may be &lt;strong&gt;split across operating systems&lt;/strong&gt; by a directory named
&lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt;. Such a directory &lt;strong&gt;selects but does not name&lt;/strong&gt;: it is not a module, contributes no
segment to any name, and the files inside it belong to the directory that &lt;em&gt;holds&lt;/em&gt; it — exactly as if
they had been written there.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl/fs/path.sysl              module sysl.fs, on every target
sysl/fs/__linux__/dirent.c     that module&apos;s C on Linux, absent everywhere else
sysl/fs/__macos__/dirent.c     that module&apos;s C on macOS
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An importer writes &lt;code&gt;import sysl.fs&lt;/code&gt; and names its members. Which files went into it is not something
they can see or have to know — &lt;strong&gt;the module name is unchanged by the selection&lt;/strong&gt;, and that invariant
is the point of the feature.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The vocabulary is the operating systems a target can have&lt;/strong&gt;, and no more: &lt;code&gt;__macos__&lt;/code&gt;, &lt;code&gt;__linux__&lt;/code&gt;,
&lt;code&gt;__windows__&lt;/code&gt;, &lt;code&gt;__freestanding__&lt;/code&gt;. These are the same words &lt;code&gt;#if linux&lt;/code&gt; uses, because they are the
same idea. A directory of the &lt;code&gt;__x__&lt;/code&gt; shape naming anything else is an &lt;strong&gt;error&lt;/strong&gt; — a misspelled
&lt;code&gt;__linx__&lt;/code&gt; read as an ordinary module directory would compile nothing on any target and be reported,
much later, as a missing function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exactly one operating system is true of a target&lt;/strong&gt;, so at most one of these directories is selected
at any one level. There is no precedence to remember and no tie to break. Files sitting directly in a
directory are compiled for &lt;strong&gt;every&lt;/strong&gt; target; the folders &lt;em&gt;add&lt;/em&gt; to them rather than replacing them, so
shared code stays where it is and only the part that differs moves.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl/posix/time/time.sysl              the whole API, written once
sysl/posix/time/__linux__/clock.sysl   the one primitive that differs
sysl/posix/time/__macos__/clock.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That layering is how to use this: &lt;strong&gt;put the smallest private primitive in the folder and build the
public surface once, outside it.&lt;/strong&gt; A public API duplicated per operating system is two APIs, and they
will drift.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt; directory may not be nested inside another.&lt;/strong&gt; Two axes — an operating system and a
processor, an operating system and a libc — are not what this is for: the second axis is &lt;code&gt;#if&lt;/code&gt; inside
the file, or the C preprocessor inside the &lt;code&gt;.c&lt;/code&gt;, which is where the world already keeps that
knowledge.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A directory this target did not select is not read at all&lt;/strong&gt; — not compiled, not analyzed, not
parsed. That is what lets it hold a &lt;code&gt;.c&lt;/code&gt; including a header this machine does not have, and it is
also the cost: a Linux implementation is checked by a build on Linux and by nothing else.&lt;/p&gt;
&lt;h3 id=&quot;it-exists-for-the-c&quot;&gt;It exists for the C&lt;/h3&gt;
&lt;p&gt;Everything above is true of &lt;code&gt;.sysl&lt;/code&gt; files, and they are the smaller half. A module that differs by
platform can usually say so with &lt;code&gt;#if&lt;/code&gt; in one file — but &lt;strong&gt;a &lt;code&gt;.c&lt;/code&gt; cannot carry a sysl attribute&lt;/strong&gt;, and
it will not be given a sysl-shaped name. The path is the only place its selector could go.&lt;/p&gt;
&lt;p&gt;That is what a directory buys over a filename suffix, and it is why the suffix this section used to
describe was never built: a grammar over sysl filenames would have selected everything except the one
kind of file the feature is for. &lt;a href=&quot;/reference/ffi/&quot;&gt;A library may carry C&lt;/a&gt; has the rest — and the
standard library’s own &lt;code&gt;sysl.fs.entries&lt;/code&gt; is the worked example, four lines of C under each of two
folders, reaching a &lt;code&gt;struct dirent&lt;/code&gt; whose layout no sysl file could honestly transcribe.&lt;/p&gt;
&lt;h2 id=&quot;the-module-graph-is-acyclic&quot;&gt;The module graph is acyclic&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Two modules may not depend on each other&lt;/strong&gt;, directly or through a chain. The dependency graph is a
DAG, and a cycle in it is a compile error naming the modules on the cycle. This is Go’s rule, and a
deliberate divergence from Scala, where a package’s compilation units may depend on each other freely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The graph is over references, not over imports.&lt;/strong&gt; A member of another module is reachable by its
full path with no import at all, so a file can depend on a module its header never mentions. An edge
is whatever &lt;em&gt;resolution&lt;/em&gt; found — a call, a type named in a signature or a field, a trait named as a
bound or behind a memory mode, a variant, a generic instantiated from elsewhere. An import contributes
an edge of its own on top of those, because a file’s imports are meant to be readable as what it
needs, and a dependency that came and went with a use would not be.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;anonymous root module&lt;/strong&gt; sits outside the graph: nothing can depend on it, having no name for
another module to write.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The standard module does not sit outside it.&lt;/strong&gt; Writing &lt;code&gt;print&lt;/code&gt; records an edge on &lt;code&gt;sysl&lt;/code&gt; like any
other reference, and that is deliberate. For a program the edge is inert — nothing in the library can
point back at a program’s module, so it can never close a cycle — but &lt;em&gt;within the library&lt;/em&gt; it is the
whole of what keeps the split honest. &lt;code&gt;sysl&lt;/code&gt; reaches &lt;code&gt;sysl.sys&lt;/code&gt; for the C functions its printing is
built on, so &lt;code&gt;sysl.sys&lt;/code&gt; may name nothing of &lt;code&gt;sysl&lt;/code&gt;‘s, which is why it holds the externs and nothing
else. Read as edges: &lt;code&gt;sysl.sys&lt;/code&gt; needs nothing; &lt;code&gt;sysl&lt;/code&gt; reaches &lt;code&gt;sysl.sys&lt;/code&gt;; &lt;code&gt;sysl.buf&lt;/code&gt; reaches &lt;code&gt;sysl&lt;/code&gt;;
&lt;code&gt;sysl.text&lt;/code&gt; reaches &lt;code&gt;sysl&lt;/code&gt; and &lt;code&gt;sysl.buf&lt;/code&gt;; &lt;code&gt;sysl.io&lt;/code&gt; reaches all four. &lt;strong&gt;Every edge runs away from the
standard module and none runs back&lt;/strong&gt;, which is what makes any of them removable from a program that
never asks.&lt;/p&gt;
&lt;p&gt;Three things follow from acyclicity:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Modules can be compiled in dependency order, and independent modules in parallel.&lt;/strong&gt; A topological
sort exists, so a module’s imports are all fully known before it is checked. A cyclic graph would
force the whole strongly-connected component to be checked as one unit — which is the same as saying
it was never really more than one module.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capability propagation is a sweep, not a fixpoint.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A cycle is a design error, and the fix is cheap.&lt;/strong&gt; Two directories that need each other are either
one module drawn along the wrong line — merge them, which changes no import, since a module is a
directory and its file count is not part of its name — or they share something that belongs in a
third module both import. Neither fix costs an importer anything.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Within a module, cycles are free and carry no ceremony.&lt;/strong&gt; All files of a directory share one scope,
so mutually recursive functions and types across sibling files need no forward declaration and no
ordering: the analyzer collects &lt;strong&gt;every signature in the module before it checks any body&lt;/strong&gt;. The
restriction is on the directory graph, never on how a module’s own files refer to one another.&lt;/p&gt;
&lt;h2 id=&quot;where-a-program-starts&quot;&gt;Where a program starts&lt;/h2&gt;
&lt;p&gt;A top-level &lt;strong&gt;statement&lt;/strong&gt; is not a declaration. A declaration is hoisted and belongs to the module as
a whole; a statement runs, and running happens in an order — and a module’s files have no order at
all, being one unordered scope. So &lt;strong&gt;one file of a program carries the statements it runs&lt;/strong&gt;, and a
second that carries any is an error naming both. That file is the program’s &lt;strong&gt;entry file&lt;/strong&gt;, and its
top level is a &lt;strong&gt;body&lt;/strong&gt;: what it declares is local to it, which the section below is about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A program starts in one place.&lt;/strong&gt; Statements at the top of a file and a &lt;code&gt;main&lt;/code&gt; are two ways of
writing that place, so a program that writes both is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;initialization&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;then main, with&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, args.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a program starts in one place, and this &apos;main&apos; is a second — whichever of the two the program means, the other belongs inside it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Whichever of the two the program means, the other belongs inside it. What a &lt;code&gt;main&lt;/code&gt; has that statements
do not is a parameter list, so a program that wants the arguments writes &lt;code&gt;main&lt;/code&gt; and puts inside it what
it would otherwise have written above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;initialization&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;then the work, with&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, args.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;initialization
then the work, with 1 argument
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What &lt;code&gt;main&lt;/code&gt; gets at that a statement cannot is the arguments.&lt;/strong&gt; A statement has nowhere to receive
them — it is not a call, so it has no parameter list, and a program’s arguments are not a module-level
anything. There are exactly two signatures:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no arguments wanted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;no arguments wanted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;args&lt;/code&gt; is a slice of &lt;code&gt;string&lt;/code&gt;.&lt;/strong&gt; What the platform hands a program is C’s pair — a count and a
vector of NUL-terminated byte runs — and neither appears in a sysl signature anywhere. The library
converts the pair, finding each run’s end, validating its bytes, and &lt;strong&gt;copying&lt;/strong&gt; them into strings the
program owns, so an argument outlives the vector it came from and holds no memory the platform is
still responsible for. The zeroth element is the program’s own path, because that is what the platform
passes. &lt;strong&gt;An argument that is not UTF-8 stops the program&lt;/strong&gt;, with the offset of the byte that made it
ill-formed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;main&lt;/code&gt; names one function in a program&lt;/strong&gt;, wherever it is written — even in two different modules,
where nothing else would collide, and even at the two signatures above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; is where a program starts, so there is one — a second declaration of it would overload the name, and a program has one beginning rather than a set of them
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the reason C reserves the name: it is not a name the program calls, it is the name the
&lt;em&gt;platform&lt;/em&gt; calls, so two would leave which one the program &lt;strong&gt;is&lt;/strong&gt; to whichever was emitted last.
Otherwise it is an ordinary function, and may be called by the program too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;main&lt;/code&gt; may answer with a &lt;code&gt;Result[unit, E]&lt;/code&gt;&lt;/strong&gt;, which is what lets &lt;code&gt;?&lt;/code&gt; reach the top of a program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{read_text, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;}

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; text = &lt;span class=&quot;hl-function&quot;&gt;read_text&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/nonexistent/file&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)?

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(text)

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program prints nothing and exits &lt;strong&gt;1&lt;/strong&gt;, having written &lt;code&gt;error: no such file or directory&lt;/code&gt; to
stderr. Without the form, every fallible call in &lt;code&gt;main&lt;/code&gt; ends in &lt;code&gt;.unwrap()&lt;/code&gt;, which reports the
failure as a panic naming the line that gave up rather than the thing that went wrong.&lt;/p&gt;
&lt;p&gt;Three parts of it are decided rather than incidental. The &lt;code&gt;unit&lt;/code&gt; is not decoration — a value &lt;code&gt;main&lt;/code&gt;
answered with would have nowhere to go, since what the platform takes is a status. &lt;code&gt;E&lt;/code&gt; must be
&lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Display&lt;/code&gt;&lt;/a&gt;, because the report is the whole point and an error nobody can render
would exit non-zero having said nothing. And the status is &lt;code&gt;1&lt;/code&gt; rather than something read off the
error: a status is one byte and an error is a value, so mapping one onto the other is the program’s
business, and &lt;code&gt;exit&lt;/code&gt; is how a program that wants to choose says so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing else is admitted:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; yields nothing or a &apos;Result[unit, E]&apos;, so it may not result in int — a program&apos;s exit status is not something a signature can say
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A program in which no file carries a statement is a complete program that does nothing.&lt;/strong&gt; The entry
point exists, runs nothing, and succeeds. That is what a tree of pure declarations compiles to, which
is what it should compile to — a library is not an error.&lt;/p&gt;
&lt;h3 id=&quot;the-entry-file-is-a-body-and-what-it-declares-is-local-to-it&quot;&gt;The entry file is a body, and what it declares is local to it&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;val&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt; at the top of the entry file are &lt;strong&gt;locals&lt;/strong&gt;: initialized where they are written, in
the order the statements around them run. A function declared there is a &lt;strong&gt;nested function&lt;/strong&gt;
(&lt;a href=&quot;/../functions/&quot;&gt;functions&lt;/a&gt;), so it reads and writes the bindings above it with nothing passed in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
    counter += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counter)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole point of the arrangement, and it is what a script wants: a sequence that is a
sequence. A &lt;code&gt;val&lt;/code&gt; bound from what the statements above it produced is ordinary here, and could never
be a module member — a module member is bound before any statement runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A helper pays nothing for this unless it uses it.&lt;/strong&gt; Whether a function at the top of the entry file
belongs to the body is settled by whether it reads one of the body’s bindings. One that reads none is
an ordinary module function: generic if it says so, addressable, passable as a value, and reachable
from another file. Only one that reads a binding is nested, and only that one takes the nested
function’s limits.&lt;/p&gt;
&lt;h3 id=&quot;static-asking-for-the-module-instead&quot;&gt;&lt;code&gt;static&lt;/code&gt; — asking for the module instead&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt; in the entry file that should be the &lt;strong&gt;module’s&lt;/strong&gt; says so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; table: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = table[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] + table[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] + table[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is then hoisted, laid into the object file, visible to every file of the module, and initialized
before any statement runs — which is also why its initializer may not call a helper that reads the
body: at that moment there is no body yet.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;static var&lt;/code&gt;&lt;/strong&gt; is the same storage, written — assignment at every depth and &lt;code&gt;&amp;amp;&lt;/code&gt;, which is what the
word &lt;code&gt;var&lt;/code&gt; already means, and which a &lt;code&gt;val&lt;/code&gt; refuses because a &lt;code&gt;val&lt;/code&gt; promises its storage is written
once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ticks: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;tick&lt;/span&gt;() = ticks += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;tick&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;tick&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(ticks)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its initializer may be &lt;strong&gt;absent&lt;/strong&gt;, which a &lt;code&gt;val&lt;/code&gt;‘s may not — the type’s zero is what it starts at, and
that is the cheapest form and the one an arena wants.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It holds a counted value, and the last one it holds is never released.&lt;/strong&gt; A &lt;code&gt;string&lt;/code&gt;, a slice, a
&lt;code&gt;&amp;amp;T&lt;/code&gt;, a &lt;code&gt;weak T&lt;/code&gt; and anything built out of them are all module storage; every assignment during the
run gives back the count it replaces, and the only release with nowhere to go is the one at exit —
which is the release a static is &lt;em&gt;defined&lt;/em&gt; by not taking.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; current: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) = current = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + s + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(current)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[two]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was refused until the reason behind it was read again: storage lasting the whole run has no line
to write a release on, which is true and is a description of a static rather than an argument against
one. What the refusal cost was the shape every callback interface needs — a C function that calls
back takes an address and an opaque word, so a binding offering a sysl closure has to keep it where
the trampoline finds it again, and module storage is the only storage that outlives the call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is refused instead is a type with no zero and no initializer&lt;/strong&gt;, which is a narrower rule about
a different thing. A &lt;code&gt;&amp;amp;T&lt;/code&gt; has no zero, because there is no such thing as a reference to nothing; an
enum has none either, since a zeroed tag names no variant in particular. A &lt;code&gt;string&lt;/code&gt; and a slice both
zero to the empty one and need nothing written. It is the same question a &lt;strong&gt;local&lt;/strong&gt; declared with no
initializer is already held to.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cell: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;cell&apos; needs a value: storage with no initializer starts at its type&apos;s zero, and &amp;amp;Cell has none — the same rule a local with no initializer is held to. A &apos;string&apos; and a slice both start empty and need no value written; a reference and an enum need one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; takes the same ruling and for the same reason: a value in module
storage never reaches a count of zero, so its &lt;code&gt;drop&lt;/code&gt; does not run when the program ends.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;static&lt;/code&gt; is meaningful only in the entry file&lt;/strong&gt;, since only that file has a body for a declaration
to &lt;em&gt;not&lt;/em&gt; belong to. In a file with a &lt;code&gt;module&lt;/code&gt; header, or a headerless file carrying no statements,
everything is the module’s already and the modifier is refused rather than ignored. A function never
takes it either: settled by what it reads, the modifier would be redundant on one and impossible on
the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So everywhere else the same storage is written plain &lt;code&gt;var&lt;/code&gt;&lt;/strong&gt;, and it is the same declaration —
visibility, the shared value namespace, the initializer graph and the release rule all answer for it
exactly as above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;counter&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;() = count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two spellings never compete, because the modifier is needed precisely where there is a body to be
asking about. Reading them side by side: &lt;code&gt;static var&lt;/code&gt; in the file the program starts in, &lt;code&gt;var&lt;/code&gt;
anywhere else, one kind of module storage.&lt;/p&gt;
&lt;p&gt;Visibility is the part of that worth writing out, because a module with state usually wants it — the
functions that maintain the storage are public and the storage itself is nobody’s business:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;counter&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;() = count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;peek&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = count&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both spellings take one, so &lt;code&gt;private static var&lt;/code&gt; says the same thing in the file the program starts
in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;var&lt;/code&gt; does not decide which file the program starts in.&lt;/strong&gt; That is settled by what a file &lt;em&gt;runs&lt;/em&gt;,
and declaring storage runs nothing — a file holding a counter is no more the program’s beginning than
one holding a table. Where a file carries a statement that is not a binding, it is the entry file and
every other file’s top-level &lt;code&gt;var&lt;/code&gt;s are their module’s. Where nothing runs anywhere, a single
&lt;strong&gt;headerless&lt;/strong&gt; file of bindings is still a body, so a one-file &lt;code&gt;var n = 1&lt;/code&gt; means what it always did.&lt;/p&gt;
&lt;p&gt;That word is load-bearing: &lt;strong&gt;a file naming a module is never the program’s beginning&lt;/strong&gt;, and it is the
sentence at the top of this section seen from the other side — a header means everything the file
declares is the module’s already, so there is no body for a binding to belong to instead. A library is
the shape that tests it, being files and no beginning anywhere.&lt;/p&gt;
&lt;h2 id=&quot;const-a-value&quot;&gt;&lt;code&gt;const&lt;/code&gt; — a value&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;const&lt;/code&gt; is a module member&lt;/strong&gt;: hoisted, order-free, visible to the whole module and beyond it under
the ordinary rules, and never running at all.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; capacity: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;512&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; window: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class=&quot;hl-number&quot;&gt;15&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;capacity

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; table: [capacity]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; capacity]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(table.len, window, capacity)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;512 32768 512
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why it exists at all&lt;/strong&gt;, when a nullary function already serves every use in an expression: an array
bound is a compile-time constant and a call is not. Without &lt;code&gt;const&lt;/code&gt;, a program carries &lt;code&gt;[512]u8&lt;/code&gt; next
to a &lt;code&gt;capacity()&lt;/code&gt; function and a comment asking the reader to keep the two in step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The type is always written&lt;/strong&gt; — not because it could not be inferred from the initializer, but
because the rule that anything visible outside its file states its types is what keeps interface
extraction parse-only. Writing it is also what fixes the literal’s type, so &lt;code&gt;const capacity: usize = 512&lt;/code&gt; needs no suffix on the &lt;code&gt;512&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And the type is a scalar, or a transparent subtype of one.&lt;/strong&gt; The first half is the shape of what a
constant expression can produce rather than a restriction anybody chose — there is no aggregate
literal to fold to, and a table would be storage rather than a value. The second half follows from a
transparent subtype &lt;em&gt;being&lt;/em&gt; its base, so a constant declared at one is a literal at an integer, a
float or a &lt;code&gt;char&lt;/code&gt; — and its range is checked while compiling:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; oldest: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;122&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(oldest)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;122
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; oldest: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;which Age does not admit — it holds 0 to 150
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That check is the one thing a constant gets that a &lt;code&gt;val&lt;/code&gt; of the same type gets only at run time, and
it is what a &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c const&lt;/code&gt;&lt;/a&gt; is really for: a number nobody chose — a &lt;code&gt;sizeof&lt;/code&gt;, a config
macro out of somebody else’s header — held to what this program can actually do with it.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;new&lt;/code&gt; type&lt;/strong&gt; is refused, because reaching one from its base is a written conversion and a constant
is the value it was written as, so there is nowhere on the line to write one. A &lt;strong&gt;&lt;code&gt;where&lt;/code&gt; predicate&lt;/strong&gt;
is refused too, because a predicate is checked where a value is &lt;em&gt;made&lt;/em&gt; and a constant is folded into
its uses rather than made anywhere — admitting one would be a check the declaration claims and the
program never gets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A constant expression&lt;/strong&gt; is a literal; a &lt;code&gt;const&lt;/code&gt;; a conversion; a unary &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt; or &lt;code&gt;~&lt;/code&gt;; or a binary
arithmetic, bitwise, shift, or comparison operator applied to constant expressions. Integers, floats,
&lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;char&lt;/code&gt; fold.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are no calls&lt;/strong&gt;, and a &lt;code&gt;string&lt;/code&gt; constant’s initializer must be a &lt;strong&gt;literal&lt;/strong&gt; — since &lt;code&gt;+&lt;/code&gt; on
strings allocates, and a compile-time concatenation would be a different operation wearing the same
spelling:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; called: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(called)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the value of &apos;called&apos; is not a constant expression
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function call in a constant expression is a request for compile-time evaluation of arbitrary code,
which is a language of its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“A &lt;code&gt;const&lt;/code&gt;“ above means the declaration, not a spelling of it.&lt;/strong&gt; A constant reached by its full path
is the same constant as one reached by an import, and the two fold alike in every position below —
what decides is what the name resolves to, and the three steps above are the whole of how a name
resolves:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; bits.byte_width

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; packed: [byte_width]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;            -- imported
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; padded: [bits.byte_width]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;       -- the same declaration, named through its &lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is worth saying only because the two spellings are different enough to be implemented separately,
and once were. A &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c const&lt;/code&gt;&lt;/a&gt; is no different: a binding keeps its measured
constants in a sub-module of their own, so every consumer names them qualified.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where a constant may stand:&lt;/strong&gt; anywhere an expression may, plus the four places a literal was
previously the only thing accepted — an &lt;strong&gt;array bound&lt;/strong&gt;, an &lt;strong&gt;enum discriminant&lt;/strong&gt;, a &lt;strong&gt;pattern&lt;/strong&gt;, and
the bounds of a &lt;strong&gt;&lt;code&gt;within&lt;/code&gt; range&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Op&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Halt&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Push&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at the limit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;     &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Op&lt;/span&gt;.&lt;span class=&quot;hl-type&quot;&gt;Halt&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Op&lt;/span&gt;.&lt;span class=&quot;hl-type&quot;&gt;Push&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;at the limit other 3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All four go through the &lt;strong&gt;same fold&lt;/strong&gt;, which is the property worth keeping: they accept the same
expressions because they ask the same question, rather than several grammars agreeing by coincidence.&lt;/p&gt;
&lt;p&gt;The pattern position is the one worth saying out loud, because it is where other languages have come
to grief: a name in a pattern binds unless it resolves to something, and Rust’s rule that a lowercase
&lt;code&gt;const&lt;/code&gt; in a pattern &lt;em&gt;binds&lt;/em&gt; instead of matching is a documented trap. Here it cannot arise — a
pattern name already resolves against the enum variants in scope before it is taken as a binding, and
a constant joins that same resolution rather than adding a second one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A constant has no address.&lt;/strong&gt; It is folded into each use and occupies no storage, which is why it
needs no initialization order, why a &lt;code&gt;no alloc&lt;/code&gt; module may hold one, and why &lt;code&gt;&amp;amp;capacity&lt;/code&gt; is not a
thing to write. That is also what rules it out for a &lt;strong&gt;table&lt;/strong&gt;, which is indexed at a value only known
while running and therefore has to be somewhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A cycle between constants is reported at the declaration&lt;/strong&gt;, naming the loop:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = b
&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;constant &apos;a&apos; is defined in terms of itself: a → b → a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things a constant is &lt;strong&gt;not&lt;/strong&gt;. Not an &lt;strong&gt;enumeration&lt;/strong&gt; — a set of related named values is a simple
enum, which is the type-safe replacement for a pile of constants; if a second constant would be the
obvious neighbour of the first, the declaration wanted was an &lt;code&gt;enum&lt;/code&gt;. And not a &lt;strong&gt;value generic&lt;/strong&gt; —
parameterizing over a length is &lt;code&gt;[const N: usize]&lt;/code&gt;, which is this declaration with the initializer
left to the caller. The two are one idea in two positions, and this one had to come first: a value
cannot be passed as an argument before it can be named.&lt;/p&gt;
&lt;h2 id=&quot;val-a-thing&quot;&gt;&lt;code&gt;val&lt;/code&gt; — a thing&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;val&lt;/code&gt; is a thing, where a &lt;code&gt;const&lt;/code&gt; is a value.&lt;/strong&gt; As a module member it is read-only storage that
exists for the whole run; as a local it is the immutable counterpart of &lt;code&gt;var&lt;/code&gt;, in the same frame with
the same lifetime. One keyword at both levels, because it is one idea at both — and which one it is
follows the file it is written in: the module’s everywhere except the entry file, whose top level is a
body, and where &lt;code&gt;static&lt;/code&gt; asks for the member.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; order: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = order[i]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; order.len
    total += &lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i)
    i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(total, order[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;31 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The whole difference from a &lt;code&gt;const&lt;/code&gt; is an address.&lt;/strong&gt; A constant is folded into every use, which is
what lets it size an array and what stops it from being one. A &lt;code&gt;val&lt;/code&gt; sits somewhere, so it may be
indexed at a value only known while running, iterated, and reached into. The rule for a reader is
short: &lt;strong&gt;if it has to be indexed or pointed at, it is a &lt;code&gt;val&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because it is read while running, a &lt;code&gt;val&lt;/code&gt; is the one module-level name that cannot size a type or
stand in a pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; table: [limit]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(table.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an array length must be a constant — a literal, or a &apos;const&apos; naming one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Naming one in a pattern with a &lt;strong&gt;bare&lt;/strong&gt; name is an error rather than a quiet binding, for the same
reason — a bare name there would bind rather than match, and the diagnostic names what to write
instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        limit -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at the limit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;     &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a bare name here would bind rather than match
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What to write is the &lt;a href=&quot;/reference/patterns/#a-backticked-name-references-rather-than-binds&quot;&gt;backticked form&lt;/a&gt;,
which says the test was meant and compares against whatever the &lt;code&gt;val&lt;/code&gt; holds when the match runs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limit: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;`limit`&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at the limit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;     &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;at the limit other
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rest of what a module-level &lt;code&gt;val&lt;/code&gt; may hold — read-only at every depth, and the &lt;code&gt;[]const T&lt;/code&gt; a
slice of one yields — is on &lt;a href=&quot;/reference/declarations/#a-module-member-states-its-type&quot;&gt;declarations&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;separate-compilation&quot;&gt;Separate compilation&lt;/h2&gt;
&lt;p&gt;A library is built into one file and linked against, rather than recompiled by everything that uses
it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl build-lib mylib -o mylib.syslib     # compile the library once
sysl run prog.sysl --lib mylib.syslib    # link a program against it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--lib&lt;/code&gt; takes either an artifact or a source tree&lt;/strong&gt;, and which one is read off the name. How a
library shipped is the shipper’s business; a program that depends on one should not have to write down
which form it got. Given a source tree the library is simply &lt;em&gt;more modules&lt;/em&gt;, and the rules at the top
of this page do the rest.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An artifact has two halves, and the split is the whole design.&lt;/strong&gt; A declaration with &lt;strong&gt;no type
parameters&lt;/strong&gt; is compiled ahead of time into object code by whoever built the library, and a program
that calls it declares the symbol and links the body. A &lt;strong&gt;generic&lt;/strong&gt; has nothing to compile until a
caller fixes its type arguments, so it crosses as the tree it was parsed into and is monomorphized in
the consuming program. Rust’s &lt;code&gt;.rlib&lt;/code&gt; makes the same split for the same reason.&lt;/p&gt;
&lt;p&gt;The metadata carries &lt;strong&gt;every&lt;/strong&gt; declaration, not only the generic ones: a call into the precompiled
half still has to be type-checked, and the tree is where the signature is. What the symbol list adds
is which of those the consumer must declare rather than emit a second time.&lt;/p&gt;
&lt;p&gt;Five consequences, each a thing a reader would otherwise have to discover:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;An artifact is for one machine&lt;/strong&gt;, and &lt;em&gt;both&lt;/em&gt; halves pin it. The object half obviously does; the
tree half does because a library may gate on the machine it is built for, which makes two artifacts
built from one source two different sets of declarations. So an artifact records its target and is
refused by a build for another — refused rather than left to the linker, which would eventually
complain about object formats in a message saying nothing about which library or why.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A library carries no entry point.&lt;/strong&gt; A &lt;code&gt;main&lt;/code&gt; of its own would collide with the one belonging to
whatever links it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing is pruned when a library is built.&lt;/strong&gt; A program is lowered from &lt;code&gt;main&lt;/code&gt; outwards because
what it cannot reach is dead; a library has no &lt;code&gt;main&lt;/code&gt; and every public declaration is a potential
entry, so all of them are emitted and the &lt;em&gt;linker&lt;/em&gt; discards what a given program never calls.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A library defines its own declarations and nobody else’s.&lt;/strong&gt; A library that prints reaches the
library’s own printing surface exactly as a program does — but emitting &lt;em&gt;those&lt;/em&gt; would put a copy in
every artifact, so two libraries that both printed could not be linked into one program. They are
declared in the artifact and defined in the consuming program.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A library may not sit in the anonymous root module.&lt;/strong&gt; A library is reached by naming its module,
and the root module has no name, so nothing depending on it could write a path to what it declares.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A library may be built on another library&lt;/strong&gt;, and &lt;code&gt;--lib&lt;/code&gt; is how one gets there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build-lib sdl3 -o sdl3.syslib
sysl build-lib sdl3-ttf --lib sdl3.syslib -o sdl3-ttf.syslib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;build-lib&lt;/code&gt; takes &lt;code&gt;--lib&lt;/code&gt; exactly as a compilation does, and for the same reason: a library whose
declarations are written in another library’s types does not compile without them. &lt;code&gt;sdl3-ttf&lt;/code&gt;‘s
&lt;code&gt;Font&lt;/code&gt; renders to an &lt;code&gt;sdl3&lt;/code&gt; &lt;code&gt;Surface&lt;/code&gt;, so a package that could not say so would have to be a module
inside its dependency rather than a package of its own. Nothing about the artifact changes, because
the fourth bullet above already governs it — the dependency’s compiled half is declared here and
defined by whatever program links both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What &lt;code&gt;build-lib&lt;/code&gt; does not do is fetch.&lt;/strong&gt; A &lt;code&gt;dependencies&lt;/code&gt; block is a coordinate to resolve over the
network, and a command whose whole job is to compile one tree into an artifact for one machine does
not go looking — so a package that declares dependencies and is handed no library is refused, naming
the dependency and the flag that answers it. Such a package writes its dependency down twice, once in
&lt;code&gt;package.hocon&lt;/code&gt; and once on the command line, and that is the price of a compile step that is offline
by construction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The container is an &lt;code&gt;ar&lt;/code&gt; archive&lt;/strong&gt;, which is what an &lt;code&gt;.rlib&lt;/code&gt; is and for the same reason: the linker
already reads one, so the compiled half needs no unwrapping and a member is pulled in only to resolve
something a program actually left undefined. The metadata rides inside it wrapped in a real object
file, as one &lt;code&gt;private&lt;/code&gt; constant in a section of its own, so nothing ever gives the linker a reason to
pull it in and it costs the linked program nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The standard module is built the same way, and linked by default.&lt;/strong&gt; Which library a compilation is
compiled against is a &lt;em&gt;parameter&lt;/em&gt; of it rather than an ambient fact — which is what lets two cores be
handed to two compilations and compared — but the parameter has a default, and the default is found
rather than named. &lt;strong&gt;A compilation that finds no standard module at the default path builds one&lt;/strong&gt;, in
well under a second, announcing it on stderr. That is not the silent substitution a compiler must
never make: a rebuild compiles against &lt;em&gt;this&lt;/em&gt; library, from its own source, held to the same
fingerprint on the way back in. Nothing is substituted, so there is nothing to be misled about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The standard module’s source ships with the compiler and is read off disk&lt;/strong&gt; —
&lt;code&gt;share/sysl/library&lt;/code&gt; under the install prefix, found from the binary’s own location the way &lt;code&gt;rustc&lt;/code&gt;
finds its sysroot. Running out of a checkout, it is &lt;code&gt;library/&lt;/code&gt; in the tree. You can read it, and you can edit it: a changed
file changes the library’s fingerprint, so the next compilation builds an artifact of its own rather
than picking up a stale one. &lt;code&gt;SYSL_LIB&lt;/code&gt; names a library root outright, which is what a broken install
needs and nothing else does. A compiler that cannot find its library names every path it tried.&lt;/p&gt;
&lt;p&gt;The default path is keyed by a fingerprint of the library, so every compilation of the same library
on the machine finds the same artifact — and a rebuild therefore &lt;strong&gt;publishes by rename&lt;/strong&gt;: it is
assembled beside its destination and moved onto it. Two builds may run at once; a reader gets the
whole of one artifact or the whole of the other, and a rebuild that fails leaves the one that was
already there.&lt;/p&gt;
&lt;p&gt;An artifact &lt;strong&gt;named&lt;/strong&gt; on the command line is never rebuilt, and one that cannot be read stops the
compilation — corrupt, truncated, built by another sysl, or built from other sources. Someone who
wrote down which standard module to compile against is owed the truth about that one.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-absent&quot;&gt;What is deliberately absent&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;absent&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a file as a module&lt;/td&gt;&lt;td&gt;the file is a contribution, not a unit; there is no per-file namespace and no import of a file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;pub&lt;/code&gt; keyword&lt;/td&gt;&lt;td&gt;public is the unmarked default; its absence &lt;em&gt;is&lt;/em&gt; public&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;relative or wildcard-path imports&lt;/td&gt;&lt;td&gt;an import names a module by its full dotted path from the project root, so a reference means the same thing wherever the importing file sits&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;auto-import beyond the standard module&lt;/td&gt;&lt;td&gt;a module earns visibility by being imported or fully qualified&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;implicits — Scala’s &lt;code&gt;given&lt;/code&gt;/&lt;code&gt;using&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a term selected by &lt;em&gt;searching&lt;/em&gt; the scope would let a change anywhere alter what resolves in a file that did not change, so a module’s interface would no longer bound its blast radius&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last is the sharpest of them. Scala pays for implicits with per-file used-name tables and API
diffing, and that machinery is the &lt;strong&gt;cost of the feature&lt;/strong&gt; rather than an implementation detail of it.
The one search sysl does perform, for a trait &lt;code&gt;impl&lt;/code&gt;, is bounded to two modules by
&lt;a href=&quot;/reference/traits/#where-an-impl-may-live&quot;&gt;the coherence rule&lt;/a&gt; for exactly the same reason.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Memory</title>
    <link href="https://sysl.sh/tour/memory/"/>
    <id>https://sysl.sh/tour/memory/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Three modes, chosen per declaration. No garbage collector, no borrow checker, and no allocation keyword.</summary>
    <content type="html">&lt;p&gt;This is the chapter that makes sysl a different language rather than a different syntax. Everything
before it would have read much the same in half a dozen languages; nothing after it reads right
until you know this.&lt;/p&gt;
&lt;p&gt;A systems language is used for the control it gives you over where things live and when they die.
The two well-known ways to keep that control and stay safe are a garbage collector, which takes away
the &lt;em&gt;when&lt;/em&gt;, and a borrow checker, which keeps both but asks you to prove your program correct to a
checker as you write it. sysl takes a third road: &lt;strong&gt;reference counting&lt;/strong&gt;, with the choice of mode
written on each declaration.&lt;/p&gt;
&lt;h2 id=&quot;the-three-modes&quot;&gt;The three modes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;mode&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;th&gt;who frees it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value — on the stack, in a register, or inline in something bigger&lt;/td&gt;&lt;td&gt;nobody; it goes when the frame does&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a counted reference to a heap object&lt;/td&gt;&lt;td&gt;the compiler, when the last reference goes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a raw pointer — C’s pointer&lt;/td&gt;&lt;td&gt;you&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The choice is &lt;strong&gt;per declaration&lt;/strong&gt;, not per type. The same &lt;code&gt;struct Point&lt;/code&gt; can be a value here and a
heap object there, and it is the declaration that says which:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; here = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)              &lt;span class=&quot;hl-comment&quot;&gt;// a value, in this frame&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; shared: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)    &lt;span class=&quot;hl-comment&quot;&gt;// on the heap, counted&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;value:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, here.x, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;reference:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, shared.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;value: 1 reference: 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Look closely at those two lines, because the difference between them is the whole idea:
&lt;strong&gt;the constructions are identical.&lt;/strong&gt; &lt;code&gt;Point(3, 4)&lt;/code&gt; did not ask to be on the heap. The annotation
&lt;code&gt;&amp;amp;Point&lt;/code&gt; is an &lt;em&gt;expectation&lt;/em&gt;, and writing an ordinary construction where a &lt;code&gt;&amp;amp;T&lt;/code&gt; is expected is what
puts the object there.&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-allocation-keyword&quot;&gt;There is no allocation keyword&lt;/h2&gt;
&lt;p&gt;No &lt;code&gt;new&lt;/code&gt;, no &lt;code&gt;malloc&lt;/code&gt;, no &lt;code&gt;Rc::new&lt;/code&gt;, no &lt;code&gt;.clone()&lt;/code&gt;, no wrapper type to learn. The positions that
create a reference are the ones that already state a type — a declared local, a parameter, a return
type, a struct field, an enum variant’s payload:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;
    id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    priority: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Process&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;(id, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;spawned:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p.id)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;spawned: 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The return type says &lt;code&gt;&amp;amp;Process&lt;/code&gt;, so the construction in the body allocates. Somewhere with no
expectation at all, a construction is a value. That is the whole rule.&lt;/p&gt;
&lt;h2 id=&quot;references-are-shared-and-mutable-through-any-alias&quot;&gt;References are shared, and mutable through any alias&lt;/h2&gt;
&lt;p&gt;There is no borrow checker, so there is no exclusivity rule to satisfy. Many references may point at
one object, and any of them may write to it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Account&lt;/span&gt;
    owner: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    balance: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Account&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;deposit&lt;/span&gt;(a: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Account&lt;/span&gt;, amount: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    a.balance += amount

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; shared: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Account&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Account&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; alias = shared

&lt;span class=&quot;hl-function&quot;&gt;deposit&lt;/span&gt;(alias, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;balance:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, shared.balance, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;same object:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, shared == alias)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;balance: 140 same object: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;alias = shared&lt;/code&gt; did not copy the account — it made a second reference to it, and incremented the
count. Compare that with the struct chapter, where &lt;code&gt;b = a&lt;/code&gt; on a value copied it. Same syntax, and
the declared mode is what decides.&lt;/p&gt;
&lt;p&gt;If you are coming from Rust: yes, that is two live mutable aliases, and yes, it is allowed. Handing
that back is the deliberate trade. Reference counting pays for it at run time — a retain here, a
release there — and buys a language you can be productive in on the first day.&lt;/p&gt;
&lt;h2 id=&quot;a-reference-is-never-null&quot;&gt;A reference is never null&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;&amp;amp;T&lt;/code&gt; always points at a live object. There is no null reference to check for and no way to make
one, which removes an entire category of bug rather than diagnosing it.&lt;/p&gt;
&lt;p&gt;Something that may be absent is therefore an &lt;code&gt;Option&lt;/code&gt;, and that is what makes a linked structure
look the way it does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    rest: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Item&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(list: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    list &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(item) -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(item.rest)
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; count&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; last: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; middle: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(last))
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; items: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(middle))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;length:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(items)), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;head:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, items.label)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;length: 3 head: a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;match&lt;/code&gt; is not ceremony around a null check — it is the only way to get at the item, so the
absent case cannot be forgotten.&lt;/p&gt;
&lt;h2 id=&quot;cycles-and-weak&quot;&gt;Cycles, and &lt;code&gt;weak&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Reference counting has one honest weakness: a cycle of strong references keeps itself alive. A
parent holding its children while each child holds its parent is the shape that does it, and it
is common enough to have a purpose-built answer.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;weak T&lt;/code&gt; is a non-owning reference. It does not keep its referent alive, and when the last strong
reference goes away it simply becomes empty:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(n: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n.parent.&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(p) -&amp;gt; p.label
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(none)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; parent_of&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; root: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; child: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, root)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&apos;s parent:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(root))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;child&apos;s parent:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(child))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;root&apos;s parent: (none)
child&apos;s parent: root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading one is a &lt;em&gt;question&lt;/em&gt;, asked with &lt;code&gt;get()&lt;/code&gt;, and the answer is &lt;code&gt;Option[&amp;amp;T]&lt;/code&gt; — a live strong
reference, or &lt;code&gt;None&lt;/code&gt;. So a weak reference can never dangle: by the time you have something to use,
you have proved it is still there.&lt;/p&gt;
&lt;p&gt;There is no operator that makes a weak reference. A &lt;code&gt;&amp;amp;T&lt;/code&gt; becomes one wherever a &lt;code&gt;weak T&lt;/code&gt; is what was
asked for, which above is the struct field. Reach for &lt;code&gt;weak&lt;/code&gt; when you have a genuine cycle, and not
before.&lt;/p&gt;
&lt;h2 id=&quot;when-the-last-reference-goes&quot;&gt;When the last reference goes&lt;/h2&gt;
&lt;p&gt;ARC returns the storage and releases whatever the value held. What it cannot do is close a
descriptor, unmap a region, or hand a handle back to the C library that made it — those live behind a
raw pointer or an integer, and nothing about either says it is owned. &lt;code&gt;impl Drop for T&lt;/code&gt; is where that
is said, once, beside the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;drop&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;closing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.id)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;working&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;working
closing 7
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;defer&lt;/code&gt; (in &lt;a href=&quot;/reference/statements/&quot;&gt;statements&lt;/a&gt;) is the other way to say it, and neither replaces
the other: &lt;code&gt;defer&lt;/code&gt; covers every site a program can &lt;em&gt;name&lt;/em&gt;, and a destructor covers the deaths it
cannot — an element of a container that goes out of scope dies at a point with no expression in the
source. The &lt;a href=&quot;/reference/memory/&quot;&gt;reference&lt;/a&gt; has the four limits, of which the one to know first is
that a destructor runs for a value held behind a &lt;code&gt;&amp;amp;T&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;t-the-way-out&quot;&gt;&lt;code&gt;*T&lt;/code&gt; — the way out&lt;/h2&gt;
&lt;p&gt;The third mode is C’s pointer, and it is exactly as safe as C’s pointer. It is spelled with a sigil
you can grep for, which is the point: the unsafe tier is visible in the source rather than hidden
behind a keyword nobody scans for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(n: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;counter:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, counter)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;counter: 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;x&lt;/code&gt; takes the address of something and &lt;code&gt;*p&lt;/code&gt; reads or writes through a pointer, both as in C.
Nothing is counted, nothing is checked, and a pointer can dangle. In exchange it costs nothing at
all, which is what a device driver, an allocator, or the inside of a data structure sometimes needs.&lt;/p&gt;
&lt;p&gt;A pointer is also how a type reaches &lt;em&gt;itself&lt;/em&gt; without an &lt;code&gt;Option&lt;/code&gt; — and selecting through one needs
no &lt;code&gt;-&amp;gt;&lt;/code&gt;, because there is nothing else &lt;code&gt;.&lt;/code&gt; could mean:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    next: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; third = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; second = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;third)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; first = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;second)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; walk = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;first
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; walk != &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
    total += walk.value
    walk = walk.next

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;chain:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;chain: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; exists for &lt;code&gt;*T&lt;/code&gt; and only for &lt;code&gt;*T&lt;/code&gt;. That is the trade the three modes make explicit: the one
place a null can appear is the one place you asked for C’s rules.&lt;/p&gt;
&lt;h3 id=&quot;volatile-storage-the-program-is-not-the-only-one-writing&quot;&gt;&lt;code&gt;volatile&lt;/code&gt; — storage the program is not the only one writing&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ptr_cast&lt;/code&gt; gets a driver to a register block; it does not get it a &lt;em&gt;correct&lt;/em&gt; one. An optimizer is
entitled to assume that reading the same storage twice gives the same value, that a store nobody
reads is a store nobody needs, and that two accesses in a row may be merged into one wider access.
Every one of those is false at a device, and the last of them is why a poll loop can spin forever on
the first value it read.&lt;/p&gt;
&lt;p&gt;So sysl has C’s qualifier, spelled where C spells it — in the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Gpio&lt;/span&gt;
    input:  volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    output: volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    shadow: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Gpio&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; block = &lt;span class=&quot;hl-type&quot;&gt;Gpio&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0b1010&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; regs: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Gpio&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;block

regs.output = &lt;span class=&quot;hl-number&quot;&gt;0b0110&lt;/span&gt;
regs.shadow = regs.output

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(regs.input, regs.output, regs.shadow)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 6 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;volatile&lt;/code&gt; place is one whose reads and writes are &lt;strong&gt;effects rather than value computations&lt;/strong&gt;, so
the compiler emits exactly the accesses the source wrote, exactly once each, in the order written.&lt;/p&gt;
&lt;p&gt;Two things about it are worth carrying away. It &lt;strong&gt;constrains the compiler, not the machine&lt;/strong&gt; — no
atomicity, no ordering against another core, no protection from a torn read, so a program reaching
for this word to share a counter between threads has written a race with a keyword in front of it.
And it is &lt;strong&gt;per field&lt;/strong&gt;, which is what &lt;code&gt;shadow&lt;/code&gt; above is there to show: a driver keeps ordinary
values beside its registers, and a qualifier on the whole struct would sweep them in and make every
touch of a cached flag an unoptimizable access.&lt;/p&gt;
&lt;p&gt;It also qualifies &lt;strong&gt;storage&lt;/strong&gt;, never a value — which is the rule the spelling follows from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;volatile u32&apos; is the type of *storage*, and this is a value — what a read of a volatile place hands back is an ordinary &apos;u32&apos;. The qualifier goes where the storage is named: a struct field, an element, or the pointee of a &apos;*T&apos;, as &apos;*volatile u32&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What a load hands back is a number, and a number is not somewhere a device can write.&lt;/p&gt;
&lt;h2 id=&quot;ref-a-name-for-a-place&quot;&gt;&lt;code&gt;ref&lt;/code&gt; — a name for a place&lt;/h2&gt;
&lt;p&gt;A place can be deep, and the two ways to shorten one both cost something. &lt;code&gt;var t = self.tasks[i]&lt;/code&gt;
binds a &lt;strong&gt;copy&lt;/strong&gt;, so every read and every write walks the path from the table again.
&lt;code&gt;&amp;amp;self.tasks[i]&lt;/code&gt; gives the name back — and gives up bounds checking, &lt;code&gt;within&lt;/code&gt; checking, invariant
re-checking and the guarantee at the top of this chapter, all in one step.&lt;/p&gt;
&lt;p&gt;That is a cliff rather than a gradient, which is what &lt;code&gt;ref&lt;/code&gt; is for. It binds a name to the place:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bank&lt;/span&gt;
    slot: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; e = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.slot[i]

        e = e + &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Bank&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Bank&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

b.&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.slot[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b.slot[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], b.slot[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 44 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The place is evaluated &lt;strong&gt;once&lt;/strong&gt;, where the binding is written — the index is computed once, the
bounds are checked once — and what the name means afterwards is the storage that was found, not the
expression that found it. A later &lt;code&gt;i += 1&lt;/code&gt; leaves &lt;code&gt;e&lt;/code&gt; naming the element it always named.&lt;/p&gt;
&lt;h3 id=&quot;it-is-a-declaration-never-a-type&quot;&gt;It is a declaration, never a type&lt;/h3&gt;
&lt;p&gt;Which is the whole of why it can exist in a language with no borrow checker. &lt;code&gt;ref&lt;/code&gt; may be written
only as a local declaration: there is no &lt;code&gt;ref&lt;/code&gt; type, so one cannot be a field, a parameter, a return
type, an element, or a type argument. It cannot be captured by a closure, and it does not outlive
the block that declares it.&lt;/p&gt;
&lt;p&gt;That restriction is what keeps the compiler’s knowledge complete. A &lt;code&gt;*T&lt;/code&gt; is a type, so the moment
one exists it can be carried somewhere the compiler has lost the path it came from. A ref never
travels, so the analyzer still holds the place expression, at the point it was written, in the same
body.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At run time a ref stores an address. At compile time it remembers a place.&lt;/strong&gt; Both halves matter.
The address is what makes sixty-five path walks one. The remembered place is what keeps every check
a &lt;code&gt;*T&lt;/code&gt; would have severed — the invariants of every struct the place lies inside, the &lt;code&gt;within&lt;/code&gt; on a
constrained slot, the read-only-ness of storage reached through a &lt;code&gt;val&lt;/code&gt;, and the bounds check the
subscript owed.&lt;/p&gt;
&lt;p&gt;So a ref is &lt;strong&gt;not a fourth memory mode&lt;/strong&gt;. It introduces no representation, no new type, and nothing
that can be stored: it is a second way to &lt;em&gt;say&lt;/em&gt; a place the three modes already describe.&lt;/p&gt;
&lt;h3 id=&quot;what-may-be-written&quot;&gt;What may be written&lt;/h3&gt;
&lt;p&gt;A ref’s initializer must be a &lt;strong&gt;place&lt;/strong&gt;. A call result has no address, so there is nothing for the
name to mean:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; x = &lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;()

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;ref&apos; names a place — a local, a field, an element, or a dereference — and this expression has no address for &apos;x&apos; to name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A ref inherits the place’s writability and gets no modifier of its own — so a ref into a &lt;code&gt;val&lt;/code&gt; may
be read and not written, exactly as the &lt;code&gt;val&lt;/code&gt; may. Stating it twice would only create the chance to
state it wrong.&lt;/p&gt;
&lt;p&gt;Note also that this is the &lt;em&gt;built-in&lt;/em&gt; subscript. A user type’s &lt;code&gt;b[i]&lt;/code&gt; goes through the &lt;code&gt;Index&lt;/code&gt;
trait, which is a call rather than a walk to an address, so there is no place there for a ref to
name.&lt;/p&gt;
&lt;h3 id=&quot;the-one-rule-what-may-move-underneath-it&quot;&gt;The one rule: what may move underneath it&lt;/h3&gt;
&lt;p&gt;A stored address is only as good as the storage staying where it is. C# has ref locals and needs no
rule like this, because a tracing collector keeps the old array alive when the variable is pointed
at a new one; sysl has no collector in this tier, so the same program would dangle:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;
    cell: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; e = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]

        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Table&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

t.&lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;e&apos; is a &apos;ref&apos; standing on storage this assignment would release, so the name would be left pointing at freed memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;While a ref is live, no step of its place that could come to name different storage may be
assigned, and no mutating method may be called on a prefix of one.&lt;/strong&gt; The check is local and decided
from types alone; it never asks where the ref is &lt;em&gt;used&lt;/em&gt;, which is the question that would need
lifetimes.&lt;/p&gt;
&lt;p&gt;The second half is the one that catches a call rather than an assignment. A &lt;code&gt;*self&lt;/code&gt; method may write
any part of its receiver, so a live ref into that receiver is refused the call — whether or not that
particular method reassigns anything, because deciding otherwise would mean reading the callee’s
body, and a module compiles against its imports’ signatures and never their bodies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;
    cell: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;grow&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Table&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

&lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; e = t.cell[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

t.&lt;span class=&quot;hl-function&quot;&gt;grow&lt;/span&gt;()

e = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;e&apos; is a &apos;ref&apos; standing on storage this call could release, since a &apos;*self&apos; method may write its receiver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which steps are hazards falls out of the model rather than being a list, and the discriminator is
&lt;strong&gt;ownership&lt;/strong&gt;, not indirection. Only a step that &lt;em&gt;releases&lt;/em&gt; something when it is overwritten can
strand a ref:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/strong&gt; step and a &lt;strong&gt;view&lt;/strong&gt; step are hazards, because overwriting either drops what it held and
that release may be the last;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;&lt;code&gt;*T&lt;/code&gt;&lt;/strong&gt; step is &lt;strong&gt;not&lt;/strong&gt;. A raw pointer owns nothing, so &lt;code&gt;p = q&lt;/code&gt; frees nothing and the storage a
ref found through it stays exactly as alive as it was — no more, and no less;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;field, a fixed array, or an element of one&lt;/strong&gt; is not either: that storage &lt;em&gt;is&lt;/em&gt; the enclosing
object’s bytes, so assigning to it overwrites the bytes rather than moving them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;*T&lt;/code&gt; exclusion is not a concession, it is what makes the feature usable where it is wanted most.
A program that reaches its tables through a &lt;code&gt;*Self&lt;/code&gt; receiver has no owning step anywhere in the
chain, so it is asked for nothing at all — every &lt;code&gt;self.…()&lt;/code&gt; call stays legal, and the ref costs it
exactly nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;
    state: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    prio: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Task&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Kernel&lt;/span&gt;
    tasks: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;advance&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; t = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tasks[i]

        t.state = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
        t.prio = t.prio + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Kernel&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; k = &lt;span class=&quot;hl-type&quot;&gt;Kernel&lt;/span&gt;([&lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;); &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])

k.&lt;span class=&quot;hl-function&quot;&gt;advance&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(k.tasks[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].state, k.tasks[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].prio, k.tasks[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;].prio)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 8 7
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-ref-to-a-slot-that-holds-a-reference&quot;&gt;A ref to a slot that holds a reference&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ref r = self.node&lt;/code&gt;, where &lt;code&gt;node&lt;/code&gt; is a &lt;code&gt;&amp;amp;Node&lt;/code&gt;, names the &lt;strong&gt;slot&lt;/strong&gt; and not the object in it. So the
binding takes no count — nothing new holds the object — and &lt;code&gt;r = other&lt;/code&gt; is the assignment
&lt;code&gt;self.node = other&lt;/code&gt; by another name, releasing what was there and retaining what arrives, in that
order.&lt;/p&gt;
&lt;p&gt;The distinction matters because the other reading is available and wrong: if binding retained, a ref
would be a &lt;code&gt;&amp;amp;T&lt;/code&gt; with extra steps, and the count it took would keep an object alive past the write
that replaced it.&lt;/p&gt;
&lt;h3 id=&quot;where-it-comes-from&quot;&gt;Where it comes from&lt;/h3&gt;
&lt;p&gt;The form is old, and none of the languages this tour has been comparing itself to have it — Swift,
Kotlin, Scala and Go are all silent. &lt;strong&gt;Ada’s &lt;code&gt;renames&lt;/code&gt;&lt;/strong&gt; is the general case and evaluates the name
once at the declaration; &lt;strong&gt;Fortran’s &lt;code&gt;ASSOCIATE&lt;/code&gt;&lt;/strong&gt; is the closest in shape, being block-scoped and
deliberately not a type; &lt;strong&gt;C#’s &lt;code&gt;ref&lt;/code&gt; locals&lt;/strong&gt; are the closest in spelling. C# also shows what the
restriction is worth: having added ref returns and ref fields, it spent several releases building
the escape analysis that keeping the form local avoids entirely.&lt;/p&gt;
&lt;p&gt;Scala’s by-name parameter is the thing this is &lt;em&gt;not&lt;/em&gt;. &lt;code&gt;x: =&amp;gt; T&lt;/code&gt; re-evaluates at every use; a ref
evaluates once and remembers what it found.&lt;/p&gt;
&lt;h2 id=&quot;what-this-costs&quot;&gt;What this costs&lt;/h2&gt;
&lt;p&gt;Less than you would think, because the compiler knows when counting is pointless. A local that
never escapes its frame is not heap-allocated at all; a closure that does not outlive its frame is
inlined rather than boxed; a slice of a local array stays on the stack when nothing takes a view of
it away. You do not annotate any of that, and you cannot get it wrong — try to return a view of a
local buffer and the compiler will tell you.&lt;/p&gt;
&lt;p&gt;What remains is a retain and a release at the points where a reference is genuinely shared. That is
the price of not having to prove anything to a borrow checker, and it is the trade the whole
language is built around.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/arrays/&quot;&gt;arrays and slices&lt;/a&gt; — two types that lean on everything in this chapter.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Memory</title>
    <link href="https://sysl.sh/reference/memory/"/>
    <id>https://sysl.sh/reference/memory/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The three modes, ARC, weak references, places and `ref`, escape analysis, the raw tier, and device memory.</summary>
    <content type="html">&lt;p&gt;Every value in a sysl program lives in one of three ways, and the declaration that names it is what
says which. This page is the whole of that model: what each mode costs, what it guarantees, how a
reference is made, when storage moves without being asked, and where the guarantees stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you do not write &lt;code&gt;*T&lt;/code&gt;, you cannot segfault.&lt;/strong&gt; The safe subset — values, references, weak
references, arrays, and slices — has no use-after-free, no null dereference, no out-of-bounds access,
and no dangling pointer. The single unsafe primitive is the raw pointer, and it is &lt;strong&gt;greppable&lt;/strong&gt;: a
program’s exposure to C’s hazards is exactly the lines with a &lt;code&gt;*&lt;/code&gt; in the type. A driver has them and
an application does not, and you can tell which by looking.&lt;/p&gt;
&lt;h2 id=&quot;the-three-modes&quot;&gt;The three modes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;mode&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;th&gt;who frees it&lt;/th&gt;&lt;th&gt;needs an allocator&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value — on the stack, in a register, or inline in something bigger&lt;/td&gt;&lt;td&gt;nobody; it goes when its frame or its container does&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a counted reference to a heap object&lt;/td&gt;&lt;td&gt;the compiler, when the last reference goes&lt;/td&gt;&lt;td&gt;to &lt;strong&gt;make&lt;/strong&gt; one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a raw machine pointer&lt;/td&gt;&lt;td&gt;you&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; here = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; shared: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; raw: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;here

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(here.x, shared.x, raw.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 3 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The choice is per declaration, not per type.&lt;/strong&gt; The same &lt;code&gt;struct Point&lt;/code&gt; is a value in the first
line, a heap object in the second, and a pointer’s target in the third. This is C’s arrangement
rather than Swift’s or Scala’s, where a type is &lt;code&gt;struct&lt;/code&gt; or &lt;code&gt;class&lt;/code&gt; once and for all, and systems
code depends on it: a page-table entry, a temporary in a loop, and a shared configuration object may
all be the same type held three ways.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Value is the unmarked default, and the kernel is why.&lt;/strong&gt; A module that has given up the allocator
cannot &lt;em&gt;make&lt;/em&gt; a reference. If the reference were the bare default, the unmarked spelling would be
the one that is illegal exactly where value semantics matter most — every kernel struct would need a
mark, and would hit “references need an allocator” on its most natural form. With value as the
default, &lt;code&gt;T&lt;/code&gt; is usable in both worlds, &lt;code&gt;*T&lt;/code&gt; covers pointers, and &lt;code&gt;&amp;amp;T&lt;/code&gt; appears in allocator-free code
only where something else handed one over.&lt;/p&gt;
&lt;h2 id=&quot;t-values&quot;&gt;&lt;code&gt;T&lt;/code&gt; — values&lt;/h2&gt;
&lt;p&gt;A value lives inline: in a stack slot, in a register, or embedded in the struct or array that
contains it. &lt;strong&gt;Assignment and argument passing copy it&lt;/strong&gt;, exactly as in C.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Counter&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a

b.n = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.n, b.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is &lt;strong&gt;no move semantics and no use-after-move&lt;/strong&gt;. &lt;code&gt;a&lt;/code&gt; is still a whole &lt;code&gt;Counter&lt;/code&gt; after &lt;code&gt;b = a&lt;/code&gt;,
and it always will be — the concept of a value that has been given away does not exist here, so
neither does the class of error built on it.&lt;/p&gt;
&lt;p&gt;A value containing a &lt;code&gt;&amp;amp;T&lt;/code&gt; field is still a value: copying it &lt;strong&gt;retains&lt;/strong&gt; that field, so the copy is
independently safe and the original is untouched. That is the one thing a copy does beyond moving
bytes, and it is what makes “values are simple” true rather than approximately true.&lt;/p&gt;
&lt;p&gt;Values need no allocator and are always safe.&lt;/p&gt;
&lt;h2 id=&quot;t-counted-references&quot;&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt; — counted references&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;&amp;amp;T&lt;/code&gt; is a reference to a heap object managed by &lt;strong&gt;ARC&lt;/strong&gt;: the compiler emits the retains and
releases, and the object is destroyed the moment the last strong reference to it goes away. It is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;shared and freely aliased&lt;/strong&gt; — many references may point at one object;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mutable through any alias&lt;/strong&gt; — there is no borrow checker and no exclusivity rule;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;non-null&lt;/strong&gt; — a &lt;code&gt;&amp;amp;T&lt;/code&gt; always points at a live object;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;automatically managed&lt;/strong&gt; — no &lt;code&gt;free&lt;/code&gt;, and no place to forget one.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Counter&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a

b.n = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.n, b.n, a == b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;99 99 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compare that with the value example above: &lt;strong&gt;the same two lines, and the declared mode is the only
difference.&lt;/strong&gt; &lt;code&gt;b = a&lt;/code&gt; copied a &lt;code&gt;Counter&lt;/code&gt; there and made a second reference here.&lt;/p&gt;
&lt;p&gt;Two live mutable aliases is what Rust exists to prevent, and permitting them is the deliberate
trade. Reference counting pays for it at run time — a retain here, a release there — and buys a
language with no lifetimes, no borrow checker, and nothing to prove to a checker as you write.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;References compare by address.&lt;/strong&gt; &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt; on a reference or a pointer ask whether the two
name the same object, which is the only question a bare address can answer, and there is no ordering
on either.&lt;/p&gt;
&lt;h3 id=&quot;there-is-no-allocation-keyword&quot;&gt;There is no allocation keyword&lt;/h3&gt;
&lt;p&gt;A reference is made by writing an ordinary construction &lt;strong&gt;where a &lt;code&gt;&amp;amp;T&lt;/code&gt; is expected&lt;/strong&gt;. The expectation
is what puts the object on the heap:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;
    id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    priority: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Process&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;(id, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-function&quot;&gt;spawn&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-type&quot;&gt;Process&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.id, q.id, v.id)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 8 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Process(id, 0)&lt;/code&gt; in the body allocates because the return type says &lt;code&gt;&amp;amp;Process&lt;/code&gt;. &lt;code&gt;Process(8, 1)&lt;/code&gt;
allocates because the annotation says so. &lt;code&gt;Process(9, 2)&lt;/code&gt; does not, because nothing asked — with no
expectation at all, a construction is a value.&lt;/p&gt;
&lt;p&gt;No &lt;code&gt;new&lt;/code&gt;, no &lt;code&gt;malloc&lt;/code&gt;, no &lt;code&gt;Rc::new&lt;/code&gt;, no &lt;code&gt;.clone()&lt;/code&gt;, and no wrapper type. The positions that fix the
expectation are the ones that already state a type for generic inference:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;position&lt;/th&gt;&lt;th&gt;example&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a declared local&lt;/td&gt;&lt;td&gt;&lt;code&gt;var p: &amp;amp;Point = Point(1, 2)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a parameter&lt;/td&gt;&lt;td&gt;&lt;code&gt;f(p: &amp;amp;Point)&lt;/code&gt;, called as &lt;code&gt;f(Point(1, 2))&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a return type&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&amp;gt; &amp;amp;Point&lt;/code&gt;, with a construction as the result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a struct field&lt;/td&gt;&lt;td&gt;&lt;code&gt;Item(&amp;quot;a&amp;quot;, Node(1))&lt;/code&gt; where the field is &lt;code&gt;&amp;amp;Node&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an enum variant’s payload&lt;/td&gt;&lt;td&gt;&lt;code&gt;Some(Node(1))&lt;/code&gt; where the payload is &lt;code&gt;&amp;amp;Node&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;An element of an array or slice, a part of a tuple, a generic argument, and a parameter of a callable
type all ask the same way. &lt;strong&gt;The rule is about the types and not about the syntax&lt;/strong&gt;: a &lt;code&gt;T&lt;/code&gt; written
where a &lt;code&gt;&amp;amp;T&lt;/code&gt; is expected goes on the heap, whatever produced it.&lt;/p&gt;
&lt;p&gt;A prefix &lt;code&gt;&amp;amp;&lt;/code&gt; on a construction was considered as an explicit mark and not taken — it would collide
with address-of, which is a different operation producing a different type.&lt;/p&gt;
&lt;h3 id=&quot;the-expectation-reaches-each-branch&quot;&gt;The expectation reaches each branch&lt;/h3&gt;
&lt;p&gt;An &lt;code&gt;if&lt;/code&gt;, a &lt;code&gt;match&lt;/code&gt;, and a loop yield their value through their branches, so a &lt;code&gt;&amp;amp;T&lt;/code&gt; expectation
reaches &lt;strong&gt;each branch on its own&lt;/strong&gt; rather than the expression as a whole:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; origin: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; far = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; far &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; origin

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.x, p.y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is what lets a value branch and an already-reference branch meet at &lt;code&gt;&amp;amp;Point&lt;/code&gt;. Boxing the whole
expression instead would fail, because a branch that is already a &lt;code&gt;&amp;amp;Point&lt;/code&gt; cannot un-become a value —
something that is already a reference passes through untouched.&lt;/p&gt;
&lt;p&gt;It is also what lets a scalar be referenced without &lt;code&gt;int&lt;/code&gt; needing a constructor of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-reference-is-never-null&quot;&gt;A reference is never null&lt;/h3&gt;
&lt;p&gt;There is no null in the safe subset and no way to make one, so there is no null dereference to
diagnose. Something that may be absent is an &lt;code&gt;Option[&amp;amp;T]&lt;/code&gt;, and getting at it is a &lt;code&gt;match&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Item&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(o: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    o &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(i) -&amp;gt; i.label
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(none)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; it: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Item&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(it)), &lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a (none)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;match&lt;/code&gt; is not ceremony around a null check. It is the only route to the item, so the absent case
cannot be forgotten rather than merely being unwise to forget.&lt;/p&gt;
&lt;h3 id=&quot;what-a-heap-object-costs&quot;&gt;What a heap object costs&lt;/h3&gt;
&lt;p&gt;Every ARC object carries &lt;strong&gt;three header words&lt;/strong&gt;: the strong count, a pointer to the function that
destroys it, and a weak count. Release decrements the strong count; at zero it calls through the
hook, which releases whatever the payload holds and returns the storage to the heap the object came
from — &lt;a href=&quot;/reference/packages/#one-heap-and-the-package-that-names-it&quot;&gt;one heap for the whole program&lt;/a&gt;,
libc’s unless a package named another pair.&lt;/p&gt;
&lt;p&gt;Putting the destructor behind a hook rather than inline at each release site is what makes letting go
of a reference &lt;strong&gt;type-erased&lt;/strong&gt; — one instruction sequence, no static type. Slices need exactly that,
since a &lt;code&gt;[]T&lt;/code&gt; gives no clue what type of object its owner word points at.&lt;/p&gt;
&lt;p&gt;One word per object buys three things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ARC works the same everywhere.&lt;/strong&gt; A module that never allocates can still retain and release,
because the free path calls back into the heap the object came from. The operations are a few
instructions and depend on no runtime.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Several heaps coexist.&lt;/strong&gt; A kernel heap, a server’s heap, and an arena are different allocators,
and an object frees itself into the one that made it, wherever it is dropped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There is no boundary rule to learn.&lt;/strong&gt; Ownership crosses an allocator-free edge like any other
value.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Teardown is iterative, so depth is bounded.&lt;/strong&gt; Destroying the head of a long chain of references
would recurse one frame per node if a destructor called the next destructor. It does not: an object
whose count reaches zero is pushed onto a worklist, reusing its now-dead refcount slot as the link,
and the first release to hit zero drains the list in a loop. A structure of any depth comes apart in
O(1) stack. The worklist is &lt;strong&gt;per thread&lt;/strong&gt;, because it is scratch space a drain uses rather than
state anything shares.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a freestanding target the worklist is asked for rather than assumed&lt;/strong&gt;, since there is no thread
pointer to key it on. A &lt;code&gt;&amp;amp;sync&lt;/code&gt; release that reaches zero fetches it through one weak symbol,
&lt;code&gt;__sysl_arc_reaper&lt;/code&gt;, which answers with a &lt;code&gt;head&lt;/code&gt; pointer and a &lt;code&gt;draining&lt;/code&gt; flag belonging to the
running task:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;struct sysl_arc_reaper { void *head; unsigned char draining; };

/* FreeRTOS, say: whatever this runtime keeps per task. The storage is the port&apos;s to give out and
   must last as long as the task — set when the task is created, never shared with another:

       static struct sysl_arc_reaper slots[MAX_TASKS];
       vTaskSetThreadLocalStoragePointer(task, 0, &amp;amp;slots[n]);            */
struct sysl_arc_reaper *__sysl_arc_reaper(void) {
    return pvTaskGetThreadLocalStoragePointer(NULL, 0);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Define nothing and the program uses the single slot it carries, which is right for a machine where
nothing schedules — the overwhelming case, and why the symbol is weak. Define it in an RTOS port and
&lt;code&gt;&amp;amp;sync T&lt;/code&gt; means on that target what it means everywhere else. This is the arrangement &lt;code&gt;&amp;amp;sync&lt;/code&gt;‘s
counts are already under there: with no &lt;code&gt;ldrex&lt;/code&gt;/&lt;code&gt;strex&lt;/code&gt; beneath it an atomic increment becomes a call
to an &lt;code&gt;__atomic_*&lt;/code&gt; the board defines, and on a two-core part that needs a hardware spinlock.&lt;/p&gt;
&lt;p&gt;The header is the same three words for every object whether or not anything weakly references it,
which is what keeps the type-erased release path expressible at all. The cost is eight bytes on an
allocation that already cost a &lt;code&gt;malloc&lt;/code&gt;, and it lands only where the feature is used: values, fixed
arrays, and &lt;code&gt;*T&lt;/code&gt; buffers have no header, so allocator-free code pays nothing for a mechanism it never
touches.&lt;/p&gt;
&lt;h2 id=&quot;weak-t-breaking-cycles&quot;&gt;&lt;code&gt;weak T&lt;/code&gt; — breaking cycles&lt;/h2&gt;
&lt;p&gt;Reference counting has one honest weakness: a cycle of strong references keeps itself alive. A parent
holding its children while each child holds its parent is the shape that does it, and it is common
enough in systems code — a back-link in an intrusive list, a process’s pointer to its parent — to
have a purpose-built answer.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;weak T&lt;/code&gt; does not keep its referent alive.&lt;/strong&gt; When the last strong reference goes, the object is
destroyed and every weak reference to it becomes empty.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(n: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n.parent.&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(p) -&amp;gt; p.label
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(none)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; root: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; kid: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;kid&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, root)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(root), &lt;span class=&quot;hl-function&quot;&gt;parent_of&lt;/span&gt;(kid))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;(none) root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;weak T&lt;/code&gt; is a type, not an operator.&lt;/strong&gt; There is nothing that makes one; a &lt;code&gt;&amp;amp;T&lt;/code&gt; becomes a &lt;code&gt;weak T&lt;/code&gt;
wherever a &lt;code&gt;weak T&lt;/code&gt; is what the context asked for — the struct field above, an argument, a declared
local, a returned value. That is the same rule that makes a &lt;code&gt;&amp;amp;T&lt;/code&gt; out of a &lt;code&gt;T&lt;/code&gt;, so both &lt;code&gt;&amp;amp;&lt;/code&gt; and &lt;code&gt;weak&lt;/code&gt;
live at the boundaries a program annotates and neither appears in a body.&lt;/p&gt;
&lt;p&gt;The conversion goes one way. A &lt;code&gt;weak T&lt;/code&gt; is not a &lt;code&gt;&amp;amp;T&lt;/code&gt; and never silently becomes one, because
becoming one is the operation that can fail.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;&amp;amp;&lt;/code&gt; is in the mode already, so &lt;code&gt;weak &amp;amp;T&lt;/code&gt; is the word said twice&lt;/strong&gt; — and it is refused rather
than read as a weak edge to a box holding a reference, which is not a thing sysl has:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = r&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;weak Node&apos; is already a weak edge to a counted Node, so the &apos;&amp;amp;&apos; says the mode a second time — write &apos;weak Node&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Reading one is a question, and it is &lt;code&gt;get()&lt;/code&gt;.&lt;/strong&gt; The answer is &lt;code&gt;Option[&amp;amp;T]&lt;/code&gt;: a live strong reference
with a count taken for the caller, or &lt;code&gt;None&lt;/code&gt;. Nothing else may be done to a weak reference — no field
selection, no method call, no &lt;code&gt;==&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; root: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; kid: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;kid&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, root)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(kid.parent.label)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;may be gone, so nothing is read off one directly
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every road to the object goes through the &lt;code&gt;Option&lt;/code&gt;, which is what makes “a weak reference never
dangles” a fact about the language rather than a promise about the programmer.&lt;/p&gt;
&lt;p&gt;The parentheses are not decoration. &lt;code&gt;.len&lt;/code&gt; is a &lt;strong&gt;property&lt;/strong&gt; — a fact about the value, the same answer
every time it is asked — while &lt;code&gt;get()&lt;/code&gt; is a &lt;strong&gt;question about the world&lt;/strong&gt;: two calls a moment apart may
disagree, and the answer costs a count. sysl puts the parentheses on the second kind.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An empty weak reference is written &lt;code&gt;None&lt;/code&gt;&lt;/strong&gt;, and it is the same state whether the object is gone or
there never was one. This &lt;code&gt;None&lt;/code&gt; is not an &lt;code&gt;Option&lt;/code&gt; — it is the empty value of the weak reference
itself, chosen because it is exactly what &lt;code&gt;get()&lt;/code&gt; will hand back for it.&lt;/p&gt;
&lt;p&gt;It is also the &lt;strong&gt;zero value&lt;/strong&gt; of &lt;code&gt;weak T&lt;/code&gt;, which is the one place &lt;code&gt;weak T&lt;/code&gt; parts company with &lt;code&gt;&amp;amp;T&lt;/code&gt;:
there is no such thing as a reference to nothing, so &lt;code&gt;&amp;amp;T&lt;/code&gt; has no zero. A struct with a weak field
therefore still has one, and an uninitialized declaration of it is still a declaration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;

n.parent.&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(p) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;held&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;empty
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A weak reference may not be made from a value with nowhere else to live.&lt;/strong&gt; Constructing into a weak
position would box the value and then weaken it, leaving the weak edge as the object’s only holder —
and the object dead before the statement ended:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; kid: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;kid&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(kid.label)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a weak reference does not keep Node alive, and nothing else here holds this one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The only default a &lt;code&gt;weak T&lt;/code&gt; parameter can have is &lt;code&gt;None&lt;/code&gt;&lt;/strong&gt;, and that falls out rather than being
decided. A default is produced afresh at each call that omits it, in a scope holding none of the
caller’s locals, so what it names would have to outlive every frame — and every candidate that names
an &lt;em&gt;object&lt;/em&gt; is closed off. A construction is refused by the rule above; a top-level &lt;code&gt;var&lt;/code&gt; is a local
of the entry point; and a module-level &lt;code&gt;val&lt;/code&gt; counts nothing, which a reference does. What is left is
the one value that holds nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;adopt&lt;/span&gt;(child: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, parent: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    parent.&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(p) -&amp;gt; child + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; of &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + p.label
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; child + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; of nobody&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; root: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;adopt&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;adopt&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, root))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a of nobody b of root
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;weak sync T&lt;/code&gt; is refused&lt;/strong&gt;, naming the concurrency chapter. Upgrading an atomic weak reference is a
compare-and-swap loop against a count another thread may be driving to zero underneath it, and that
is written when there is something to race with.&lt;/p&gt;
&lt;p&gt;Everything a &lt;code&gt;&amp;amp;T&lt;/code&gt; may point at, a &lt;code&gt;weak T&lt;/code&gt; may be taken of: a struct, a scalar, an array, a generic
instantiation, a trait object, and a type parameter.&lt;/p&gt;
&lt;h2 id=&quot;t-the-raw-pointer&quot;&gt;&lt;code&gt;*T&lt;/code&gt; — the raw pointer&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;*T&lt;/code&gt; is a bare machine pointer, exactly like C’s: no length, no count, no checks, manual lifetime. It
is the only unsafe primitive over data, it needs no runtime, and it is how a kernel, a driver, or an
allocator’s own internals are written.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(n: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counter = &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;counter)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counter)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Anything C can do through a pointer, sysl can.&lt;/strong&gt; The pointer is where the language’s guarantees
stop, so it carries C’s whole surface rather than a safer subset of it — a subset would only mean a
kernel that could not be written here.&lt;/p&gt;
&lt;h3 id=&quot;null-exists-and-only-here&quot;&gt;&lt;code&gt;null&lt;/code&gt; exists, and only here&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; is the absent raw pointer. It has no type of its own and takes the &lt;code&gt;*T&lt;/code&gt; its context expects,
the way a bare &lt;code&gt;None&lt;/code&gt; takes its type argument:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    next: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; third = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; second = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;third)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; first = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;second)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; walk = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;first
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; walk != &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
    total += walk.value
    walk = walk.next

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program is also the answer to “how does a type reach itself” — see &lt;a href=&quot;#recursive-types&quot;&gt;recursive
types&lt;/a&gt; below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A generic parameter is a context like any other, and it answers late.&lt;/strong&gt; A callee still being
solved has no type at that position yet, so an argument with none of its own is set aside until the
ones that have have been read, and is then taken against the parameter it turned out to stand at:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = a == b

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;x, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;x))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Either order answers alike, because waiting is not queueing. Setting an argument aside cannot lose
the solution — one with no type of its own has nothing to contribute to it — so the parameter is
settled by the other arguments or by nothing at all. &lt;strong&gt;Nothing at all is refused rather than
defaulted&lt;/strong&gt;: a call with no other argument to read is asked what the pointer points at.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;null&apos; takes its type from its context, and there is none here
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;arithmetic-two-directions-one-spelling-each&quot;&gt;Arithmetic: two directions, one spelling each&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; buf: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;60&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;70&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;80&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; base = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;buf[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; third = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;buf[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;third, third - base, base - third, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;base[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;30 2 -2 40
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;p - q&lt;/code&gt; between two pointers of the same pointee is an &lt;code&gt;isize&lt;/code&gt;, and it counts elements&lt;/strong&gt;, not bytes
— C’s &lt;code&gt;ptrdiff_t&lt;/code&gt;. It is signed because the order of the operands is the programmer’s, and it is the
exact inverse of &lt;code&gt;&amp;amp;p[n]&lt;/code&gt;: indexing takes an address and a count to an address, and the difference
takes two addresses back to a count, both striding by the pointee.&lt;/p&gt;
&lt;p&gt;It is here because the interior-pointer half of libc needs it. &lt;code&gt;memchr&lt;/code&gt;, &lt;code&gt;strchr&lt;/code&gt;, &lt;code&gt;strrchr&lt;/code&gt;,
&lt;code&gt;strstr&lt;/code&gt; and &lt;code&gt;memmem&lt;/code&gt; all hand back a pointer &lt;em&gt;into&lt;/em&gt; a buffer the caller owns, and without a
difference every one of them is callable and useless, because nothing could turn the answer into an
index.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Offsetting stays &lt;code&gt;&amp;amp;p[n]&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;p + n&lt;/code&gt; is not spelled, deliberately: indexing already exists and
already strides by the pointee, and a second spelling for one address would be a second thing to keep
in step. &lt;code&gt;p + q&lt;/code&gt; names no address and is refused too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two pointers of different pointee types have no shared element to count&lt;/strong&gt;, and are refused by the
ordinary matching-types rule rather than by one of this operator’s own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-string&quot;&gt;&apos;x&apos;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pn = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;n
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pc = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;c

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(pn - pc)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;-&apos; needs matching types, got *int and *char
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A counted &lt;code&gt;&amp;amp;T&lt;/code&gt; has no arithmetic at all&lt;/strong&gt;, keeping the equality it always had and nothing more:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a - b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;operator &apos;-&apos; is not defined for &amp;amp;Point
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arithmetic is a property of the unsafe mode, not of holding an address.&lt;/p&gt;
&lt;p&gt;Whether two pointers into unrelated objects may be subtracted is the programmer’s business, as &lt;code&gt;p[i]&lt;/code&gt;
past the end already is.&lt;/p&gt;
&lt;h3 id=&quot;bounds-safety-follows-length-not-pointers&quot;&gt;Bounds safety follows length, not pointers&lt;/h3&gt;
&lt;p&gt;The out-of-bounds hazard is governed by whether a value &lt;strong&gt;carries its length&lt;/strong&gt;, independently of
where it was allocated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;arrays and slices carry their length&lt;/strong&gt;, so indexing is bounds-checked in every context — hosted
or allocator-free, over static, stack, or heap memory;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;*T&lt;/code&gt; carries no length&lt;/strong&gt;, so it is the one unchecked primitive. &lt;code&gt;p[i]&lt;/code&gt; reads the &lt;code&gt;i&lt;/code&gt;th element
and &lt;code&gt;p[0..&amp;lt;n]&lt;/code&gt; views &lt;code&gt;n&lt;/code&gt; of them, both exactly as C does and both unchecked, because there is no
length to check against and supplying one is the programmer’s assertion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So even low-level, allocator-free code stays bounds-safe by &lt;em&gt;choosing&lt;/em&gt; slices, and reaches for &lt;code&gt;*T&lt;/code&gt;
where it must — an MMIO window, a page table, a buffer a C function filled. That choice is the point.&lt;/p&gt;
&lt;h2 id=&quot;places&quot;&gt;Places&lt;/h2&gt;
&lt;p&gt;A &lt;strong&gt;place&lt;/strong&gt; is something with an address: a local or parameter, a dereference, an &lt;strong&gt;element&lt;/strong&gt;, and a
field of any of them. Everything else — a call result, an arithmetic result, a freshly built struct —
is a value with no address to take.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;operation&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;place&lt;/code&gt;&lt;/td&gt;&lt;td&gt;yields a &lt;strong&gt;&lt;code&gt;*T&lt;/code&gt;&lt;/strong&gt; — C’s address-of, with C’s result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*p&lt;/code&gt;&lt;/td&gt;&lt;td&gt;reads through a &lt;code&gt;*T&lt;/code&gt; or a &lt;code&gt;&amp;amp;T&lt;/code&gt;, and is itself a place&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;p.f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;selects, dereferencing &lt;strong&gt;one&lt;/strong&gt; level automatically on both &lt;code&gt;*T&lt;/code&gt; and &lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; on a place yields a raw pointer, never a reference.&lt;/strong&gt; A place lives in a frame or inside
another object, so there is no count to take a share of. Reaching a &lt;code&gt;&amp;amp;T&lt;/code&gt; means being handed one or
constructing one, and taking the address of a local is therefore inherently in the unsafe tier —
which is right, because it can dangle and nothing promotes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Selection is the only implicit dereference.&lt;/strong&gt; &lt;code&gt;p.x&lt;/code&gt; is &lt;code&gt;(*p).x&lt;/code&gt; and &lt;code&gt;p.x = 9&lt;/code&gt; writes through the
pointer — Go’s rule, with no &lt;code&gt;-&amp;gt;&lt;/code&gt;. Matching a reference to an enum against its variants is &lt;code&gt;match *e&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The shorthand stops at one level&lt;/strong&gt;, so reaching through a &lt;code&gt;**T&lt;/code&gt; is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pp = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;p
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ppp = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;pp

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(pp.x, (&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;ppp).x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leaving the step out is a diagnostic rather than a second implicit dereference, and it says how many
levels are left:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pp = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;p
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ppp = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;pp

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(ppp.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;selection reaches through one level of indirection and **Point has more
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Assignment, compound assignment, and &lt;code&gt;++&lt;/code&gt;/&lt;code&gt;--&lt;/code&gt; all take a place, so the same three forms work on a
variable, on a field, and through a pointer with nothing special said about any of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An element carries one wrinkle the other three do not.&lt;/strong&gt; A slice’s elements and a pointer’s live
wherever the storage is, which is somewhere the expression naming them is not, so they have an
address whether or not the expression naming them does. That is what makes &lt;code&gt;rows(g)[i] = v&lt;/code&gt; write
through to the grid rather than into the view the call handed back. An &lt;strong&gt;array’s&lt;/strong&gt; elements &lt;em&gt;are&lt;/em&gt; the
array, so they are places exactly when the array is. A string’s bytes are never one: writing a byte
of UTF-8 is how a string stops being UTF-8, and that is refused as immutability rather than as the
absence of an address.&lt;/p&gt;
&lt;p&gt;The hazard on the other side of that rule is the one dangle a &lt;strong&gt;single statement&lt;/strong&gt; can produce. If a
temporary view is the only holder of its buffer, the buffer is released at the end of the statement,
and &lt;code&gt;&amp;amp;f()[i]&lt;/code&gt; is a pointer to freed storage before the next line runs. That is the unsafe tier
behaving as advertised — &lt;code&gt;&amp;amp;&lt;/code&gt; yields a raw pointer, a raw pointer can dangle, nothing promotes it —
and it is called out because every other dangle needs the pointer to be carried somewhere first.&lt;/p&gt;
&lt;h2 id=&quot;ref-a-name-for-a-place&quot;&gt;&lt;code&gt;ref&lt;/code&gt; — a name for a place&lt;/h2&gt;
&lt;p&gt;A place can be deep, and until &lt;code&gt;ref&lt;/code&gt; the two ways to shorten one both cost something.
&lt;code&gt;var t = self.tasks[i]&lt;/code&gt; binds a &lt;strong&gt;copy&lt;/strong&gt;, so every read and every write walks the path from the table
again; &lt;code&gt;&amp;amp;self.tasks[i]&lt;/code&gt; gives the name back and gives up bounds checking, &lt;code&gt;within&lt;/code&gt; checking,
invariant re-checking, and the guarantee at the top of this page, all in one step. That is a cliff
rather than a gradient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ref&lt;/code&gt; binds a name to a place.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;
    state: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    prio: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Task&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Kernel&lt;/span&gt;
    tasks: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;advance&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; t = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.tasks[i]

        t.state = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
        t.prio = t.prio + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Kernel&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; k = &lt;span class=&quot;hl-type&quot;&gt;Kernel&lt;/span&gt;([&lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;); &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])

k.&lt;span class=&quot;hl-function&quot;&gt;advance&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2usize&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(k.tasks[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].state, k.tasks[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].prio, k.tasks[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;].prio)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 8 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The place is evaluated once&lt;/strong&gt;, where the binding is written — the index is computed once, the bounds
are checked once — and what the name means afterwards is the storage that was found, not the
expression that found it. A later &lt;code&gt;i += 1&lt;/code&gt; leaves &lt;code&gt;t&lt;/code&gt; naming the element it always named. Scala’s
by-name parameter is the thing this is &lt;em&gt;not&lt;/em&gt;: &lt;code&gt;x: =&amp;gt; T&lt;/code&gt; re-evaluates at every use, which would save
no check and would silently make &lt;code&gt;t&lt;/code&gt; follow a later change to &lt;code&gt;i&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;it-is-a-declaration-never-a-type&quot;&gt;It is a declaration, never a type&lt;/h3&gt;
&lt;p&gt;This is the whole of why it can exist in a language with no borrow checker. &lt;code&gt;ref&lt;/code&gt; may be written
&lt;strong&gt;only as a local declaration&lt;/strong&gt;. There is no &lt;code&gt;ref&lt;/code&gt; type, so a ref cannot be a field, a parameter, a
return type, an element, or a type argument; it cannot be re-pointed at a second place once bound; it
cannot be captured by a closure; and it does not outlive the block that declares it.&lt;/p&gt;
&lt;p&gt;A ref &lt;em&gt;of&lt;/em&gt; a ref is not a re-pointing and is ordinary — one more name for the place the first one
stands for, with the walks following through it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; a = xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; b = a

b = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 42 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That restriction is what keeps the compiler’s knowledge complete. A &lt;code&gt;*T&lt;/code&gt; is a type, so the moment one
exists it can be carried somewhere the compiler has lost the path it came from. A ref never travels,
so the analyzer still holds the place expression, at the point it was written, in the same body.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At run time a ref stores an address. At compile time it remembers a place.&lt;/strong&gt; Both halves are
load-bearing. The address is what makes sixty-five path walks one. The remembered place is what keeps
every check a &lt;code&gt;*T&lt;/code&gt; would have severed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a write through the ref re-runs the &lt;code&gt;invariant&lt;/code&gt; clauses of every struct the place lies inside,
found by the same outward walk, because the walk still has the whole place to walk;&lt;/li&gt;
&lt;li&gt;a ref into a &lt;code&gt;val&lt;/code&gt;, or into an element of one, is read-only, since reaching into read-only storage
keeps the property;&lt;/li&gt;
&lt;li&gt;a ref to a &lt;code&gt;within&lt;/code&gt;-constrained slot is checked on assignment exactly as the slot is;&lt;/li&gt;
&lt;li&gt;and the bounds check a subscript owes is paid once, at the binding, rather than not at all.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A ref is therefore &lt;strong&gt;not a fourth memory mode&lt;/strong&gt;. It introduces no representation, no new type, and
nothing that can be stored: it is a second way to &lt;em&gt;say&lt;/em&gt; a place the three modes already describe.&lt;/p&gt;
&lt;h3 id=&quot;what-may-be-written&quot;&gt;What may be written&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A ref’s initializer must be a place&lt;/strong&gt;, and a call result has no address for the name to mean:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; x = &lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;()

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;demo&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;ref&apos; names a place — a local, a field, an element, or a dereference — and this expression has no address for &apos;x&apos; to name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A ref inherits the place’s writability and gets no modifier of its own.&lt;/strong&gt; A ref into a &lt;code&gt;val&lt;/code&gt; may be
read and not written, exactly as the &lt;code&gt;val&lt;/code&gt; may. Stating it twice would only create the chance to
state it wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A user type’s subscript is not a place.&lt;/strong&gt; &lt;code&gt;b[i]&lt;/code&gt; on a container goes through the &lt;code&gt;Index&lt;/code&gt; trait,
which is a call rather than a walk to an address, so there is nothing there for a name to mean. A ref
reaches the built-in subscript, which is the one that indexes storage.&lt;/p&gt;
&lt;h3 id=&quot;the-one-rule-what-may-move-underneath-it&quot;&gt;The one rule: what may move underneath it&lt;/h3&gt;
&lt;p&gt;A stored address is only as good as the storage staying where it is. C# has ref locals and needs no
rule like this, because a tracing collector keeps the old array alive when the variable is pointed at
a new one. sysl has no collector in this tier, so the same program would dangle:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;
    cell: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; e = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]

        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Table&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

t.&lt;span class=&quot;hl-function&quot;&gt;swap&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;e&apos; is a &apos;ref&apos; standing on storage this assignment would release, so the name would be left pointing at freed memory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;While a ref is live, no step of its place that could come to name different storage may be
assigned, and no mutating method may be called on a prefix of one.&lt;/strong&gt; The check is local, decided from
types alone, and never asks where the ref is &lt;em&gt;used&lt;/em&gt; — which is the question that would need lifetimes.&lt;/p&gt;
&lt;p&gt;Which steps are hazards falls out of the model rather than being a list, and &lt;strong&gt;the discriminator is
ownership, not indirection.&lt;/strong&gt; Only a step that &lt;em&gt;releases&lt;/em&gt; something when it is overwritten can strand
a ref:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;step&lt;/th&gt;&lt;th&gt;hazard?&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;overwriting it drops what it held, and that release may be the last&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a view (&lt;code&gt;[]T&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;yes&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;the same — a view owns its buffer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;a raw pointer owns nothing, so &lt;code&gt;p = q&lt;/code&gt; frees nothing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a field, a fixed array, or an element of one&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;td&gt;that storage &lt;em&gt;is&lt;/em&gt; the enclosing object’s bytes&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two words carry the rule, and between them they keep the set small. A step is held still when it is
an &lt;strong&gt;owning&lt;/strong&gt; step that the path goes &lt;strong&gt;through&lt;/strong&gt; — so the place itself is never in the set, because
an assignment to it is what writing through the ref &lt;em&gt;is&lt;/em&gt;. &lt;code&gt;ref r = h.node&lt;/code&gt; names the slot, so
&lt;code&gt;r = other&lt;/code&gt; and &lt;code&gt;h.node = other&lt;/code&gt; are one statement written two ways and neither is refused, while
&lt;code&gt;h = other&lt;/code&gt; on a &lt;code&gt;&amp;amp;Holder&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;*T&lt;/code&gt; exclusion is not a concession. A program that reaches its tables through a &lt;code&gt;*Self&lt;/code&gt; receiver
has no owning step anywhere in its chains, so it is asked for nothing at all — which is exactly the
&lt;code&gt;advance&lt;/code&gt; above, where the rule costs the program nothing.&lt;/p&gt;
&lt;p&gt;The mutating-call half is the conservative one, deliberately. A &lt;code&gt;*self&lt;/code&gt; method may write any part of
its receiver, so a live ref into that receiver is refused the call whether or not that particular
method reassigns anything:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;
    cell: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;grow&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cell = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Table&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-type&quot;&gt;Table&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

&lt;span class=&quot;hl-keyword&quot;&gt;ref&lt;/span&gt; e = t.cell[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

t.&lt;span class=&quot;hl-function&quot;&gt;grow&lt;/span&gt;()

e = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;e&apos; is a &apos;ref&apos; standing on storage this call could release, since a &apos;*self&apos; method may write its receiver
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deciding otherwise would mean reading the callee’s body, and a module compiles against its imports’
signatures and never their bodies. The cost is one refusal in a program that could have written the
ref one line later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What this does not do is make a &lt;code&gt;*T&lt;/code&gt; safe&lt;/strong&gt;, and it does not try. A ref’s place may be rooted at a
pointer, and whether &lt;em&gt;that&lt;/em&gt; points anywhere is the raw tier’s ordinary bargain. What the rule buys is
that the storage a ref names cannot be released by the block that named it.&lt;/p&gt;
&lt;h3 id=&quot;a-ref-to-a-slot-that-holds-a-reference&quot;&gt;A ref to a slot that holds a reference&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ref r = self.node&lt;/code&gt;, where &lt;code&gt;node&lt;/code&gt; is a &lt;code&gt;&amp;amp;Node&lt;/code&gt;, names the &lt;strong&gt;slot&lt;/strong&gt;, not the object in it. So the
binding takes no count — nothing new holds the object — and &lt;code&gt;r = other&lt;/code&gt; is the assignment
&lt;code&gt;self.node = other&lt;/code&gt; by another name, releasing what was there and retaining what arrives, in that
order. Reading &lt;code&gt;r&lt;/code&gt; produces the reference and takes a count for the reader exactly as reading the
field would.&lt;/p&gt;
&lt;p&gt;The distinction matters because the other reading is available and wrong: if binding retained, a ref
would be a &lt;code&gt;&amp;amp;T&lt;/code&gt; with extra steps, and the count it took would keep an object alive past the write
that replaced it.&lt;/p&gt;
&lt;h3 id=&quot;where-it-comes-from&quot;&gt;Where it comes from&lt;/h3&gt;
&lt;p&gt;The form is old and lives outside this language’s usual references, none of which have it. &lt;strong&gt;Ada’s
&lt;code&gt;renames&lt;/code&gt;&lt;/strong&gt; is the general case and evaluates the name once at the declaration; &lt;strong&gt;Fortran’s
&lt;code&gt;ASSOCIATE&lt;/code&gt;&lt;/strong&gt; is the closest in shape, being block-scoped and deliberately not a type; &lt;strong&gt;C#’s &lt;code&gt;ref&lt;/code&gt;
locals&lt;/strong&gt; are the closest in spelling. C# also shows what the restriction is worth: having added ref
returns and ref fields, it spent several releases building the escape analysis that keeping the form
local avoids entirely.&lt;/p&gt;
&lt;h2 id=&quot;recursive-types&quot;&gt;Recursive types&lt;/h2&gt;
&lt;p&gt;A type may reach itself &lt;strong&gt;through an indirection&lt;/strong&gt;, and only through one. &lt;code&gt;next: *Node&lt;/code&gt; is
pointer-sized and legal, as is &lt;code&gt;next: Option[&amp;amp;Node]&lt;/code&gt;; a struct holding itself by value has no finite
size:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    next: &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;type &apos;Node&apos; contains itself, so it has no finite size
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rule is &lt;strong&gt;per cycle rather than per field&lt;/strong&gt;: a cycle is legal as soon as one edge on it is a &lt;code&gt;*T&lt;/code&gt;
or a &lt;code&gt;&amp;amp;T&lt;/code&gt;, so mutually recursive types work as long as the loop passes through a pointer or a
reference somewhere.&lt;/p&gt;
&lt;h2 id=&quot;slices-keep-their-backing-alive&quot;&gt;Slices keep their backing alive&lt;/h2&gt;
&lt;p&gt;A slice is &lt;strong&gt;three words&lt;/strong&gt;, not two:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[]T = { owner: *Buf, ptr: *T, len: usize }        // 24 bytes on a 64-bit target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ptr&lt;/code&gt; and &lt;code&gt;len&lt;/code&gt; name the range; &lt;strong&gt;&lt;code&gt;owner&lt;/code&gt; keeps the bytes alive.&lt;/strong&gt; A bare &lt;code&gt;{ptr, len}&lt;/code&gt; view can
outlive the buffer it views — Go gets away with it because its collector finds the object from an
interior pointer, and sysl has no collector — so the slice carries the owning reference itself.
Taking a slice retains, dropping one releases, slicing stays O(1) and allocation-free, and “a slice
never dangles” becomes true rather than aspirational.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;tail&lt;/span&gt;() -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

    xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-function&quot;&gt;tail&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t.len, t[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], t[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The buffer &lt;code&gt;xs&lt;/code&gt; named is gone as a name before &lt;code&gt;print&lt;/code&gt; runs, and the slice is still valid, because
the slice is one of its owners.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;owner&lt;/code&gt; is null when there is nothing to keep alive&lt;/strong&gt; — a slice of static data, of a &lt;code&gt;*T&lt;/code&gt; buffer, or
of a fixed array whose storage outlives every view of it. Retain and release on such a slice are
no-ops, so allocator-free code slicing a static or stack buffer pays nothing at all. This is the same
immortality rule string literals use, generalized.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is then exactly an &lt;strong&gt;immutable, validated &lt;code&gt;[]u8&lt;/code&gt;&lt;/strong&gt;, and the two share one representation
and one implementation.&lt;/p&gt;
&lt;h2 id=&quot;escape-analysis&quot;&gt;Escape analysis&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;owner&lt;/code&gt; word answers “who keeps this alive” for every slice except one: a slice of a &lt;strong&gt;local
fixed array&lt;/strong&gt;. That storage is a stack slot, valid until the frame returns and no longer.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;slice of&lt;/th&gt;&lt;th&gt;&lt;code&gt;owner&lt;/code&gt;&lt;/th&gt;&lt;th&gt;safe to keep?&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a heap buffer&lt;/td&gt;&lt;td&gt;the buffer&lt;/td&gt;&lt;td&gt;yes — retained&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;static data, a string literal&lt;/td&gt;&lt;td&gt;null (immortal)&lt;/td&gt;&lt;td&gt;yes — never freed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;*T&lt;/code&gt; region&lt;/td&gt;&lt;td&gt;null&lt;/td&gt;&lt;td&gt;the programmer’s problem, like every &lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a local fixed array&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;null&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;only while the frame lives&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The compiler finds the slices for which that matters, and &lt;strong&gt;the programmer writes nothing&lt;/strong&gt;. There is
no &lt;code&gt;@escaping&lt;/code&gt;, no lifetime parameter, and no “this result views that argument” marker anywhere in a
signature. Go is the precedent; Rust’s lifetimes and Swift’s &lt;code&gt;@escaping&lt;/code&gt; are the alternative, and both
charge the programmer for what a compiler can work out.&lt;/p&gt;
&lt;h3 id=&quot;what-escapes&quot;&gt;What escapes&lt;/h3&gt;
&lt;p&gt;A slice whose origin is a local array escapes if it can be reached after the frame returns — that is,
if it is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;returned&lt;/strong&gt;, directly or nested inside whatever carries it back: a struct, an enum, an &lt;code&gt;Option&lt;/code&gt;,
a tuple, or one slot of a multi-result list;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;stored into anything that outlives the frame&lt;/strong&gt; — a global, a field reached through a &lt;code&gt;&amp;amp;T&lt;/code&gt;, or an
aggregate that is itself stored somewhere that outlives the frame;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;passed as an argument the callee keeps&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;captured by a closure that itself escapes&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;assigned into a local that escapes&lt;/strong&gt; — the rule is transitive, resolved as a fixpoint over the
function’s own locals.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Everything else needs no allocation: indexing, iterating, sub-slicing into a local that stays local,
comparing, and passing to a callee that only reads.&lt;/p&gt;
&lt;h3 id=&quot;crossing-a-call&quot;&gt;Crossing a call&lt;/h3&gt;
&lt;p&gt;Two facts about a function are enough to keep the caller’s analysis local and exact, and both are
&lt;strong&gt;inferred from the body&lt;/strong&gt; rather than written:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;per parameter&lt;/strong&gt; — does the callee let this argument outlive the call?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;for the result&lt;/strong&gt; — which parameters may the returned value be a view of?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are computed bottom-up over the call graph and recorded in module metadata. Recursion starts
optimistic and iterates to a fixpoint, so a self- or mutually-recursive function converges on the
truth rather than on the conservative answer.&lt;/p&gt;
&lt;p&gt;Two cases get the pessimistic answer instead — every parameter kept, the result viewing everything:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a call through a trait object&lt;/strong&gt;, because which body it reaches is a word read at run time, so
there is no one summary to consult. Reading through a &lt;em&gt;concrete&lt;/em&gt; type or through a bounded type
parameter is unaffected, since monomorphization turns the second into a direct call too;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a function whose body is not available&lt;/strong&gt; — an &lt;code&gt;extern&lt;/code&gt;, which is the declaration form for exactly
that. The foreign side may retain what it was given, and nothing here can tell.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-happens-when-a-slice-escapes&quot;&gt;What happens when a slice escapes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;With an allocator, the array is promoted.&lt;/strong&gt; It is allocated as an ARC buffer instead of a stack
slot, the slice’s &lt;code&gt;owner&lt;/code&gt; points at it, and nothing else about the program changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;render&lt;/span&gt;() -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; line: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

    line[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;104u8&lt;/span&gt;
    line[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;105u8&lt;/span&gt;

    line[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; l = &lt;span class=&quot;hl-function&quot;&gt;render&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(l.len, l[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], l[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 104 105
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The array keeps its type, and only its storage moves.&lt;/strong&gt; A promoted &lt;code&gt;[8]u8&lt;/code&gt; is still a &lt;code&gt;[8]u8&lt;/code&gt;: its
length is still a compile-time constant, it is still a value that copies on assignment, and every
index and store is emitted exactly as an unpromoted one’s is. What changes is where the name’s
address points, and that a view of it carries that buffer as its owner. Rewriting the declaration
into a &lt;code&gt;[]u8&lt;/code&gt; would have been the other way to do it and is wrong — it changes the type at every use,
and an array is a value type where a view is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Which array moves&lt;/strong&gt; is decided by the &lt;em&gt;root&lt;/em&gt; of the escaping view. An index step is walked through,
because an element of a local array of arrays is part of that array’s storage; a &lt;strong&gt;field&lt;/strong&gt; step is
not, because that storage belongs to a struct. Only arrays that are &lt;em&gt;both&lt;/em&gt; sliced &lt;em&gt;and&lt;/em&gt; escaped are
promoted.&lt;/p&gt;
&lt;p&gt;Two roots have nowhere to be promoted to, and are diagnostics rather than promotions — an array a
caller passed &lt;strong&gt;by value&lt;/strong&gt;, which is the caller’s layout, and an array that is a &lt;strong&gt;field&lt;/strong&gt; of a struct
on the frame:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first_two&lt;/span&gt;(a: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;first_two&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]).len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a slice of an array this frame owns is returned, so it would outlive the array, and the storage is not this body&apos;s to move — it is a field of a value, or an array a caller passed by value. Declare it as a &apos;[]T&apos;, which makes a buffer of its own and owns it, or as a &apos;&amp;amp;[N]T&apos; where the length is fixed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Without an allocator it is always a compile error.&lt;/strong&gt; Under &lt;code&gt;no alloc&lt;/code&gt; there is nothing to promote
into, so every promotion becomes a refusal reported at the view that leaves the frame. That is how
every other allocation-gated feature behaves in the allocator-free subset — growable arrays, escaping
closures, and &lt;code&gt;&amp;amp;T&lt;/code&gt; creation are all compile errors there — so it introduces no new rule.&lt;/p&gt;
&lt;h3 id=&quot;promotion-is-silent-not-hidden&quot;&gt;Promotion is silent, not hidden&lt;/h3&gt;
&lt;p&gt;Silent promotion earns the obvious objection: an allocation appears that nothing in the source asked
for. The answer is discoverability rather than ceremony — &lt;strong&gt;&lt;code&gt;--explain-escapes&lt;/code&gt;&lt;/strong&gt; reports every
promotion the compiler made and the route that forced it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sysl build --explain-escapes tty.sysl
tty.sysl:31:12: &apos;buf&apos; is promoted to the heap, because this view of it is returned
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One line per array, in source order, on stderr, accepted by every subcommand. The position is the
&lt;strong&gt;view that forced the move&lt;/strong&gt; rather than the declaration, because that is the half a reader cannot
work out for themselves. This is Go’s &lt;code&gt;-m&lt;/code&gt;, and it is the right shape: the common case costs no
reading, and “why did this allocate?” always has an answer. A program that must not allocate says so
with &lt;code&gt;no alloc&lt;/code&gt;, and then the compiler enforces it rather than reporting it.&lt;/p&gt;
&lt;p&gt;The idiom worth reaching for first, even where an allocator exists, is the last one: &lt;strong&gt;return a count
and let the caller slice its own buffer.&lt;/strong&gt; That is what &lt;code&gt;snprintf&lt;/code&gt; does, what Rust’s buffer writers
do, and what most kernel code wants.&lt;/p&gt;
&lt;h2 id=&quot;reinterpreting-storage&quot;&gt;Reinterpreting storage&lt;/h2&gt;
&lt;p&gt;An allocator carves bytes and hands back a typed pointer — that is the whole of what an allocator
does. A driver takes an address the datasheet gives as a number and reaches the register block at it.
Both need a way to say which type some bytes are, and both are cases the raw tier already committed
to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three directions, two spellings&lt;/strong&gt;, because they are not equally dangerous:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;direction&lt;/th&gt;&lt;th&gt;tier&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;usize(p)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a pointer as a number&lt;/td&gt;&lt;td&gt;an ordinary conversion&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ptr_cast(n)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a number as a pointer&lt;/td&gt;&lt;td&gt;unsafe&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ptr_cast(p)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one pointee type as another&lt;/td&gt;&lt;td&gt;unsafe&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A pointer becomes an integer through the ordinary conversion syntax&lt;/strong&gt;, because it is an ordinary
conversion: &lt;code&gt;usize&lt;/code&gt; is wide enough to hold any address by definition, so it is total and loses
nothing, and the result is a number that cannot be dereferenced. &lt;code&gt;isize&lt;/code&gt; takes one too, which is what
a program comparing addresses against a signed offset wants.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; arena: [&lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

n.value = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n.value, &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;(n) == &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 4 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The target type comes from whatever receives the result&lt;/strong&gt; — the same way &lt;code&gt;va_arg&lt;/code&gt;, a bare &lt;code&gt;None&lt;/code&gt;,
and a bare &lt;code&gt;null&lt;/code&gt; all take theirs. Where that is not where a reader wants to say it, it may be
written on the form: &lt;code&gt;ptr_cast[*Node](&amp;amp;arena[0])&lt;/code&gt; is
&lt;a href=&quot;/reference/generics/&quot;&gt;the written type-argument list&lt;/a&gt; at a special form. Where neither says which
pointer is wanted, the program is told to annotate what receives it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; arena: [&lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;ptr_cast&apos; reads an address as a pointer to some type, and nothing here says which
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ptr_cast&lt;/code&gt; never produces a &lt;code&gt;&amp;amp;T&lt;/code&gt;.&lt;/strong&gt; A reference is a safe-tier value — non-null, refcounted, and
relied on by everything the safe subset promises — and an address invented from bytes has no count for
ARC to own and no object to be non-null about:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; arena: [&lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n.value)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;ptr_cast&apos; never produces a reference: a &apos;&amp;amp;T&apos; is counted and non-null, and an address read out of bytes carries no count for anything to own — read it as a &apos;*T&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;weak T&lt;/code&gt; is refused for the same reason, and the fat types — a slice, a &lt;code&gt;string&lt;/code&gt; — for that reason
and one more: they are wider than an address, so there is nothing to reinterpret. What comes out is a
&lt;code&gt;*T&lt;/code&gt;, and reaching anything else from it is the ordinary route through &lt;code&gt;*p&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt; and &lt;code&gt;offsetof&lt;/code&gt;, which measure what is being carved, are on the
&lt;a href=&quot;/reference/expressions/&quot;&gt;expressions&lt;/a&gt; page.&lt;/p&gt;
&lt;h2 id=&quot;device-memory&quot;&gt;Device memory&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;ptr_cast&lt;/code&gt; gets a driver to the register block. It does not get it a &lt;em&gt;correct&lt;/em&gt; driver, and the missing
half is this: an optimizer is entitled to assume that reading the same storage twice yields the same
value, that a store nobody reads is a store nobody needs, and that two accesses in a row may be one
wider access. Every one of those assumptions is false at a device. &lt;code&gt;while regs.status == 0u32 do ()&lt;/code&gt;
is a loop that reads a register until the hardware changes it, and a compiler that hoisted the read
out would spin forever on the first value it saw.&lt;/p&gt;
&lt;p&gt;So sysl has C’s qualifier, spelled the way C spells it — in the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt;
    status: volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    data:   volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    baud:   &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Uart&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; block = &lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;115200&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; regs: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;block

regs.data = &lt;span class=&quot;hl-number&quot;&gt;65&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(regs.status, regs.data, regs.baud)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 65 115200
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt;&lt;/strong&gt; place is one whose reads and writes are &lt;strong&gt;effects, not value computations&lt;/strong&gt;. It
may change without the program changing it, and reading it may itself do something. So the compiler
emits exactly the accesses the source wrote, exactly once each, in the order written — never adding,
dropping, merging, or moving them relative to one another.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;It constrains the compiler, not the machine.&lt;/strong&gt; No atomicity, no ordering against another core, no
protection from a torn read. C spent two decades learning this; for talking to another thread the
tools are &lt;code&gt;&amp;amp;sync T&lt;/code&gt;, &lt;code&gt;Mutex[T]&lt;/code&gt;, &lt;code&gt;Atomic[T]&lt;/code&gt; and explicit orderings, and none of them is spelled
&lt;code&gt;volatile&lt;/code&gt;. A program that reaches for this word to share a counter has written a race with a keyword
in front of it.&lt;/p&gt;
&lt;h3 id=&quot;it-qualifies-storage-and-a-value-read-out-of-storage-is-an-ordinary-value&quot;&gt;It qualifies storage, and a value read out of storage is an ordinary value&lt;/h3&gt;
&lt;p&gt;This is the rule everything else follows from. &lt;code&gt;regs.status&lt;/code&gt; above has type &lt;code&gt;u32&lt;/code&gt; — not
&lt;code&gt;volatile u32&lt;/code&gt; — because what a load hands back is a number, and a number is not somewhere a device
can write. What is qualified is the &lt;strong&gt;place&lt;/strong&gt;, and the qualifier lives in the three types that name a
place somebody else owns:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;what is qualified&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;status: volatile u32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a struct field&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bank: [4]volatile u32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an element — a GPIO bank&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;p: *volatile u32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a pointee — the lone register&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Everywhere else the type being written is the type of a &lt;strong&gt;value&lt;/strong&gt;: what a &lt;code&gt;var&lt;/code&gt; holds, what a
parameter receives, what a function hands back, what a type argument stands for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: volatile &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;volatile u32&apos; is the type of *storage*, and this is a value — what a read of a volatile place hands back is an ordinary &apos;u32&apos;. The qualifier goes where the storage is named: a struct field, an element, or the pointee of a &apos;*T&apos;, as &apos;*volatile u32&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diagnostic says which spelling was wanted, because a program that writes &lt;code&gt;var x: volatile u32&lt;/code&gt;
almost always meant &lt;code&gt;*volatile u32&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Per field, not per aggregate.&lt;/strong&gt; C also allows &lt;code&gt;volatile struct Uart&lt;/code&gt;; sysl does not, and the block
above shows why. &lt;code&gt;baud&lt;/code&gt; is a shadow value the driver keeps in ordinary memory beside the registers,
and every real device header has one — a reserved word, a cached configuration, a software flag. A
qualifier on the whole struct would sweep it in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt;
    status: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Uart&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;volatile &lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a register block is qualified one field at a time
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Qualifying per field is the same power with the opt-out, it is what CMSIS and every other vendor
header already does, and it makes the restriction below a check on one scalar instead of a walk of a
type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only a scalar or a raw pointer may be qualified.&lt;/strong&gt; The promise is about &lt;em&gt;the&lt;/em&gt; load and &lt;em&gt;the&lt;/em&gt; store
the source wrote, so it is only meaningful where an access is one instruction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a counted value is refused outright&lt;/strong&gt; — a &lt;code&gt;&amp;amp;T&lt;/code&gt;, a &lt;code&gt;weak T&lt;/code&gt;, a slice and a &lt;code&gt;string&lt;/code&gt; come with
retains and releases the compiler places, and a retain that may not be elided is not a request
anybody could act on;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a trait object is refused&lt;/strong&gt; for a plainer reason: it is two words, so touching one is two accesses
whatever the source says, and the table beside the value is this program’s rather than a device’s;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a constrained subtype is refused&lt;/strong&gt;, and this one is about trust rather than instructions. A
&lt;code&gt;Level = int within 0..7&lt;/code&gt; is the claim that a value &lt;em&gt;has been checked&lt;/em&gt;; a register holds whatever
the device put there. So the register is declared at the base type and what comes back is converted
— one written conversion, checked, at the point the value arrives;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a data enum is refused&lt;/strong&gt; — a tag beside a payload is more than one access however it is written.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A &lt;strong&gt;simple enum&lt;/strong&gt; is admitted, since it &lt;em&gt;is&lt;/em&gt; its underlying integer: it is one load, and it is the
spelling a register’s mode field wants. So is a &lt;strong&gt;bitfield&lt;/strong&gt;, which is the one case where the access
reaches more than the field named — the qualifier applies to the container the field is bits of, so a
write is a read-modify-write of the whole of it. &lt;code&gt;@packed&lt;/code&gt; on
&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; states that rule and what it costs a driver.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A struct that holds a register carries no &lt;code&gt;invariant&lt;/code&gt;.&lt;/strong&gt; A check is a call taking every field, so it
reads the whole block however few fields the clause names — an invariant written over the shadow value
beside the registers would make writing that shadow an access to the device. There is nothing to hold
the clause true either: a device changes a register between the check and the instruction after it. A
register is checked where it is read.&lt;/p&gt;
&lt;h3 id=&quot;what-the-compiler-does-with-it&quot;&gt;What the compiler does with it&lt;/h3&gt;
&lt;p&gt;A qualified access lowers to LLVM’s &lt;code&gt;load volatile&lt;/code&gt; / &lt;code&gt;store volatile&lt;/code&gt;, which is exactly the barrier
this needs: it stops the reordering, elision and merging above, and stops nothing else. There is no
runtime cost and no runtime component.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A qualified field is reached at its own address&lt;/strong&gt;, not lifted out of the block. Reading a &lt;code&gt;Uart&lt;/code&gt;
to find out what is in &lt;code&gt;status&lt;/code&gt; would also read &lt;code&gt;data&lt;/code&gt;, and reading a data register is how a FIFO is
popped — so a qualified field gets a place walk, one &lt;code&gt;getelementptr&lt;/code&gt; and one &lt;code&gt;load volatile&lt;/code&gt;, with
nothing else touched.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A whole block copied is a copy of every register in it.&lt;/strong&gt; &lt;code&gt;var u = *regs&lt;/code&gt; is one access to each,
which is as much an effect as one access to one of them, so the aggregate access is marked too.
Whether a driver wants that is the driver’s business; what it does not get is a silent unqualified
read of hardware.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An address taken of a register is the address of a register.&lt;/strong&gt; &lt;code&gt;&amp;amp;regs.status&lt;/code&gt; has type
&lt;code&gt;*volatile u32&lt;/code&gt;, so a driver may hand one register to a helper and every access the helper makes is
still an access to a device. Without that, a driver would have to be one function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A type parameter never binds to a qualified type.&lt;/strong&gt; The loads and stores a generic body emits are
&lt;em&gt;its&lt;/em&gt; accesses, written once and shared by every instantiation, so it cannot promise to have written
the ones a particular caller had in mind.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;volatile&lt;/code&gt; is not reserved.&lt;/strong&gt; It is special only in front of another type, so a program with a
variable, a field, a function, or a type of its own by that name still compiles — the same arrangement
&lt;code&gt;sync&lt;/code&gt; has after &lt;code&gt;&amp;amp;&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; volatile = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(volatile + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;[]const T&lt;/code&gt; composes with it and means a different thing.&lt;/strong&gt; &lt;code&gt;const&lt;/code&gt; is a property of the &lt;em&gt;view&lt;/em&gt; —
these elements may not be written through this handle — while &lt;code&gt;volatile&lt;/code&gt; is a property of the
&lt;em&gt;element&lt;/em&gt;. A read-only device register is &lt;code&gt;[]const volatile u32&lt;/code&gt;, and both words are doing work.&lt;/p&gt;
&lt;h2 id=&quot;where-defer-sits&quot;&gt;Where &lt;code&gt;defer&lt;/code&gt; sits&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/reference/statements/#defer&quot;&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; is the model’s answer for what the language does &lt;em&gt;not&lt;/em&gt; own: a
descriptor from &lt;code&gt;open&lt;/code&gt;, a &lt;code&gt;FILE*&lt;/code&gt; from &lt;code&gt;fopen&lt;/code&gt;, a block from &lt;code&gt;malloc&lt;/code&gt;, a lock taken from a mutex. ARC
gives back a reference, a string, and a slice’s backing without being asked, and knows nothing about
those.&lt;/p&gt;
&lt;p&gt;Three facts place it against everything above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A deferred statement runs before the block’s ARC releases&lt;/strong&gt;, so every local it names is still
alive when it runs — including the one holding the resource it is closing. Leaving from the middle
unwinds outward: the innermost block runs its deferred statements and then gives up its counts, then
the block outside it does the same.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It owns nothing and allocates nothing.&lt;/strong&gt; &lt;code&gt;defer&lt;/code&gt; takes no count, makes no box, and adds no word to
any value; a program that does not use it emits nothing for it. That is what keeps it available
under &lt;code&gt;no alloc&lt;/code&gt;, where the resources it releases are the only ones there are.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A trap runs nothing.&lt;/strong&gt; A trap aborts without stack cleanup, and &lt;code&gt;defer&lt;/code&gt; does not qualify that: a
broken invariant means the program’s model of itself is already wrong, and running cleanup against
that state is how a corrupt program writes its corruption to disk on the way down.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What it is not is a destructor.&lt;/strong&gt; A destructor belongs to a &lt;em&gt;type&lt;/em&gt; and runs wherever a value of that
type dies; &lt;code&gt;defer&lt;/code&gt; belongs to one place in one body and runs for the resource that body took. Both
exist, and the next section is why neither replaces the other.&lt;/p&gt;
&lt;h2 id=&quot;a-destructor&quot;&gt;A destructor&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;impl Drop for T&lt;/code&gt; says what a type does when the last reference to one of its values goes.&lt;/strong&gt; It
declares one member, &lt;code&gt;drop(self)&lt;/code&gt;, and it answers nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;drop&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;closing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.id)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;working&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;working
closing 7
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is for the resource the language does not manage.&lt;/strong&gt; ARC returns the storage and releases
whatever the value holds; what it cannot do is close a descriptor, unmap a region, or hand a handle
back to the C library that made it. Those live at the far end of a &lt;code&gt;*T&lt;/code&gt; or behind an integer, and
nothing about either says it is owned. The destructor is where that is said, once, beside the type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;defer&lt;/code&gt; is the other way to say it, and neither replaces the other.&lt;/strong&gt; &lt;code&gt;defer close(f)&lt;/code&gt; covers every
site a program can &lt;em&gt;name&lt;/em&gt;. Under ARC a value can also die where there is no site to write one — and
that case is the whole argument for this being a capability rather than a shorthand:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Drop&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;drop&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;closing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.id)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&amp;amp;&lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = [&lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)]
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;holding&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, xs.len)

&lt;span class=&quot;hl-function&quot;&gt;hold&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;holding 2
closing 2
closing 1
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in that program names the moment either element dies. The slice goes, and its elements go
with it — so no &lt;code&gt;defer&lt;/code&gt; could have been written, and a leak there would not be something the author
could have prevented. Where both would work, the destructor is the better one: it is written once,
and a caller cannot forget it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It costs nothing to have.&lt;/strong&gt; Release already calls through a per-payload hook, and a destructor is a
call at the top of that hook. A type without one produces exactly the hook it always did.&lt;/p&gt;
&lt;h3 id=&quot;the-four-limits-each-a-consequence-of-where-it-runs&quot;&gt;The four limits, each a consequence of where it runs&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;It runs before the value’s own references are released&lt;/strong&gt;, so it is handed &lt;code&gt;self&lt;/code&gt; intact and a field
may be read to close what it names. It borrows rather than taking a count — the count is already
zero, and taking one would resurrect the object into a second teardown.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is not called for a value that never reached the heap.&lt;/strong&gt; A value type is copied, and a copy is
not a second resource: there is no single point of death to hook, and running it per copy would close
one descriptor several times. So a destructor is for a type held behind a &lt;code&gt;&amp;amp;T&lt;/code&gt;, and a program that
puts one on a type it then passes by value gets no destructor rather than a wrong one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is not called for a value in a reference cycle&lt;/strong&gt;, whose count never reaches zero. That is not a
new consequence of this feature but the existing cost of counting rather than collecting — the
&lt;em&gt;storage&lt;/em&gt; already leaks there. A &lt;code&gt;weak T&lt;/code&gt; is what breaks a cycle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is not called for module storage when the program ends.&lt;/strong&gt; Storage that lasts the whole run is
never let go of, so its count never reaches zero. There is no exit pass and there will not be one: a
process exiting is what returns what it held, and running destructors at exit is the feature C++ has
spent decades regretting, because the order two statics come apart in has no good answer. What it
costs is that a buffered writer held in a static is not flushed at exit; the program flushes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No order is promised among siblings.&lt;/strong&gt; Two values that die together — the elements of a slice, the
fields of a struct — come apart in an order that follows the teardown worklist, which today makes it
last-to-first. A program that needs one before another has to say so.&lt;/p&gt;
&lt;h2 id=&quot;crossing-a-concurrency-domain&quot;&gt;Crossing a concurrency domain&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;&amp;amp;T&lt;/code&gt; permits aliasing and mutation through any reference, which is safe &lt;strong&gt;within one concurrency
domain&lt;/strong&gt; and nowhere else: its refcount is non-atomic, and two threads touching it would race. So a
&lt;code&gt;&amp;amp;T&lt;/code&gt; may not leave its domain, and crossing one &lt;strong&gt;copies&lt;/strong&gt; by default — which is what process IPC does
anyway, and what keeps the ordinary path free of atomics.&lt;/p&gt;
&lt;p&gt;The exception is &lt;strong&gt;&lt;code&gt;&amp;amp;sync T&lt;/code&gt;&lt;/strong&gt;, whose refcount is atomic. It is a distinct type from &lt;code&gt;&amp;amp;T&lt;/code&gt; with no
conversion either way, and which one an object is is chosen where it is allocated:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cell&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;send&lt;/span&gt;(c: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sync &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = c.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;send&lt;/span&gt;(c))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;&amp;amp;Cell&apos; and &apos;&amp;amp;sync Cell&apos; are distinct types, and neither converts to the other: a count is atomic or it is not from the moment the object is allocated, and a conversion would put an ordinary retain beside an atomic one. Allocate Cell as a &apos;&amp;amp;sync Cell&apos; where it is constructed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A conversion would put an ordinary retain beside an atomic one, so the count is atomic or it is not
from the moment the object exists. &lt;strong&gt;&lt;code&gt;&amp;amp;sync T&lt;/code&gt; makes the &lt;em&gt;reference&lt;/em&gt; safe to share, not the object
safe to mutate&lt;/strong&gt; — that still wants a &lt;code&gt;Mutex&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;crossing-where-the-rule-is-asked&quot;&gt;&lt;code&gt;@crossing&lt;/code&gt; — where the rule is asked&lt;/h3&gt;
&lt;p&gt;The rule above says &lt;em&gt;what&lt;/em&gt; may cross. &lt;strong&gt;&lt;code&gt;@crossing&lt;/code&gt; says where&lt;/strong&gt;: it is the annotation a facility
writes above the function that hands a value to another domain, naming the parameters it hands it
through. &lt;code&gt;sysl.posix.threads.spawn&lt;/code&gt; is declared with one, and so is any package binding a scheduler
of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cell&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;
    cell: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; State&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;crossing&lt;/span&gt;(s)
&lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = s.cell.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; st = &lt;span class=&quot;hl-type&quot;&gt;State&lt;/span&gt;(c)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;start&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;st))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;what &apos;s&apos; of &apos;start&apos; points at reaches another concurrency domain, so every count inside it has to be atomic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;*T&lt;/code&gt; parameter is looked through&lt;/strong&gt;, and that is the whole of what the annotation buys. A raw
pointer carries no refcount &lt;em&gt;of its own&lt;/em&gt;, which says nothing about the object at the far end — and
the object at the far end is what crossed. Everything else is asked about the parameter’s own type.
Hold the cell as a &lt;code&gt;&amp;amp;sync Cell&lt;/code&gt; and the same program compiles.&lt;/p&gt;
&lt;p&gt;It costs nothing at run time: no code is emitted, no signature moves, and a program that satisfies it
is the program it would have been without the line. What it adds is the refusal, made at each call —
so a generic facility is asked afresh for every set of type arguments, exactly as a &lt;code&gt;&amp;amp;sync Box[T]&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A boundary nobody marks is not examined.&lt;/strong&gt; The annotation is how a library author says a domain
begins here, and there is no way for the compiler to guess: a scheduler in a package looks like any
other function until somebody writes the line.&lt;/p&gt;
&lt;h2 id=&quot;hazard-summary&quot;&gt;Hazard summary&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;segfault source&lt;/th&gt;&lt;th&gt;prevented in the safe subset by&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;use-after-free / double-free&lt;/td&gt;&lt;td&gt;ARC on &lt;code&gt;&amp;amp;T&lt;/code&gt;; &lt;code&gt;weak&lt;/code&gt; degrades to &lt;code&gt;Option&lt;/code&gt; and never dangles&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;null dereference&lt;/td&gt;&lt;td&gt;non-null references; nullable is &lt;code&gt;Option&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;out-of-bounds&lt;/td&gt;&lt;td&gt;length-carrying arrays and slices, checked everywhere&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;slice outliving its buffer&lt;/td&gt;&lt;td&gt;the slice’s &lt;code&gt;owner&lt;/code&gt; word retains it; escaping locals are promoted&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;refcount race across threads&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;sync T&lt;/code&gt; is atomic; a &lt;code&gt;&amp;amp;T&lt;/code&gt; may not cross a domain, checked at a &lt;code&gt;@crossing&lt;/code&gt; parameter&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;dangling or wild pointer&lt;/td&gt;&lt;td&gt;impossible without &lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Only &lt;code&gt;*T&lt;/code&gt; opts out, and it opts out visibly.&lt;/p&gt;
&lt;p&gt;One hazard is &lt;strong&gt;not&lt;/strong&gt; on that list: racing on the &lt;em&gt;fields&lt;/em&gt; of an object two threads deliberately
share. Preventing that needs proof of exclusive access, which is the thing this language trades away,
so it is answered by a &lt;code&gt;Mutex&lt;/code&gt; and by convention rather than by the type checker. It takes &lt;code&gt;&amp;amp;sync&lt;/code&gt; or
&lt;code&gt;*T&lt;/code&gt; to reach the situation at all, so it is at least as greppable as everything else here.&lt;/p&gt;
&lt;h2 id=&quot;the-two-worlds-one-language&quot;&gt;The two worlds, one language&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application, server, utility:&lt;/strong&gt; &lt;code&gt;T&lt;/code&gt; and &lt;code&gt;&amp;amp;T&lt;/code&gt;, plus &lt;code&gt;weak&lt;/code&gt;, slices, and arrays. Safe, pleasant,
ARC-managed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kernel, driver, allocator-free:&lt;/strong&gt; &lt;code&gt;T&lt;/code&gt;, &lt;code&gt;*T&lt;/code&gt;, fixed arrays, slices, and manual &lt;code&gt;malloc&lt;/code&gt;/&lt;code&gt;free&lt;/code&gt;. A
module that never &lt;em&gt;creates&lt;/em&gt; a &lt;code&gt;&amp;amp;T&lt;/code&gt; emits no allocation and no allocator dependency, exactly like C,
and stays bounds-checked wherever it uses arrays and slices.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The boundary is not a convention — it is compiler-enforced through the allocator capability. &lt;strong&gt;What it
gates is allocation, not ownership.&lt;/strong&gt; Allocator-free code may hold, pass, copy, and drop a &lt;code&gt;&amp;amp;T&lt;/code&gt; or a
heap-backed slice that something else created: retain and release are a few instructions, and the free
path goes through the object’s own deallocation hook. What it may not do is &lt;em&gt;make&lt;/em&gt; one. That is what
lets a driver keep the &lt;code&gt;&amp;amp;Device&lt;/code&gt; its bus manager handed it, and a &lt;code&gt;no alloc&lt;/code&gt; parser read a heap-backed
slice it was given — neither of which is expressible if ownership stops at the boundary.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/arrays/&quot;&gt;arrays and slices&lt;/a&gt; — the two sequence types, and what a view keeps alive.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>matrix</title>
    <link href="https://sysl.sh/guides/matrix/"/>
    <id>https://sysl.sh/guides/matrix/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>An operator whose result is neither operand&apos;s type — one type carrying three implementations of one trait.</summary>
    <content type="html">&lt;p&gt;A vector space and the matrices over it, then Gaussian elimination on top.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: an operator whose result is neither operand’s type.&lt;/strong&gt; &lt;code&gt;A * v&lt;/code&gt; gives a vector and &lt;code&gt;A * B&lt;/code&gt;
gives a matrix, so one type carries three implementations of one trait — &lt;code&gt;Mul[Vector, Vector]&lt;/code&gt;,
&lt;code&gt;Mul[Matrix, Matrix]&lt;/code&gt; and &lt;code&gt;Mul[real, Matrix]&lt;/code&gt;. Each is selected by the type of the right operand, and
each declares what it hands back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing here is a method that wanted to be an operator&lt;/strong&gt;, which is the whole point of the exercise.
This is the program that demonstrates &lt;a href=&quot;/reference/traits/&quot;&gt;parameterized traits&lt;/a&gt; carrying real weight:
a type implements a trait once at each argument list, so three multiplications on one type are
ordinary rather than a conflict, and the argument list is what tells a call which it meant.&lt;/p&gt;
&lt;p&gt;Contrast &lt;a href=&quot;/guides/datetime/&quot;&gt;datetime&lt;/a&gt;, where the same mechanism does &lt;em&gt;not&lt;/em&gt; rescue
&lt;code&gt;Instant - Instant -&amp;gt; Duration&lt;/code&gt;. The difference is exactly which position the varying type is in: here
the result is named by the row that was selected, and there it would have had to be named by a row
that could not exist.&lt;/p&gt;
&lt;h2 id=&quot;what-it-exercises&quot;&gt;What it exercises&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A matrix is a handle exactly as a vector is.&lt;/strong&gt; The cells are stored row-major in one &lt;code&gt;&amp;amp;Buf[real]&lt;/code&gt;,
so the operators build fresh values and &lt;code&gt;copy&lt;/code&gt; is how a caller stops sharing. That makes the memory
question visible in a place people usually do not think about it: a linear-algebra type is a
&lt;em&gt;container&lt;/em&gt;, and whether &lt;code&gt;B = A&lt;/code&gt; shares or copies is a decision the language makes you write down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gaussian elimination is where the numerics land.&lt;/strong&gt; Pivoting, and the fact that a comparison against
zero is the wrong test for a float, are what the second half is about — and they are ordinary sysl,
because the operator work in the first half means the algorithm reads as the algorithm.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/matrix&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/ring/&quot;&gt;ring&lt;/a&gt; — ranges, attributes, contracts, and invariants.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The math module</title>
    <link href="https://sysl.sh/library/math/"/>
    <id>https://sysl.sh/library/math/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.math` — the `Float` trait over both widths, `Signed` and `Bits` over the open integer family, the constants, `min`/`max`/`clamp` over anything ordered, the float comparisons, and the integer arithmetic above the operators.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.math&lt;/code&gt; is four files and three traits, and the interesting thing about it is that &lt;strong&gt;the three
traits are written three different ways&lt;/strong&gt; — because the types they cover are three different shapes.
Above them sit the free functions, which are not members of anything and say in a bound what they
need. It requires no capability at all: every name here is reachable under &lt;code&gt;no alloc&lt;/code&gt; and on a target
with no operating system.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Bits&lt;/span&gt;, min, pi}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; two = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; u = &lt;span class=&quot;hl-number&quot;&gt;0b1011u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(two.&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(), pi, &lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;count_ones&lt;/span&gt;(), u.&lt;span class=&quot;hl-function&quot;&gt;rotate_left&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u32&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1.41421 3.14159 3
3 22
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-constants&quot;&gt;The constants&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{pi, tau, e, sqrt2, ln2, ln10}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(pi, tau, e)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sqrt2, ln2, ln10)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3.14159 6.28319 2.71828
1.41421 0.693147 2.30259
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those are the full-precision values printed by &lt;code&gt;%g&lt;/code&gt;‘s six significant digits, which is what
&lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;print&lt;/code&gt;&lt;/a&gt; does with a float. The constants themselves carry every digit a &lt;code&gt;real&lt;/code&gt;
holds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All six are &lt;code&gt;real&lt;/code&gt;&lt;/strong&gt;, which is the width they are correct to and the width arithmetic reaches for
unless a program says otherwise. An &lt;code&gt;f32&lt;/code&gt; program writes &lt;code&gt;f32(pi)&lt;/code&gt;: the conversion is a constant the
compiler folds, so it costs nothing at run time, and one declaration per constant is better than two
that could drift apart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;They are digits rather than expressions.&lt;/strong&gt; &lt;code&gt;tau&lt;/code&gt; is written out rather than as &lt;code&gt;2.0 * pi&lt;/code&gt;, because a
constant is a value and not a computation — and the last bit of a doubled binary64 is not always the
last bit of the correctly rounded product.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tau&lt;/code&gt; earns its place beside &lt;code&gt;pi&lt;/code&gt; because it is the one that appears in the arguments to &lt;code&gt;sin&lt;/code&gt; and
&lt;code&gt;cos&lt;/code&gt;: a whole turn is &lt;code&gt;tau&lt;/code&gt;, a quarter turn is &lt;code&gt;tau / 4.0&lt;/code&gt;, and no factor of two has to be carried
around to remember it.&lt;/p&gt;
&lt;h2 id=&quot;float&quot;&gt;&lt;code&gt;Float&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Neg&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Sub&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Mul&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Div&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// The type&apos;s own values, asked without a receiver.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;max_value&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;epsilon&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;infinity&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;pi&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// Required — each width binds these to its own libm entry point.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;cbrt&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;exp&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;exp2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;log2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;log10&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, exponent: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;hypot&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, other: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;sin&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;cos&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;tan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;asin&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;acos&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;atan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;atan2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;sinh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;cosh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;tanh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;asinh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;acosh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;floor&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;ceil&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;round&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trunc&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;fmod&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, divisor: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, sign: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;to_radians&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;to_degrees&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// Answered by the trait, once, for both widths.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;recip&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;lerp&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, to: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;, t: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_infinite&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_finite&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A trait rather than two sets of functions.&lt;/strong&gt; The shape was forced by a language decision that has
since been reversed, and is kept because it is the better one anyway. sysl had no
&lt;a href=&quot;/reference/declarations/&quot;&gt;overloading&lt;/a&gt; when this was written, so free functions could not call the
square root of a &lt;code&gt;real&lt;/code&gt; and the square root of an &lt;code&gt;f32&lt;/code&gt; by one name — it would have needed &lt;code&gt;sqrt&lt;/code&gt;
and &lt;code&gt;sqrtf&lt;/code&gt; the way C does. Two free &lt;code&gt;sqrt&lt;/code&gt;s would resolve correctly today.&lt;/p&gt;
&lt;p&gt;What the trait still buys is the half overloading does not: a member that is &lt;em&gt;arithmetic over the
others&lt;/em&gt; — the logarithm in an arbitrary base, the hypotenuse — is written &lt;strong&gt;once&lt;/strong&gt; as a default and
inherited by both widths, where two free functions would need it twice and could disagree. Dispatch
on the receiver is worth having for its own sake too: &lt;code&gt;x.sqrt()&lt;/code&gt; is the same three words whichever
width &lt;code&gt;x&lt;/code&gt; is, and changing a declaration from &lt;code&gt;f32&lt;/code&gt; to &lt;code&gt;real&lt;/code&gt; sends nobody editing call sites.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The split between what is required and what is answered is where the mathematics is.&lt;/strong&gt; A method
whose result C computes — a range-reduced sine, a correctly rounded root — is required, and each width
binds it to its own libm entry point. A method that is &lt;em&gt;arithmetic over the others&lt;/em&gt; is a default,
written once and inherited by both. So &lt;code&gt;log&lt;/code&gt; in an arbitrary base exists in exactly one place, and
adding a third floating-point width would be 38 bindings and no new mathematics.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;, tau, e}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; two = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; three = &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; eight = &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hundred = &lt;span class=&quot;hl-number&quot;&gt;100.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; eightyone = &lt;span class=&quot;hl-number&quot;&gt;81.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; quarter = tau / &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(two.&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(), eight.&lt;span class=&quot;hl-function&quot;&gt;cbrt&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e.&lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;(), two.&lt;span class=&quot;hl-function&quot;&gt;exp2&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(hundred.&lt;span class=&quot;hl-function&quot;&gt;log10&lt;/span&gt;(), eight.&lt;span class=&quot;hl-function&quot;&gt;log2&lt;/span&gt;(), eightyone.&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(three))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(two.&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;), three.&lt;span class=&quot;hl-function&quot;&gt;hypot&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(quarter.&lt;span class=&quot;hl-function&quot;&gt;sin&lt;/span&gt;(), quarter.&lt;span class=&quot;hl-function&quot;&gt;cos&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1.41421 2
1 4
2 3 4
1024 5
1 6.12323e-17
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four of those lines are decisions rather than arithmetic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ln&lt;/code&gt; is spelled for what it is&lt;/strong&gt;, rather than as C’s bare &lt;code&gt;log&lt;/code&gt; — which reads as though it were the
general one and is the single most common way to get a base wrong. &lt;code&gt;log(base)&lt;/code&gt; is the general one, and
it is the default written over &lt;code&gt;ln&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;log2&lt;/code&gt; and &lt;code&gt;log10&lt;/code&gt; are required separately rather than left to that default&lt;/strong&gt;, because reading them
back through a ratio loses digits that libm keeps.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hypot&lt;/code&gt; is not &lt;code&gt;(x*x + y*y).sqrt()&lt;/code&gt;.&lt;/strong&gt; The squares of operands near the top of the range overflow to
infinity when the answer itself is perfectly representable; libm’s does the scaling that avoids it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;cos(tau/4)&lt;/code&gt; is &lt;code&gt;6.12e-17&lt;/code&gt; and not zero&lt;/strong&gt;, which is not a bug in anything — a quarter turn is not
exactly representable in binary, so the argument handed to &lt;code&gt;cos&lt;/code&gt; is not exactly π/2. This is the
ordinary floating-point fact, and the page shows it rather than choosing an example that hides it.&lt;/p&gt;
&lt;h3 id=&quot;rounding-sign-and-the-rest&quot;&gt;Rounding, sign, and the rest&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; half = &lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; neg = -&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; three = &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; seven = &lt;span class=&quot;hl-number&quot;&gt;7.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; four = &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; zero = &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ten = &lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; one = &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(half.&lt;span class=&quot;hl-function&quot;&gt;floor&lt;/span&gt;(), half.&lt;span class=&quot;hl-function&quot;&gt;ceil&lt;/span&gt;(), half.&lt;span class=&quot;hl-function&quot;&gt;round&lt;/span&gt;(), neg.&lt;span class=&quot;hl-function&quot;&gt;trunc&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(neg.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), three.&lt;span class=&quot;hl-function&quot;&gt;copysign&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(seven.&lt;span class=&quot;hl-function&quot;&gt;fmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(four.&lt;span class=&quot;hl-function&quot;&gt;recip&lt;/span&gt;(), three.&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(), zero.&lt;span class=&quot;hl-function&quot;&gt;lerp&lt;/span&gt;(ten, &lt;span class=&quot;hl-number&quot;&gt;0.25&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(one.&lt;span class=&quot;hl-function&quot;&gt;atan2&lt;/span&gt;(one).&lt;span class=&quot;hl-function&quot;&gt;to_degrees&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(neg.&lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;(), zero.&lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 3 3 -2
2.5 -3
1.5
0.25 9 2.5
45
-1 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;All four rounding functions answer in the float’s own type.&lt;/strong&gt; A &lt;code&gt;floor&lt;/code&gt; that returned an integer
would have no answer for the operands that do not fit one — the caller who wants an integer is the
caller who knows the range, and casts.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;round&lt;/code&gt; goes &lt;strong&gt;away from zero&lt;/strong&gt; at a half, which is C’s rule and not the banker’s rounding a printed
value gets. &lt;code&gt;trunc&lt;/code&gt; goes towards zero, which is what a cast already does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;fmod&lt;/code&gt; is not &lt;code&gt;%&lt;/code&gt;.&lt;/strong&gt; The integer types have &lt;code&gt;Rem&lt;/code&gt; and the floats do not, because a float remainder is
a library operation rather than an instruction. It keeps the sign of the receiver.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;atan2&lt;/code&gt; takes the two coordinates rather than their ratio&lt;/strong&gt;, which is what lets it tell the four
quadrants apart, and the receiver is the &lt;em&gt;vertical&lt;/em&gt; coordinate — matching the argument order the name
has had since Fortran.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lerp&lt;/code&gt; is written &lt;code&gt;a + (b - a) * t&lt;/code&gt; rather than &lt;code&gt;a * (1 - t) + b * t&lt;/code&gt;.&lt;/strong&gt; The second form is exact at
&lt;code&gt;t = 1&lt;/code&gt; and this one is exact at &lt;code&gt;t = 0&lt;/code&gt;, and starting where you said you would start is what a caller
notices.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;signum&lt;/code&gt; answers a zero with that zero&lt;/strong&gt; rather than with a one it cannot justify: it is a pair of
comparisons, so it does not see a negative zero, and a NaN satisfies neither comparison and leaves by
the same arm holding itself. &lt;code&gt;abs&lt;/code&gt; and &lt;code&gt;copysign&lt;/code&gt; are the other two readings of a sign, and those
&lt;em&gt;do&lt;/em&gt; see a negative zero, because they work on the bit.&lt;/p&gt;
&lt;h3 id=&quot;hyperbolics-and-where-they-have-no-answer&quot;&gt;Hyperbolics, and where they have no answer&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; one = &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; two = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; half = &lt;span class=&quot;hl-number&quot;&gt;0.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; below = &lt;span class=&quot;hl-number&quot;&gt;0.5&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; outside = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; neg = -&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(one.&lt;span class=&quot;hl-function&quot;&gt;sinh&lt;/span&gt;(), one.&lt;span class=&quot;hl-function&quot;&gt;cosh&lt;/span&gt;(), one.&lt;span class=&quot;hl-function&quot;&gt;tanh&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(one.&lt;span class=&quot;hl-function&quot;&gt;sinh&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;asinh&lt;/span&gt;(), two.&lt;span class=&quot;hl-function&quot;&gt;cosh&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;acosh&lt;/span&gt;(), half.&lt;span class=&quot;hl-function&quot;&gt;tanh&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(neg.&lt;span class=&quot;hl-function&quot;&gt;asinh&lt;/span&gt;(), below.&lt;span class=&quot;hl-function&quot;&gt;acosh&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;(), outside.&lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1.1752 1.54308 0.761594
1 2 0.5
-1.81845 true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The three inverses are the ones with domains.&lt;/strong&gt; &lt;code&gt;acosh&lt;/code&gt; wants an argument of at least one, &lt;code&gt;atanh&lt;/code&gt;
one strictly between −1 and 1, and &lt;code&gt;asinh&lt;/code&gt; is defined everywhere — which is why the third line asks
two of them for an answer they do not have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outside a domain the answer is a NaN, not a trap.&lt;/strong&gt; That is the same thing &lt;code&gt;asin&lt;/code&gt; and &lt;code&gt;acos&lt;/code&gt; do
outside theirs: a float has a value meaning &lt;em&gt;no answer&lt;/em&gt;, and the library hands it back rather than
stopping the program. It is quiet, so a program that can reach outside a domain should say what it
does about it — &lt;code&gt;is_nan&lt;/code&gt; is the test, and a NaN that flows on will keep failing every comparison it
meets.&lt;/p&gt;
&lt;h3 id=&quot;the-type-s-own-values&quot;&gt;The type’s own values&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2.0f32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;epsilon&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;max_value&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;pi&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;epsilon&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2.22045e-16 1.79769e+308
1.41421 3.14159 1.19209e-07
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;These are members with no receiver, reached through the type&lt;/strong&gt;, and they are what makes the defaults
possible at all: a &lt;code&gt;signum&lt;/code&gt; needs a one to answer with and a &lt;code&gt;recip&lt;/code&gt; needs a one to divide, and
neither can be written in a body shared by two widths unless there is a way to ask a type for its own
one. &lt;code&gt;Self.one()&lt;/code&gt; is that way, so a routine bounded by &lt;code&gt;[T: Float]&lt;/code&gt; can build a value of a width it
has never met.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;epsilon&lt;/code&gt; is what a convergence test should be written against — a loop that stops when two iterations
agree to within a few epsilons stops at the right point at &lt;em&gt;both&lt;/em&gt; widths, where a literal tolerance
does not.&lt;/p&gt;
&lt;p&gt;The two that no literal spells get bodies that say what they are: &lt;code&gt;infinity()&lt;/code&gt; is &lt;code&gt;1.0 / 0.0&lt;/code&gt; and
&lt;code&gt;nan()&lt;/code&gt; is &lt;code&gt;0.0 / 0.0&lt;/code&gt;. Dividing a float by zero is not the error dividing an integer by zero is — IEEE
754 says what the answer is, and this is where the library says it too.&lt;/p&gt;
&lt;p&gt;The only thing that stays per width beyond the libm bindings is the pair of angle conversions, whose
factor is π over 180 — and 180 is not something a zero and a one can be built up into.&lt;/p&gt;
&lt;h3 id=&quot;nan-and-what-compares-to-it&quot;&gt;NaN, and what compares to it&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;, infinity, nan, min}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; one = &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;infinity&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_infinite&lt;/span&gt;(), one.&lt;span class=&quot;hl-function&quot;&gt;is_finite&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;(), one).&lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(one, &lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;()).&lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true true
true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_nan&lt;/code&gt; is &lt;code&gt;self != self&lt;/code&gt;&lt;/strong&gt; — the only value not equal to itself, which is both the definition and
the test, and the reason an equality check cannot be used to look for one. &lt;code&gt;is_infinite&lt;/code&gt; asks whether
the magnitude exceeds the largest finite value, a condition only the two infinities meet and which a
NaN fails the way it fails every comparison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That second line is the one to read carefully.&lt;/strong&gt; &lt;code&gt;min(nan(), 1.0)&lt;/code&gt; is a NaN and &lt;code&gt;min(1.0, nan())&lt;/code&gt; is
&lt;code&gt;1.0&lt;/code&gt;, and neither is a bug. A NaN is less than nothing and greater than nothing, so the single
comparison each of these makes is false whichever way round the operands go, and both fall through to
the arm holding the &lt;strong&gt;first&lt;/strong&gt; argument.&lt;/p&gt;
&lt;p&gt;That is said here rather than worked around. Propagating a NaN from one argument position while
dropping it from the other is what C’s &lt;code&gt;fmin&lt;/code&gt; was criticised for — and the alternative is a comparison
per argument on every call, to spare a case a caller can see coming. A program that must reject a NaN
tests for one.&lt;/p&gt;
&lt;h2 id=&quot;min-max-and-clamp-are-not-float-s&quot;&gt;&lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt; and &lt;code&gt;clamp&lt;/code&gt; are not &lt;code&gt;Float&lt;/code&gt;‘s&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{min, max, clamp}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; half = &lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(half, &lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 7 10
a 2.5
0 5
(1, 2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;They are generic over &lt;code&gt;Ord&lt;/code&gt;, and that is why they are in a file of their own.&lt;/strong&gt; Nothing about
picking the smaller of two things is arithmetic: &lt;code&gt;min&lt;/code&gt; over the integers is the same three words as
&lt;code&gt;min&lt;/code&gt; over the floats, over a string, over a tuple, and over any type a program has written an
&lt;code&gt;lt&lt;/code&gt; for. A version living on &lt;code&gt;Float&lt;/code&gt; would have been the narrowest useful one and would have left
every other type asking why.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A tie answers with the first argument.&lt;/strong&gt; &lt;code&gt;min&lt;/code&gt; is written &lt;code&gt;if b &amp;lt; a then b else a&lt;/code&gt; rather than the
other way round, and for types whose equality does not mean identity — a record ordered on one field,
a pair ordered on its first — which of two indistinguishable values comes back is something a caller
can observe. Taking the first is what makes a fold over a sequence stable.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;clamp&lt;/code&gt; tests the low end first, so an inverted range answers &lt;code&gt;low&lt;/code&gt;. There is no check that the two
bounds are the right way round: a bound is nearly always a constant or a length at the call site, and
a &lt;a href=&quot;/reference/errors/&quot;&gt;contract&lt;/a&gt; is the tool for saying so where it is not.&lt;/p&gt;
&lt;h2 id=&quot;comparing-floats-that-were-computed&quot;&gt;Comparing floats that were computed&lt;/h2&gt;
&lt;p&gt;Binary floating point does not hold &lt;code&gt;0.1 + 0.2 == 0.3&lt;/code&gt;, so a program that checks a computation
against a written-down number needs a tolerance rather than an equality:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{approx_eq, approx_eq_rel, nan, infinity, &lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.1&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;0.2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e-12&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;infinity&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;infinity&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;nan&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;approx_eq_rel&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1e18&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e18&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;1000.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e-6&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;approx_eq_rel&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e-6&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false
true false
true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;approx_eq&lt;/code&gt; takes an &lt;strong&gt;absolute&lt;/strong&gt; tolerance, which is what a delta comparison is. &lt;code&gt;approx_eq_rel&lt;/code&gt;
scales it to the larger of the two operands, so the tolerance reads as a fraction — &lt;code&gt;0.001&lt;/code&gt; means
“within a tenth of a percent” whatever the magnitude — and is the one to reach for when the values
could be any size. Near zero the relative form becomes strict, since the scale goes to zero with the
operands; that is the case the absolute form is for.&lt;/p&gt;
&lt;p&gt;Two behaviours are worth knowing rather than discovering. &lt;strong&gt;Identical infinities are close&lt;/strong&gt;, because
both functions test equality before subtracting — &lt;code&gt;inf - inf&lt;/code&gt; is a NaN, and the subtraction alone
would call a value unequal to itself. And &lt;strong&gt;a NaN is close to nothing, including another NaN&lt;/strong&gt;,
whatever the tolerance, which falls out of the comparisons and agrees with &lt;code&gt;==&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Each has an assertion beside it, which stops the program and names both values and the tolerance
rather than answering &lt;code&gt;bool&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.assert_approx_eq

&lt;span class=&quot;hl-function&quot;&gt;assert_approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.1&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;0.2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e-12&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;assert_approx_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.1&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;0.2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1e-12&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the sum&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;both held&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;both held
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;assert_approx_eq_rel&lt;/code&gt; is the same against the relative test. &lt;strong&gt;They live here rather than beside
&lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;assert_eq&lt;/code&gt;&lt;/a&gt; in the core&lt;/strong&gt;, and that is forced rather than chosen: &lt;code&gt;Float&lt;/code&gt; is
declared in this module and reaches &lt;code&gt;Eq&lt;/code&gt;, &lt;code&gt;Ord&lt;/code&gt; and the arithmetic traits in the core, so &lt;code&gt;sysl.math&lt;/code&gt;
depends on &lt;code&gt;sysl&lt;/code&gt; — and a float assertion written in the core would point an edge back the other way,
which &lt;a href=&quot;/reference/modules/&quot;&gt;the module graph&lt;/a&gt; refuses. Anyone writing float assertions imports this
module already, since it is where the float functions are.&lt;/p&gt;
&lt;p&gt;Mixing types is refused, as everywhere else in the language:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.min

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;min&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;b&apos; of &apos;sysl.math.min&apos; is int, but real was given
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;signed-and-bits-a-different-mechanism&quot;&gt;&lt;code&gt;Signed&lt;/code&gt; and &lt;code&gt;Bits&lt;/code&gt; — a different mechanism&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Signed&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bits&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count_ones&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;count_zeros&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;leading_zeros&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trailing_zeros&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;leading_ones&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;trailing_ones&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;reverse_bits&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;rotate_left&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;rotate_right&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Neither of these has an &lt;code&gt;impl&lt;/code&gt; block anywhere, and neither could.&lt;/strong&gt; &lt;code&gt;Float&lt;/code&gt; is a trait with an &lt;code&gt;impl&lt;/code&gt;
per width because there are exactly two widths. The integers are an &lt;a href=&quot;/reference/types/&quot;&gt;open family&lt;/a&gt;:
&lt;code&gt;i5&lt;/code&gt; and &lt;code&gt;u12&lt;/code&gt; are types a program may name, so there is no finite list of scalars to write an &lt;code&gt;impl&lt;/code&gt;
for, and five blocks covering &lt;code&gt;i8&lt;/code&gt; through &lt;code&gt;isize&lt;/code&gt; would leave &lt;code&gt;i128&lt;/code&gt; and every narrow width without
one — a worse surface than none at all.&lt;/p&gt;
&lt;p&gt;So membership is the &lt;strong&gt;compiler’s&lt;/strong&gt;, by the same rule that makes an &lt;code&gt;int&lt;/code&gt; an &lt;code&gt;Add&lt;/code&gt; without anything
having written &lt;code&gt;impl Add for int&lt;/code&gt;. What is in the source file is the part a declaration can say: the
names, the signatures, and what each one means.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The trait still has to be in scope to be reached.&lt;/strong&gt; That is what a compiler-provided membership does
&lt;em&gt;not&lt;/em&gt; change — it settles which types have the member, not which files may name it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.pi

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x = &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(pi, x.&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;real has &apos;sqrt&apos; from sysl.math.Float, and that trait is not in scope here — import it to reach the member
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Importing the module is not the same as importing the trait: &lt;code&gt;pi&lt;/code&gt; is in scope on that line and
&lt;code&gt;sqrt&lt;/code&gt; is not.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Signed&lt;/code&gt; covers the signed widths only; &lt;code&gt;Bits&lt;/code&gt; covers both signednesses, because a bit pattern is a
bit pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Signed&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; u = &lt;span class=&quot;hl-number&quot;&gt;5u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;type &apos;byte&apos; has no method &apos;abs&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;signed&quot;&gt;&lt;code&gt;Signed&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Signed&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = -&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; z = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = -&lt;span class=&quot;hl-number&quot;&gt;2147483647&lt;/span&gt; - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; big: i128 = -&lt;span class=&quot;hl-number&quot;&gt;170141183460469231731687303715884105727&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), n.&lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;(), z.&lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(big.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), big.&lt;span class=&quot;hl-function&quot;&gt;signum&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 -1 0
-2147483648
170141183460469231731687303715884105727 -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;At the most negative value, &lt;code&gt;abs&lt;/code&gt; answers that value again.&lt;/strong&gt; The magnitude is one larger than the
width can hold, and &lt;a href=&quot;/reference/types/&quot;&gt;plain integer arithmetic in sysl wraps&lt;/a&gt; — so this is what the
two’s-complement negation beside it already does, and the alternative would be a member that traps
where the &lt;code&gt;-&lt;/code&gt; next to it does not.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;signum&lt;/code&gt; answers in &lt;code&gt;Self&lt;/code&gt; rather than a fixed width, so it can be multiplied back into a value of the
same type — which is what a signum is usually for.&lt;/p&gt;
&lt;h3 id=&quot;bits&quot;&gt;&lt;code&gt;Bits&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Bits&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; u = &lt;span class=&quot;hl-number&quot;&gt;0b1011u8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; zero8 = &lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; all8 = &lt;span class=&quot;hl-number&quot;&gt;255u8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;count_ones&lt;/span&gt;(), u.&lt;span class=&quot;hl-function&quot;&gt;count_zeros&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;leading_zeros&lt;/span&gt;(), u.&lt;span class=&quot;hl-function&quot;&gt;trailing_zeros&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;leading_ones&lt;/span&gt;(), u.&lt;span class=&quot;hl-function&quot;&gt;trailing_ones&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u.&lt;span class=&quot;hl-function&quot;&gt;reverse_bits&lt;/span&gt;(), u.&lt;span class=&quot;hl-function&quot;&gt;rotate_left&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u32&lt;/span&gt;), u.&lt;span class=&quot;hl-function&quot;&gt;rotate_right&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u32&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(zero8.&lt;span class=&quot;hl-function&quot;&gt;leading_zeros&lt;/span&gt;(), zero8.&lt;span class=&quot;hl-function&quot;&gt;trailing_zeros&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(all8.&lt;span class=&quot;hl-function&quot;&gt;leading_ones&lt;/span&gt;(), all8.&lt;span class=&quot;hl-function&quot;&gt;count_zeros&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(wide.&lt;span class=&quot;hl-function&quot;&gt;leading_zeros&lt;/span&gt;(), wide.&lt;span class=&quot;hl-function&quot;&gt;rotate_right&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u32&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 5
4 0
0 2
208 22 133
8 8
8 0
31 2147483648
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every one of these is a shift-and-mask loop a program would otherwise write, and every one is a
single instruction on the machines sysl targets&lt;/strong&gt; — &lt;code&gt;count_ones&lt;/code&gt; is &lt;code&gt;popcnt&lt;/code&gt;, &lt;code&gt;leading_zeros&lt;/code&gt; is
&lt;code&gt;lzcnt&lt;/code&gt; or &lt;code&gt;clz&lt;/code&gt;, the rotations are &lt;code&gt;rol&lt;/code&gt; and &lt;code&gt;ror&lt;/code&gt;. That is the case for a member rather than a
comment recommending a loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Zero answers the width, at both ends&lt;/strong&gt;, rather than being undefined the way the bare machine
instruction is on some targets — &lt;code&gt;0u8.leading_zeros()&lt;/code&gt; is 8 and so is its &lt;code&gt;trailing_zeros&lt;/code&gt;. That is
what makes &lt;code&gt;leading_zeros&lt;/code&gt; usable as “how far left is the top bit” with no special case in front of
it, and what makes the same program print the same number on every machine.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;count_zeros&lt;/code&gt; is worth having rather than left to a subtraction&lt;/strong&gt;, because the width is the fact the
caller would otherwise have to know and this is the member that already knows it. &lt;code&gt;leading_ones&lt;/code&gt; and
&lt;code&gt;trailing_ones&lt;/code&gt; are the same pair counted over set bits, so &lt;code&gt;-1&lt;/code&gt; answers the width and &lt;code&gt;0&lt;/code&gt; answers
nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The rotation amount is taken modulo the width&lt;/strong&gt;, so every amount is meaningful and none of it is
undefined — which is the whole reason to call this rather than write &lt;code&gt;(x &amp;lt;&amp;lt; n) | (x &amp;gt;&amp;gt; (w - n))&lt;/code&gt;, an
expression that shifts by the width when &lt;code&gt;n&lt;/code&gt; is zero and is undefined when it does. The amount is a
&lt;code&gt;u32&lt;/code&gt; rather than &lt;code&gt;Self&lt;/code&gt;, because how far to rotate is a count of bit positions and not a value of the
type being rotated: a narrow receiver would otherwise be unable to state an amount its own width
cannot hold.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;reverse_bits&lt;/code&gt; is not a byte order.&lt;/strong&gt; The width is the receiver’s, so it is a different function at
every type.&lt;/p&gt;
&lt;h3 id=&quot;there-is-deliberately-no-swap-bytes&quot;&gt;There is deliberately no &lt;code&gt;swap_bytes&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Bits&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.&lt;span class=&quot;hl-function&quot;&gt;swap_bytes&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;type &apos;uint&apos; has no method &apos;swap_bytes&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reversing the byte order needs a whole number of bytes and at least two, so a &lt;code&gt;u24&lt;/code&gt; has no answer to
it and a &lt;code&gt;u4&lt;/code&gt; has none either. &lt;strong&gt;Every member of &lt;code&gt;Bits&lt;/code&gt; is total over every integer type&lt;/strong&gt;, because a
&lt;code&gt;[T: Bits]&lt;/code&gt; body is written once and instantiated later — a member that worked at &lt;code&gt;u32&lt;/code&gt; and not at
&lt;code&gt;u24&lt;/code&gt; would turn a bound that was supposed to have &lt;em&gt;proven&lt;/em&gt; an operation into a failure at somebody
else’s instantiation.&lt;/p&gt;
&lt;p&gt;A program that means to reorder bytes has the shifts, and knows its own width while writing them.&lt;/p&gt;
&lt;h2 id=&quot;the-arithmetic-above-the-operators&quot;&gt;The arithmetic above the operators&lt;/h2&gt;
&lt;p&gt;Six free functions sit above &lt;code&gt;Signed&lt;/code&gt; and &lt;code&gt;Bits&lt;/code&gt;, and they are what the operators do not give you:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pow(base, exponent)          gcd(a, b)                lcm(a, b)
divmod(a, b) -&amp;gt; T, T         is_power_of_two(x)       next_power_of_two(x) -&amp;gt; Option[T]
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{pow, gcd, lcm, is_power_of_two, next_power_of_two}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0u32&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;lcm&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;lcm&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1024 1
6 12 42
true false
32
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;free-functions-and-the-bound-is-the-specification&quot;&gt;Free functions, and the bound is the specification&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;None of these is a trait member&lt;/strong&gt;, and the reason is the one this page already gave for &lt;code&gt;min&lt;/code&gt;. A
member has to belong to a trait, and the trait is what decides which types have it — but nothing here
is a question about a &lt;em&gt;bit pattern&lt;/em&gt;, which is what &lt;code&gt;Bits&lt;/code&gt; collects, nor about having a sign, which is
what &lt;code&gt;Signed&lt;/code&gt; collects.&lt;/p&gt;
&lt;p&gt;What each one actually needs is written in its own bound instead:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;function&lt;/th&gt;&lt;th&gt;bound&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pow&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Mul + Ord&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;gcd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Rem + Eq + Ord + Sub&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lcm&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Rem + Eq + Ord + Sub + Div + Mul&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;divmod&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Div + Rem&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;is_power_of_two&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Bits + Ord&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;next_power_of_two&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Bits + Ord + Shl + Sub&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Read &lt;code&gt;gcd&lt;/code&gt;‘s: &lt;code&gt;Rem&lt;/code&gt; because Euclid’s algorithm is a remainder loop, &lt;code&gt;Sub&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; because it has to
answer a magnitude — and &lt;strong&gt;deliberately not &lt;code&gt;Signed&lt;/code&gt;&lt;/strong&gt;, which would have shut the unsigned widths out
of a function that serves them perfectly well.&lt;/p&gt;
&lt;p&gt;That is also the thing a trait member could not have offered. The memberships of &lt;code&gt;Bits&lt;/code&gt; and &lt;code&gt;Signed&lt;/code&gt;
are the compiler’s, and &lt;strong&gt;no program can join them&lt;/strong&gt; — so a member would have been closed to a
program’s own numeric type forever, where a bound is satisfied by whoever satisfies it.&lt;/p&gt;
&lt;p&gt;When one is not, the bound is what says so, by name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.is_power_of_two

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;sysl.math.is_power_of_two&apos; requires its type parameter &apos;T&apos; to implement &apos;sysl.math.Bits&apos;, but real does not
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And these are ordinary names in the module, so they are reached the way &lt;code&gt;pi&lt;/code&gt; is — by importing them,
not by importing the module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.pi

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;), pi)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;undefined function &apos;gcd&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;pow&quot;&gt;&lt;code&gt;pow&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.pow

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3u32&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;64u32&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2u8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9u32&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1024 -27
0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The exponent is a &lt;code&gt;u32&lt;/code&gt; and not a &lt;code&gt;T&lt;/code&gt;&lt;/strong&gt;, because how many times to multiply is a &lt;em&gt;count&lt;/em&gt; rather
than a value of the type being multiplied — the same reason &lt;code&gt;rotate_left&lt;/code&gt; takes one. A negative
exponent has no answer among the integers, and saying so in the type is better than a trap:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.pow

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the literal -1 does not fit uint
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An overflowing power wraps&lt;/strong&gt;, as every other integer operation in the language does. &lt;code&gt;pow(2, 64)&lt;/code&gt;
at &lt;code&gt;int&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;pow(2u8, 9)&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;, both arrived at honestly — the doubling that overflows is a
&lt;code&gt;*&lt;/code&gt; like any other. A program that needs to know writes the check it needs.&lt;/p&gt;
&lt;p&gt;The implementation is repeated squaring, so the exponent costs a logarithmic number of multiplies
rather than a linear one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This one is the integers’.&lt;/strong&gt; Its bound admits a &lt;code&gt;real&lt;/code&gt;, and the body does not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.pow

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10u32&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;cannot initialize &apos;acc&apos;: declared real but the value is int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A float raises through &lt;a href=&quot;#float&quot;&gt;&lt;code&gt;Float&lt;/code&gt;&lt;/a&gt;‘s own member — &lt;code&gt;2.0.pow(10.0)&lt;/code&gt; — which takes its exponent as
a &lt;code&gt;Self&lt;/code&gt; rather than a count, because a float exponent is a meaningful thing to have and an integer
one is not the same operation.&lt;/p&gt;
&lt;h3 id=&quot;gcd-and-lcm&quot;&gt;&lt;code&gt;gcd&lt;/code&gt; and &lt;code&gt;lcm&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{gcd, lcm}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;gcd&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12u8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18u8&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;lcm&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;lcm&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;lcm&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 6 6 6
7 7 6
12 0 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Neither ever answers a negative&lt;/strong&gt;, and how &lt;code&gt;gcd&lt;/code&gt; gets there is worth reading. The magnitude is
taken at the &lt;strong&gt;end&lt;/strong&gt; rather than at the start: &lt;code&gt;%&lt;/code&gt; truncates, so Euclid’s loop over negative operands
arrives at the right divisor already, carrying the wrong sign, and one comparison at the end fixes
it. Doing it at the start would have meant negating both operands first — two operations instead of
one, and a signed-only one at that.&lt;/p&gt;
&lt;p&gt;Because the negation is written &lt;code&gt;zero - x&lt;/code&gt; rather than &lt;code&gt;-x&lt;/code&gt;. Unary minus requires &lt;code&gt;Neg&lt;/code&gt;, which the
language gives to the &lt;strong&gt;signed&lt;/strong&gt; integers alone, while &lt;code&gt;Sub&lt;/code&gt; is every integer’s — so that one
spelling is what keeps &lt;code&gt;gcd(12u8, 18u8)&lt;/code&gt; on the third value of the second line.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gcd(x, 0)&lt;/code&gt; is &lt;code&gt;x&lt;/code&gt;, which is both the identity the loop already produces and the answer number theory
gives: everything divides zero, so the largest divisor the pair has in common is &lt;code&gt;x&lt;/code&gt;‘s own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lcm&lt;/code&gt; divides before multiplying&lt;/strong&gt; — &lt;code&gt;a / gcd(a, b) * b&lt;/code&gt; and not &lt;code&gt;a * b / gcd(a, b)&lt;/code&gt; — because the
product of the operands overflows at half the width where the answer itself would fit, and the
quotient is exact by construction, &lt;code&gt;gcd&lt;/code&gt; being a divisor of &lt;code&gt;a&lt;/code&gt;. That is the same reason &lt;code&gt;hypot&lt;/code&gt; is
not &lt;code&gt;sqrt(x*x + y*y)&lt;/code&gt;. A zero operand answers zero rather than dividing by one, since &lt;code&gt;gcd(0, 0)&lt;/code&gt; is
zero and reaching the division would be a division by it.&lt;/p&gt;
&lt;h3 id=&quot;divmod&quot;&gt;&lt;code&gt;divmod&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.divmod

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q, r = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; nq, nr = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q, r)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(nq, nr)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2
-3 -2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both are the operators’ own, so both truncate toward zero and the remainder takes the sign of the
&lt;strong&gt;dividend&lt;/strong&gt;. The reason to call this rather than write the two operators is that it says once what a
reader would otherwise have to check twice: that the same two operands feed both.&lt;/p&gt;
&lt;p&gt;It answers a &lt;a href=&quot;/reference/declarations/&quot;&gt;result list&lt;/a&gt; and not a tuple, because the pair travels from
callee to caller and nothing afterwards needs to hold the two together. A caller that &lt;em&gt;does&lt;/em&gt; need to
hold them writes the tuple itself.&lt;/p&gt;
&lt;p&gt;A binding naming several things is a &lt;strong&gt;local&lt;/strong&gt; form — its parts have nowhere to write a type — so the
top of a program, which is a body, takes one exactly as a function does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.divmod

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q, r = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q, r)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Asking for the module’s storage instead is what has nowhere to put the types, and is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.divmod

&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q, r = &lt;span class=&quot;hl-function&quot;&gt;divmod&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q, r)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a module-level &apos;val&apos; states its type, and a binding that names several things has nowhere to write one — declare &apos;q&apos; and &apos;r&apos; separately
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;is-power-of-two-and-next-power-of-two&quot;&gt;&lt;code&gt;is_power_of_two&lt;/code&gt; and &lt;code&gt;next_power_of_two&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.{is_power_of_two, next_power_of_two}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;128i8&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;128u8&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;200u8&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;128u8&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;100i8&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;next_power_of_two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;60i8&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0i8&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false false true
false true
32 16
1 1
false 128
false 64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_power_of_two&lt;/code&gt; is one set bit &lt;em&gt;and&lt;/em&gt; a comparison against zero&lt;/strong&gt;, and the second line is why the
comparison is there. &lt;code&gt;-128i8&lt;/code&gt; has exactly one bit set — &lt;code&gt;count_ones&lt;/code&gt; answers &lt;code&gt;1&lt;/code&gt; — and it is
emphatically not a power of two. A comparison costs nothing and is the whole of the difference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;next_power_of_two&lt;/code&gt; answers an &lt;code&gt;Option&lt;/code&gt;, and that is what totality costs here.&lt;/strong&gt; &lt;code&gt;200u8&lt;/code&gt;‘s next
power is &lt;code&gt;256&lt;/code&gt;, which no &lt;code&gt;u8&lt;/code&gt; holds. Wrapping to zero would be silently wrong, and a trap would make
a library function rule that a caller’s arithmetic is a bug — so the absence goes in the &lt;strong&gt;type&lt;/strong&gt;,
where a caller has to look at it. Values at or below one answer &lt;code&gt;1&lt;/code&gt;, negatives included: one is the
smallest power of two and every negative is below it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The last two lines are the same width answering differently&lt;/strong&gt;, and they are the reason the
implementation works at all. &lt;code&gt;128&lt;/code&gt; fits a &lt;code&gt;u8&lt;/code&gt; and does not fit an &lt;code&gt;i8&lt;/code&gt;, because the top bit of a
signed byte is the sign — so &lt;code&gt;next_power_of_two(100i8)&lt;/code&gt; is none while &lt;code&gt;next_power_of_two(128u8)&lt;/code&gt; is
&lt;code&gt;128&lt;/code&gt;. The body does not ask which &lt;code&gt;T&lt;/code&gt; it has, which is a question a generic body has no way to put:
it performs the shift and compares the result against zero, since &lt;strong&gt;a signed shift that has reached
the sign bit comes back negative&lt;/strong&gt; and an unsigned one never does.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/time/&quot;&gt;&lt;code&gt;sysl.time&lt;/code&gt;&lt;/a&gt; — instants, durations, and the calendar between them.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>lisp</title>
    <link href="https://sysl.sh/guides/lisp/"/>
    <id>https://sysl.sh/guides/lisp/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The reference cycle — the one shape a reference count cannot reclaim, with `weak T` used as both the cure and the instrument that measures it.</summary>
    <content type="html">&lt;p&gt;A Lisp small enough to read in one sitting: seven kinds of value, three special forms, nine builtins,
and a reader that knows integers, symbols and parentheses. It is not here to be a Lisp. It is here
because a Lisp &lt;strong&gt;cannot avoid&lt;/strong&gt; the one thing reference counting cannot do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The second literate program in the set&lt;/strong&gt;, after &lt;a href=&quot;/guides/slab/&quot;&gt;slab&lt;/a&gt;: a &lt;code&gt;.lsysl&lt;/code&gt; file is Markdown
whose four-column-indented part is the program, so the argument for each arm of &lt;code&gt;eval&lt;/code&gt; sits beside
that arm. As a comment above the function, nobody would read it where it mattered. &lt;code&gt;sysl weave guide/lisp/lisp.lsysl -o lisp.html&lt;/code&gt; sets it as a document — its derivations included — and &lt;code&gt;sysl tangle&lt;/code&gt; prints just the program. See &lt;a href=&quot;/getting-started/cli/#weave&quot;&gt;the CLI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: the reference cycle.&lt;/strong&gt; sysl’s headline memory claim is that it counts references rather
than checking borrows, and the honest cost of that choice is a cycle — an island of objects that all
point at each other, that nothing outside can reach, and whose counts therefore never reach zero.
&lt;a href=&quot;/reference/memory/&quot;&gt;&lt;code&gt;weak T&lt;/code&gt;&lt;/a&gt; exists in the language for this and no other reason, and until this
program nothing in the set showed why anyone would reach for it. &lt;a href=&quot;/guides/json/&quot;&gt;json&lt;/a&gt; is a &lt;em&gt;tree&lt;/em&gt;;
&lt;a href=&quot;/guides/scheduler/&quot;&gt;scheduler&lt;/a&gt;‘s graphs are mutated but acyclic in the direction that matters; and
&lt;a href=&quot;/guides/kernel/&quot;&gt;kernel&lt;/a&gt; sidesteps the question entirely by giving objects indices instead of
references.&lt;/p&gt;
&lt;p&gt;A Lisp closes the loop on the first useful thing anyone types:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-lisp&quot;&gt;(define (fact n) (if (= n 0) 1 (* n (fact (- n 1)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The closure has to see the environment it was written in, or the recursive call could not find
&lt;code&gt;fact&lt;/code&gt;. The definition puts that closure &lt;strong&gt;into&lt;/strong&gt; that environment. &lt;code&gt;Env → &amp;amp;Closure → &amp;amp;Env&lt;/code&gt;, and
neither count will ever be zero again.&lt;/p&gt;
&lt;h2 id=&quot;the-interpreter-is-built-twice&quot;&gt;The interpreter is built twice&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Lambda&lt;/code&gt; carries the edge back to its environment in two spellings, and exactly one is ever filled:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Lambda&lt;/span&gt;
    params: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    body: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Value&lt;/span&gt;
    held: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Env&lt;/span&gt;]
    seen: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Env&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Lambda&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An interpreter is made one way or the other. Both run the same source to the same answers — the page
below is not about a bug, and there is no wrong output anywhere in it. What differs is only what is
left over afterwards.&lt;/p&gt;
&lt;h2 id=&quot;how-it-is-measured-which-is-the-part-worth-stealing&quot;&gt;How it is measured, which is the part worth stealing&lt;/h2&gt;
&lt;p&gt;sysl has a &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; now, and this program deliberately does not use one —
which is worth reading, because the technique below is what a program reaches for when a destructor
is the wrong tool. A destructor would perturb what it measures: giving &lt;code&gt;Env&lt;/code&gt; one means every
environment does work as it dies, on the path being timed. Asking instead costs the objects nothing.
A weak reference does not hold its referent alive, so a buffer of one witness per environment ever
created is a &lt;strong&gt;live-object counter that needs no runtime support and perturbs nothing it counts&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;after_run&lt;/span&gt;(src: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, owning: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Env&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ws: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Env&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Interp&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;interp&lt;/span&gt;(owning, ws)

    &lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;(i, src)

    ws
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; after_run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The interpreter is a local, so it and everything it owns are released before the witnesses are
returned. &lt;strong&gt;That release is the measurement.&lt;/strong&gt; What still answers afterwards is what the run could
not get back. Every number below is a weak reference being asked whether it still resolves.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What leaks is one environment per environment a definition lands in.&lt;/strong&gt; That is not the same as one
per program and not the same as one per call, and the difference is what decides whether a naive
interpreter is usable. Every top-level &lt;code&gt;define&lt;/code&gt; binds into the same globals frame, so &lt;code&gt;(fact 10)&lt;/code&gt; and
a program making five hundred more calls leave &lt;em&gt;the same single environment&lt;/em&gt; alive:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;program&lt;/th&gt;&lt;th&gt;environments made&lt;/th&gt;&lt;th&gt;alive after the interpreter went&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;one definition, eleven calls&lt;/td&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;two definitions, five hundred more calls&lt;/td&gt;&lt;td&gt;513&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a definition &lt;strong&gt;inside&lt;/strong&gt; a function, called three times&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The third row is the one that was not guessed. Move the definition inside a function and the
identical rule reads the other way: each call makes a frame, each frame gets a closure pointing back
at it, and nothing is reclaimed at all. The first two rows were the prediction; the third came from
asking. That is the argument for having a count rather than an opinion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The cure costs more than the disease.&lt;/strong&gt; Making the back-edge &lt;code&gt;weak&lt;/code&gt; means something else has to own
every environment, and the only owner available is the interpreter — so nothing is freed until the
&lt;em&gt;whole run&lt;/em&gt; is over. The naive interpreter holds one environment forever; the careful one holds
&lt;strong&gt;every&lt;/strong&gt; environment until it exits, which the same counter reads as 12 alive where the naive one
reads 1. ARC offers a choice between two leaks here and there is no third option, because the cycle
is the semantics rather than an artefact of how the semantics were encoded. This is the program that
says plainly what reference counting does not do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Breaking a cycle turns a total operation into a partial one.&lt;/strong&gt; &lt;code&gt;held&lt;/code&gt; is an &lt;code&gt;&amp;amp;Env&lt;/code&gt; and always
answers; &lt;code&gt;seen&lt;/code&gt; is a &lt;code&gt;weak Env&lt;/code&gt; and answers &lt;code&gt;Option[&amp;amp;Env]&lt;/code&gt;. The interpreter unwraps it on a path that
cannot fail — the owner table is exactly what makes it so — and the unwrap is written anyway. That is
the honest price of &lt;code&gt;weak&lt;/code&gt;, and it shows up as code rather than as a caveat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“Not optimized” was a statement about sysl and not a prediction about the stack.&lt;/strong&gt; &lt;code&gt;eval&lt;/code&gt; and
&lt;code&gt;apply&lt;/code&gt; are mutually recursive, which is the one kind of tail call sysl does not turn into a jump, so
&lt;code&gt;eval&lt;/code&gt; carries the loop itself — a tail position reassigns &lt;code&gt;expr&lt;/code&gt; and &lt;code&gt;env&lt;/code&gt; and goes round again. The
claim that made that necessary turned out to need qualifying: built at the default &lt;code&gt;-O1&lt;/code&gt; a mutual
recursion ten million deep returns an answer, because LLVM’s sibling-call pass does what sysl
declined to, and the identical source built &lt;code&gt;--optimize 0&lt;/code&gt; segfaults. The loop stays either way —
what rescued it is a back-end pass rather than a guarantee, and the first argument too large for a
register takes it away again. The &lt;a href=&quot;/reference/functions/&quot;&gt;functions chapter&lt;/a&gt; now says so; it did not
before this program was written.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three recursive walks, and one limit closes all of them.&lt;/strong&gt; The reader, the renderer, and the
non-tail arms of &lt;code&gt;eval&lt;/code&gt; each recurse on nesting — and nothing but the reader ever &lt;em&gt;makes&lt;/em&gt; a nested
value, since &lt;code&gt;cons&lt;/code&gt; grows a list to the right and every walk over one is a loop. So the depth cap
belongs in the reader and nowhere else, and a form the reader accepted is one the other two are
already bounded on. That is a property of how the values are represented rather than of the code, and
it is why the cap is one constant instead of three.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A hundred thousand cons cells come apart without a stack.&lt;/strong&gt; Teardown is
&lt;a href=&quot;/reference/memory/&quot;&gt;iterative&lt;/a&gt; — a count reaching zero drains a worklist rather than recursing — so
dropping a long list is O(1) in stack depth whatever its length. Confirmed here at a scale a
recursive release would not have survived.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Everything the interpreter &lt;em&gt;refuses&lt;/em&gt; is stated in &lt;code&gt;tests.sysl&lt;/code&gt; instead, because a refusal traps and a
trap ends the run rather than reporting into it. The split is itself a claim about where a failure
comes from: a malformed &lt;strong&gt;text&lt;/strong&gt; arrives from outside, so the reader answers with a &lt;code&gt;Result&lt;/code&gt; the run
can check; a malformed &lt;strong&gt;program&lt;/strong&gt; is a bug in the thing being run, and the interpreter stops the way
sysl stops.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Lexical structure</title>
    <link href="https://sysl.sh/reference/lexical/"/>
    <id>https://sysl.sh/reference/lexical/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>What the compiler reads before it parses anything — tokens, literals, and the layout rules that decide where a statement ends.</summary>
    <content type="html">&lt;p&gt;sysl is read in two passes that are worth keeping separate in your head. A &lt;strong&gt;lexer&lt;/strong&gt; turns characters
into tokens and, because the language is indentation-sensitive, also inserts the tokens that open and
close blocks. Only then does a parser see anything. Most of the surprises in a layout-sensitive
language happen in the first pass, which is why it gets its own page.&lt;/p&gt;
&lt;h2 id=&quot;source-text&quot;&gt;Source text&lt;/h2&gt;
&lt;p&gt;Source is &lt;strong&gt;UTF-8&lt;/strong&gt;, and the encoding is not configurable. A non-ASCII character is legal in a
comment, a string literal, and a character literal; identifiers are ASCII (see below).&lt;/p&gt;
&lt;p&gt;Line endings may be LF or CRLF. A file need not end in a newline.&lt;/p&gt;
&lt;h2 id=&quot;comments&quot;&gt;Comments&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;// A line comment runs to the end of the line.&lt;/span&gt;

/* &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt; block comment
   may span lines. */

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; /* and may sit inside a line */ + &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no documentation-comment form with special syntax. Doc text is an ordinary comment above the
declaration it describes.&lt;/p&gt;
&lt;h2 id=&quot;identifiers&quot;&gt;Identifiers&lt;/h2&gt;
&lt;p&gt;An identifier starts with a letter or &lt;code&gt;_&lt;/code&gt; and continues with letters, digits, or &lt;code&gt;_&lt;/code&gt;. Letters are
ASCII &lt;code&gt;A&lt;/code&gt;–&lt;code&gt;Z&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt;–&lt;code&gt;z&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Case is significant. Capitalization is not enforced anywhere, but the convention the standard library
and this documentation follow is &lt;code&gt;PascalCase&lt;/code&gt; for types and traits, &lt;code&gt;snake_case&lt;/code&gt; for everything else —
and the syntax highlighting treats a capitalized name as a type, so following it makes code read
correctly on a page.&lt;/p&gt;
&lt;h3 id=&quot;quoted-identifiers&quot;&gt;Quoted identifiers&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A name written between backticks may be anything the rule above refuses&lt;/strong&gt; — a reserved word, or a
name carrying spaces and punctuation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;`item count`&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;`match`&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;`Grid Cell`&lt;/span&gt;
    &lt;span class=&quot;hl-variable&quot;&gt;`row index`&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;`Grid Cell`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a name and nothing more: &lt;code&gt;`match`&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; the identifier &lt;code&gt;match&lt;/code&gt;. A contextual word written
this way is an ordinary name rather than the word — &lt;code&gt;`end`&lt;/code&gt; names something, and does not close a
block.&lt;/p&gt;
&lt;p&gt;Two characters may not appear inside, and a newline ends the search rather than the name, so an
unclosed backtick is reported on the line that opened it. A &lt;strong&gt;backtick&lt;/strong&gt; cannot appear at all, since
there are no escapes inside. A &lt;strong&gt;&lt;code&gt;.&lt;/code&gt;&lt;/strong&gt; cannot either: a qualified name is carried as a dotted string,
so a dot inside one part could not be told from the separator between two.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;module path&lt;/strong&gt; is written with plain names only, for the same reason — &lt;code&gt;module my.mod&lt;/code&gt;, never
&lt;code&gt;module `my mod` &lt;/code&gt;. A module names a directory, and its parts are what the file system holds.&lt;/p&gt;
&lt;p&gt;The form does a second job in a &lt;code&gt;match&lt;/code&gt; arm, where a backticked name &lt;strong&gt;references&lt;/strong&gt; a variable
already declared rather than binding a new one.&lt;/p&gt;
&lt;h2 id=&quot;reserved-words&quot;&gt;Reserved words&lt;/h2&gt;
&lt;p&gt;Forty words are reserved and may not be used as identifiers:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;alignof&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;as&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;break&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;const&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;continue&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;do&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;elif&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;else&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ensure&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;extern&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;for&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;if&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;impl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;import&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;in&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;loop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;match&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;module&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;offsetof&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;override&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;require&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;return&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sizeof&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;static&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;then&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;trait&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;val&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;var&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;weak&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;while&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;alloc&lt;/code&gt;, &lt;code&gt;no&lt;/code&gt; and &lt;code&gt;requires&lt;/code&gt; are &lt;em&gt;not&lt;/em&gt; among them&lt;/strong&gt;, though they read like keywords where they
appear. A capability is written as an &lt;a href=&quot;/reference/attributes/&quot;&gt;attribute&lt;/a&gt; — &lt;code&gt;@no_alloc&lt;/code&gt;,
&lt;code&gt;@requires(os)&lt;/code&gt; — and an attribute’s words are matched as ordinary identifiers, which is the point of
spelling capabilities that way: no word is spent, so an allocator may still call its function
&lt;code&gt;alloc&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Type names are deliberately not among them.&lt;/strong&gt; &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;usize&lt;/code&gt;, &lt;code&gt;f32&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt; and the rest
are &lt;em&gt;predeclared identifiers&lt;/em&gt; that the analyzer resolves, exactly as in Go and Swift. That is what
lets the &lt;code&gt;iN&lt;/code&gt; / &lt;code&gt;uN&lt;/code&gt; / &lt;code&gt;fN&lt;/code&gt; families stay open: &lt;code&gt;u12&lt;/code&gt; and &lt;code&gt;i5&lt;/code&gt; are types you may write without the
lexer having heard of them, and no list of widths has to be maintained anywhere.&lt;/p&gt;
&lt;p&gt;A few words are &lt;strong&gt;contextual&lt;/strong&gt; — special only where the grammar expects one, and ordinary identifiers
everywhere else: &lt;code&gt;is&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, &lt;code&gt;invariant&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;within&lt;/code&gt;, &lt;code&gt;where&lt;/code&gt;, and the &lt;code&gt;c&lt;/code&gt; of a
&lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c const&lt;/code&gt; or &lt;code&gt;c type&lt;/code&gt;&lt;/a&gt; block. You may name a variable &lt;code&gt;where&lt;/code&gt;; you may not name one
&lt;code&gt;while&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The last of those is the clearest case for why the language spends so few words. &lt;code&gt;c&lt;/code&gt; is the most
common one-letter name in code that handles characters, and what keeps it available is the keyword
that follows it: nothing else in sysl puts one after a name, so each pair can only be the one thing,
and the word costs nobody anything.&lt;/p&gt;
&lt;h2 id=&quot;reserved-identifiers&quot;&gt;Reserved identifiers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An identifier that begins and ends with &lt;code&gt;__&lt;/code&gt;, holding only capitals and underscores in between,
belongs to the language.&lt;/strong&gt; Nothing may declare one — not a function, a type, a &lt;code&gt;val&lt;/code&gt;, a field, a
parameter, a type parameter, or a local.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;__FILE__        reserved
__MY_THING__    reserved — and not a built-in, which is a different thing from being available
____            reserved — the middle may be empty
___             not reserved — the markers may not overlap, so four characters is the shortest
__file__        not reserved — the middle is not capitals
__FILE_         not reserved — one underscore short, and so an ordinary name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The shape is reserved rather than the names in it, which is what makes every future addition
non-breaking: a release that adds a new built-in cannot collide with a name you already declared,
because the shape was never yours to declare. C reserves the same territory and diagnoses nothing in
it; here taking it is refused where it is written.&lt;/p&gt;
&lt;p&gt;These are &lt;strong&gt;predeclared identifiers&lt;/strong&gt;, like the type names above — not reserved words, and absent from
the table.&lt;/p&gt;
&lt;p&gt;The restriction is on sysl names only. The string an &lt;code&gt;extern&lt;/code&gt; links to is untouched, which matters
because a C library’s own symbols live in exactly this space:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;__errno_location&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;errno_location&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-built-ins&quot;&gt;The built-ins&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;identifier&lt;/th&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__FILE__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the file’s name, as a diagnostic prints it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__LINE__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;integer&lt;/td&gt;&lt;td&gt;1-based line&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__COLUMN__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;integer&lt;/td&gt;&lt;td&gt;1-based column&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__FUNCTION__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the enclosing function’s name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__DATE__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;build date, &lt;code&gt;Mmm dd yyyy&lt;/code&gt; (UTC)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;__TIME__&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;build time, &lt;code&gt;hh:mm:ss&lt;/code&gt; (UTC)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;__LINE__&lt;/code&gt; and &lt;code&gt;__COLUMN__&lt;/code&gt; are ordinary integer literals, so each takes the type its context asks
for and is range-checked with it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A built-in written as a default argument reports the caller.&lt;/strong&gt; A default is evaluated at the call,
standing where the argument would have been written, so this needs no special mechanism:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;where&lt;/span&gt;(line: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;__LINE__&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = line

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is how the standard library’s &lt;code&gt;assert&lt;/code&gt; names the line it failed on, and why its message is
optional. Where a default fills another default, the outermost call is the one reported.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;__DATE__&lt;/code&gt; and &lt;code&gt;__TIME__&lt;/code&gt; make a build non-reproducible, in the way C’s do. They are worth having for
a firmware build stamp and worth not reaching for otherwise.&lt;/p&gt;
&lt;h2 id=&quot;literals&quot;&gt;Literals&lt;/h2&gt;
&lt;h3 id=&quot;integers&quot;&gt;Integers&lt;/h3&gt;
&lt;p&gt;Decimal, hexadecimal (&lt;code&gt;0x&lt;/code&gt;), binary (&lt;code&gt;0b&lt;/code&gt;), and octal (&lt;code&gt;0o&lt;/code&gt;). An underscore may appear between digits
and is ignored, so long groupings stay readable. A canonical type name may be written as a &lt;strong&gt;suffix&lt;/strong&gt;;
without one the literal takes its type from context.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; dec = &lt;span class=&quot;hl-number&quot;&gt;1_000_000&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; hex = &lt;span class=&quot;hl-number&quot;&gt;0xFF&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bin = &lt;span class=&quot;hl-number&quot;&gt;0b1010_1010&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; oct = &lt;span class=&quot;hl-number&quot;&gt;0o755&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; suffixed = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(dec, hex, bin, oct, suffixed)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1000000 255 170 493 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The scan is greedy and validated afterwards rather than stopping at the first character that does not
fit. That is why &lt;code&gt;42abc&lt;/code&gt; is &lt;em&gt;one bad literal&lt;/em&gt; and a clear diagnostic, rather than &lt;code&gt;42&lt;/code&gt; followed by an
identifier and a confusing parse error further along.&lt;/p&gt;
&lt;p&gt;An unsuffixed literal adopts the type its context expects, provided the value fits — &lt;code&gt;var x: u8 = 42&lt;/code&gt;
makes &lt;code&gt;42&lt;/code&gt; a &lt;code&gt;u8&lt;/code&gt;, and &lt;code&gt;var x: u8 = 300&lt;/code&gt; is a compile error. This is not implicit promotion: the
literal simply &lt;em&gt;is&lt;/em&gt; that type.&lt;/p&gt;
&lt;h3 id=&quot;floating-point&quot;&gt;Floating point&lt;/h3&gt;
&lt;p&gt;A literal containing a &lt;code&gt;.&lt;/code&gt; with a digit on each side, or an exponent, is floating point. Its default
type is &lt;code&gt;real&lt;/code&gt; (&lt;code&gt;f64&lt;/code&gt;); a suffix selects another width.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f1 = &lt;span class=&quot;hl-number&quot;&gt;3.14&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f2 = &lt;span class=&quot;hl-number&quot;&gt;2.5e3&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f3 = &lt;span class=&quot;hl-number&quot;&gt;1e-3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f1, f2, f3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3.14 2500 0.001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the rendering: a float prints in the shortest form that round-trips, so &lt;code&gt;2.5e3&lt;/code&gt; shows as &lt;code&gt;2500&lt;/code&gt;
and carries no &lt;code&gt;.0&lt;/code&gt;. Hexadecimal, binary and octal have no floating-point form.&lt;/p&gt;
&lt;h3 id=&quot;characters&quot;&gt;Characters&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;char&lt;/code&gt; literal is one Unicode scalar value in single quotes. Nine escapes are named, and anything
else is written with the braced &lt;code&gt;\u{...}&lt;/code&gt; form.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;escape&lt;/th&gt;&lt;th&gt;meaning&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\n&lt;/code&gt;&lt;/td&gt;&lt;td&gt;line feed, U+000A&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\t&lt;/code&gt;&lt;/td&gt;&lt;td&gt;tab, U+0009&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\r&lt;/code&gt;&lt;/td&gt;&lt;td&gt;carriage return, U+000D&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\b&lt;/code&gt;&lt;/td&gt;&lt;td&gt;backspace, U+0008&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\f&lt;/code&gt;&lt;/td&gt;&lt;td&gt;form feed, U+000C&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;NUL, U+0000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\\&lt;/code&gt;&lt;/td&gt;&lt;td&gt;backslash&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\&apos;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;single quote&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;double quote&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;\u{H…}&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one to six hex digits, any Unicode scalar value&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ch = &lt;span class=&quot;hl-string&quot;&gt;&apos;A&apos;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; nl = &lt;span class=&quot;hl-string&quot;&gt;&apos;\n&apos;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bs = &lt;span class=&quot;hl-string&quot;&gt;&apos;\b&apos;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; uni = &lt;span class=&quot;hl-string&quot;&gt;&apos;\u{1F600}&apos;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(ch), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(nl), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(bs), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(uni))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;65 10 8 128512
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The named set is C’s, and is deliberately no larger: the escape a programmer reaches for should be
the one every language they might arrive from has. The notable absence is &lt;strong&gt;&lt;code&gt;\e&lt;/code&gt;&lt;/strong&gt; for the escape
character, U+001B, which some shells and Perl accept — it is a GNU extension rather than standard C,
and Rust and Go both refuse it. Terminal code writes &lt;code&gt;&apos;\u{1b}&apos;&lt;/code&gt; and gives it a name.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; esc = &lt;span class=&quot;hl-string&quot;&gt;&apos;\e&apos;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(esc))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;unknown escape sequence &apos;\e&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;\u{...}&lt;/code&gt; is braced rather than a fixed four hex digits because a scalar value may need up to six —
the fixed-width form is what forces surrogate pairs into source text, and sysl’s &lt;code&gt;char&lt;/code&gt; is a scalar
value rather than a UTF-16 code unit, so there is nothing to pair.&lt;/p&gt;
&lt;h3 id=&quot;strings&quot;&gt;Strings&lt;/h3&gt;
&lt;p&gt;A plain string is double-quoted and decodes the same escapes a &lt;code&gt;char&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;There are several other quote forms, each marked by a prefix on the opening quote:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;code&gt;string&lt;/code&gt; — validated UTF-8, with escapes decoded&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;c&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a C string — the same value with the terminator C expects, read as &lt;code&gt;*u8&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;s&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;interpolated: &lt;code&gt;${expr}&lt;/code&gt; holes rendered with &lt;code&gt;str&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;interpolated with a printf specifier allowed after each hole&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;raw&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no escape processing — a backslash is a backslash&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Any of them may also be written &lt;strong&gt;tripled&lt;/strong&gt; as a text block, which spans lines and strips the common
leading indentation so the text lines up with the code around it rather than against the left margin.&lt;/p&gt;
&lt;p&gt;The forms are told apart at the token, so nothing downstream has to remember which quote produced a
given value.&lt;/p&gt;
&lt;h3 id=&quot;loop-labels&quot;&gt;Loop labels&lt;/h3&gt;
&lt;p&gt;A label is &lt;code&gt;&apos;name&lt;/code&gt; — an apostrophe and an identifier, the form Rust uses. It is told from a character
literal by the &lt;strong&gt;absence of a closing quote&lt;/strong&gt;: &lt;code&gt;&apos;a&apos;&lt;/code&gt; is the character &lt;code&gt;a&lt;/code&gt;, and &lt;code&gt;&apos;a&lt;/code&gt; is the label &lt;code&gt;a&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;true-false-null&quot;&gt;&lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;, &lt;code&gt;null&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Reserved words rather than library constants. &lt;code&gt;null&lt;/code&gt; exists for &lt;code&gt;*T&lt;/code&gt; and only for &lt;code&gt;*T&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;operators-and-delimiters&quot;&gt;Operators and delimiters&lt;/h2&gt;
&lt;p&gt;The operator set is &lt;strong&gt;closed&lt;/strong&gt; — there are no user-defined operator symbols, and no way to add one.
Operators are tokenized by longest match, so &lt;code&gt;..&amp;lt;&lt;/code&gt; wins over &lt;code&gt;..&lt;/code&gt;, and &lt;code&gt;&amp;lt;&amp;lt;=&lt;/code&gt; over &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;=  +=  -=  *=  /=  %=  &amp;amp;=  |=  ^=  &amp;lt;&amp;lt;=  &amp;gt;&amp;gt;=
||  &amp;amp;&amp;amp;  !
==  !=  &amp;lt;  &amp;gt;  &amp;lt;=  &amp;gt;=
..  ..&amp;lt;  ...
|  ^  &amp;amp;  ~
+  -  *  /  %  &amp;lt;&amp;lt;  &amp;gt;&amp;gt;
++  --
(  )  [  ]  {  }  .  ?
.*
,  ::  :  -&amp;gt;
#  ;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two of these are worth a note. &lt;code&gt;.*&lt;/code&gt; is lexed as &lt;strong&gt;one token&lt;/strong&gt; — the tail of a wildcard import — which
is possible because a &lt;code&gt;.&lt;/code&gt; is otherwise only ever followed by a name. And &lt;code&gt;;&lt;/code&gt; is &lt;em&gt;only&lt;/em&gt; a separator
inside a three-clause &lt;code&gt;for&lt;/code&gt; header: it is deliberately not a statement terminator, because a line
already ends a statement and a token that could also end one would give the language two answers to
the same question.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@&lt;/code&gt; opens an annotation and &lt;code&gt;#&lt;/code&gt; opens a directive, and between them they are a declaration’s only
prefixes that are not words. Nothing in the expression grammar spells either, so neither needs
lookahead to recognize. The two are told apart by the sigil and not by the margin, though a directive
is taken by a pass that runs before the lexer and reads only column 1 — so an &lt;em&gt;indented&lt;/em&gt; &lt;code&gt;#&lt;/code&gt; reaches
the grammar like any other token, and &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; says what it is told there.&lt;/p&gt;
&lt;h2 id=&quot;layout&quot;&gt;Layout&lt;/h2&gt;
&lt;p&gt;sysl is indentation-sensitive. Indenting opens a block and dedenting closes it; there are no braces
around statement blocks, and a newline ends a statement.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..n
        total += i

    total

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;brackets-suspend-the-rule&quot;&gt;Brackets suspend the rule&lt;/h3&gt;
&lt;p&gt;Inside &lt;code&gt;(&lt;/code&gt;, &lt;code&gt;[&lt;/code&gt; or &lt;code&gt;{&lt;/code&gt;, layout stops applying until the bracket closes — so an argument list, an array
literal, or a parenthesized expression may be broken across lines however you like, and the
indentation of the continuation lines means nothing.&lt;/p&gt;
&lt;h3 id=&quot;an-unbracketed-line-continues-after-an-operator&quot;&gt;An unbracketed line continues after an operator&lt;/h3&gt;
&lt;p&gt;The rule is the narrowest one that works: &lt;strong&gt;an operator that cannot finish an expression continues the
line.&lt;/strong&gt; After &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; or a prefix &lt;code&gt;!&lt;/code&gt; something must follow, so a newline there cannot
have been the end of a statement and there is nothing ambiguous to resolve.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; +
    &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; +
    &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ok = total &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt; &amp;amp;&amp;amp;
    total &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(total, ok)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What is &lt;em&gt;excluded&lt;/em&gt; follows from the same rule rather than from taste:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;=&lt;/code&gt; and &lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/strong&gt; are binary but already open an indented block — a function body, a match arm, a
&lt;a href=&quot;/reference/declarations/#the-value-may-be-an-indented-block&quot;&gt;binding’s value&lt;/a&gt; — and one token cannot mean
both “the block starts here” and “the line goes on”. A value too long for its line therefore goes
&lt;em&gt;under&lt;/em&gt; the &lt;code&gt;=&lt;/code&gt; as a block rather than after it as a continuation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;++&lt;/code&gt;, &lt;code&gt;--&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;&lt;/strong&gt; are postfix, so a line ending in one is already complete.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;..&lt;/code&gt;, &lt;code&gt;..&amp;lt;&lt;/code&gt; and &lt;code&gt;...&lt;/code&gt;&lt;/strong&gt; can be complete too: &lt;code&gt;s[..]&lt;/code&gt; is the whole range, and &lt;code&gt;int...&lt;/code&gt; is a
variadic tail.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.&lt;/code&gt;&lt;/strong&gt; would work, but the continuation style worth having for a call chain puts the dot at the
&lt;em&gt;start&lt;/em&gt; of the next line, which needs the opposite mechanism.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;the-one-hazard&quot;&gt;The one hazard&lt;/h3&gt;
&lt;p&gt;A continuation line that is &lt;strong&gt;dedented&lt;/strong&gt; has its dedent swallowed along with the newline, so a
trailing operator can hold a block open further than it looks. Every language that joins lines has
this, including on brackets.&lt;/p&gt;
&lt;p&gt;It is documented rather than guarded against, and the reason is worth knowing: guarding would mean
the indentation of a continuation line carried meaning, and the entire point of continuing a line is
that it does not.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>kernel</title>
    <link href="https://sysl.sh/guides/kernel/"/>
    <id>https://sysl.sh/guides/kernel/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The same scheduler with no heap — a fixed table, indices for identity, and a measurement of what references were buying.</summary>
    <content type="html">&lt;p&gt;A priority scheduler with no heap: the same machine as &lt;a href=&quot;/guides/scheduler/&quot;&gt;scheduler&lt;/a&gt;, built out of
a fixed table and index numbers instead of &lt;code&gt;&amp;amp;T&lt;/code&gt; and a run-time allocator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: a program that allocates nothing.&lt;/strong&gt; Every task, every lock, every list and the trace of
the run live in one struct the checks declare as an ordinary local, so the whole machine is a few tens
of kilobytes of storage decided while compiling. Nothing in it makes a &lt;code&gt;&amp;amp;T&lt;/code&gt;, a &lt;code&gt;Buf&lt;/code&gt; or a &lt;code&gt;string&lt;/code&gt; —
one function is the exception, and it is the seam where the machine hands its answer to the reporting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is written to be compared, not just to work.&lt;/strong&gt; The shared scenarios produce byte-identical
schedules to the scheduler’s, so the two programs check each other and the difference between them is
a &lt;em&gt;measurement&lt;/em&gt; of what reference counting was buying.&lt;/p&gt;
&lt;h2 id=&quot;why-it-cannot-say-no-alloc&quot;&gt;Why it cannot say &lt;code&gt;no alloc&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;It is checked rather than asserted: in the emitted code, no function of the machine calls an
allocator. The &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;no alloc&lt;/code&gt; clause&lt;/a&gt; would say that in the source instead, and this
is the program where it does not fit — a capability is a property of the &lt;strong&gt;module&lt;/strong&gt;, both files here
are the root module, and the checks build a string on nearly every line. Even the machine’s own file
would be refused, because the seam that renders the trace is in it. &lt;a href=&quot;/guides/bytecode/&quot;&gt;bytecode&lt;/a&gt;
carries the clause instead, and the only difference is that its machine already lived in a module of
its own. &lt;a href=&quot;/guides/slab/&quot;&gt;slab&lt;/a&gt; sits in exactly the same position.&lt;/p&gt;
&lt;h2 id=&quot;what-the-difference-turned-out-to-be&quot;&gt;What the difference turned out to be&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An index carries nothing, so the table travels with it.&lt;/strong&gt; A &lt;code&gt;&amp;amp;Task&lt;/code&gt; &lt;em&gt;was&lt;/em&gt; a task; a &lt;code&gt;TaskId&lt;/code&gt; is a
number that means something only beside the table. So every method of the run queue takes the table as
a parameter — and not because it wants to look at the tasks, but because the queue’s own links live
inside them. &lt;strong&gt;A data structure that owns no storage cannot be asked a question on its own.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no local name for the task being worked on, and this program is what asked for one.&lt;/strong&gt;
Binding a copy meant every read and every write repeated the path from the table: thirteen occurrences
of one subscript in a single function, where the scheduler next door wrote one name. Taking its
address would have given the name back as a &lt;code&gt;*Task&lt;/code&gt; — the mode this program exists to do without, and
one that drops the bounds and &lt;code&gt;within&lt;/code&gt; checking that made the indices worth having.&lt;/p&gt;
&lt;p&gt;Answered by &lt;a href=&quot;/reference/memory/&quot;&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/a&gt;: the eighty-three paths through the two tables became
forty-three, the walk is made once, the subscript is bounds-checked at the binding instead of at each
use, and the name stays inside every check a written-out path gets — which is the half a pointer could
not have. &lt;strong&gt;What it costs here is nothing at all&lt;/strong&gt;, and that is a property of this program rather than
of the feature: the rule holding storage still while a ref stands on it asks only about steps that
&lt;em&gt;own&lt;/em&gt; what they point at, and a fixed table reached through a raw receiver has none.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A subtype bounds the slot but cannot spell “no slot”.&lt;/strong&gt; &lt;code&gt;TaskId&lt;/code&gt; is &lt;code&gt;u8 within 0..&amp;lt;200&lt;/code&gt;, so a number
that is not a task cannot be made into one and every table index is in range by construction. What it
cannot do is carry the sentinel a kernel would have used — 255 is not a &lt;code&gt;TaskId&lt;/code&gt; — so an empty link is
&lt;code&gt;Option[TaskId]&lt;/code&gt;, a tag beside the byte. The tag is the honest version and the checking is worth the
byte; it is just not the representation the technique is famous for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three bounded identities cannot be confused, and that is the payoff.&lt;/strong&gt; A task number, a lock number
and a priority level are three &lt;code&gt;u8&lt;/code&gt;s with three ranges, and because &lt;code&gt;within&lt;/code&gt; subtypes are &lt;code&gt;new&lt;/code&gt; they
are three &lt;em&gt;types&lt;/em&gt;. Handing a lock number to something expecting a task is the bug a table-driven
kernel actually makes, and here it does not compile.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An array bound and a &lt;code&gt;within&lt;/code&gt; bound name the same &lt;code&gt;const&lt;/code&gt;.&lt;/strong&gt; The table’s size and the range of what
may index it are one fact written once, so the two cannot drift apart. A bound is a constant
&lt;em&gt;expression&lt;/em&gt;, folded like an array bound and an enum discriminant, so this is as ordinary as the array
beside it — and the last magic number is gone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A method on a table entry copies the entry.&lt;/strong&gt; A receiver is a value and there is no reference to
take, so calling a method on a table slot would copy a task with its whole program in it. The
predicates are therefore free functions over the state enum, and every method of the machine takes a
raw &lt;code&gt;self&lt;/code&gt; including the ones that only read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage that is never allocated is never freed either.&lt;/strong&gt; The one thing that gives anything back in a
program like this is a frame at &lt;code&gt;return&lt;/code&gt;, which is why every section of the checks is a function
rather than a run of statements.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/kernel&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/datetime/&quot;&gt;datetime&lt;/a&gt; — a conversion that can succeed twice.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>json</title>
    <link href="https://sysl.sh/guides/json/"/>
    <id>https://sysl.sh/guides/json/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Recursive ownership — a value that contains itself through `&amp;T`, and the program that found the language could not build a string.</summary>
    <content type="html">&lt;p&gt;A JSON reader and writer, checked by round-tripping: parse a document, render it, parse the result,
and assert the two trees agree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: recursive ownership.&lt;/strong&gt; A JSON document is the smallest honest example of a value that
contains itself — an array holds values, and a value may be an array — so the type cannot be written
at all without an &lt;a href=&quot;/reference/memory/&quot;&gt;indirection&lt;/a&gt;, and every walk over it has to take the reference
apart:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Json&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Null&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Bool&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Num&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Str&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Arr&lt;/span&gt;(items: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Json&lt;/span&gt;])
    &lt;span class=&quot;hl-function&quot;&gt;Obj&lt;/span&gt;(fields: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Field&lt;/span&gt;])
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Field&lt;/code&gt; is a struct holding a name and a &lt;code&gt;&amp;amp;Json&lt;/code&gt;, and the &lt;code&gt;&amp;amp;&lt;/code&gt; on that value is the edge that makes
the cycle finite.&lt;/p&gt;
&lt;p&gt;Numbers are integers, and that is a deliberate narrowing rather than a shortcut. A round trip is the
assertion the program is checked by, and a float would make the check about the renderer’s digits
instead of about the tree. Floats are &lt;a href=&quot;/guides/fft/&quot;&gt;another program’s axis&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A pattern does not reach through a reference.&lt;/strong&gt; Field selection does — &lt;code&gt;p.x&lt;/code&gt; works on a &lt;code&gt;&amp;amp;T&lt;/code&gt; — so
the asymmetry is a thing to learn rather than to guess. Every walk in the program starts &lt;code&gt;*j match&lt;/code&gt;,
which is &lt;a href=&quot;/reference/patterns/&quot;&gt;the rule the reference now states outright&lt;/a&gt;: selection dereferences
one level on its own and &lt;code&gt;match&lt;/code&gt; does not, because “am I matching the reference or the thing” should
stay a visible question.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no way to build a &lt;code&gt;string&lt;/code&gt; out of bytes a program computed.&lt;/strong&gt; This is the big one. The
only sources of a string were a literal, a slice of an existing string, concatenation, and &lt;code&gt;str&lt;/code&gt; — so
unescaping was written as &lt;em&gt;“copy the source between the escapes, and append a literal for each”&lt;/em&gt;, and
&lt;code&gt;\uXXXX&lt;/code&gt; reached text only through &lt;code&gt;str(char(n))&lt;/code&gt;, a &lt;strong&gt;rendering&lt;/strong&gt; function standing in for a
constructor.&lt;/p&gt;
&lt;p&gt;Answered by &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;from_utf8&lt;/code&gt;&lt;/a&gt;, which validates a &lt;code&gt;[]u8&lt;/code&gt; into a &lt;code&gt;string&lt;/code&gt;. &lt;code&gt;parse_string&lt;/code&gt;
now gathers into one sink and converts once at the end, and an escape writes the bytes it encodes
rather than being rendered into a string that is immediately concatenated away. &lt;em&gt;The structure that
had been forced is now the structure that is wanted&lt;/em&gt; — which is the best outcome a finding has.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There were no constants.&lt;/strong&gt; A value shared by several functions had to be a nullary function. &lt;code&gt;const&lt;/code&gt;
was added afterwards, for a reason this program did not turn up on its own: a nullary function reads
perfectly well &lt;em&gt;in an expression&lt;/em&gt;, and what it cannot do is be an array bound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no growable collection.&lt;/strong&gt; An array and an object were each a linked list built by
appending through the tail reference — honest for a tree of references, and not what the data is.
Answered by &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;Buf[T]&lt;/code&gt;&lt;/a&gt; reaching the standard library — &lt;code&gt;sysl.buf&lt;/code&gt;, which a program
asks for by name rather than getting for nothing: an array became a &lt;code&gt;&amp;amp;Buf[&amp;amp;Json]&lt;/code&gt; and an
object a &lt;code&gt;&amp;amp;Buf[Field]&lt;/code&gt;. That deleted two list-cell structs, both tail-threading loops, and the two
recursive renderers.&lt;/p&gt;
&lt;h2 id=&quot;worth-noticing&quot;&gt;Worth noticing&lt;/h2&gt;
&lt;p&gt;The depth limit is &lt;code&gt;private const max_depth: int = 64&lt;/code&gt;, and the finding above is why it can be. What
a nullary function could never be is an &lt;strong&gt;array bound&lt;/strong&gt;, which is the case that motivated the form:
as &lt;a href=&quot;/reference/declarations/&quot;&gt;declarations&lt;/a&gt; puts it, a &lt;code&gt;const&lt;/code&gt; is folded into every use and has no
address, and being usable where a constant is &lt;em&gt;demanded&lt;/em&gt; is exactly what that buys.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/json&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/hashmap/&quot;&gt;hashmap&lt;/a&gt; — the trait system under load.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The io module</title>
    <link href="https://sysl.sh/library/io/"/>
    <id>https://sysl.sh/library/io/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.io` — `Reader`, the one trait input travels through; `FdReader` and `stdin()`; and `lines()`, the cursor that borrows what it reads from.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.io&lt;/code&gt; is the &lt;strong&gt;input&lt;/strong&gt; half of the byte surface. It is a module rather than part of the core for a
reason that reads as an asymmetry and is not: &lt;code&gt;print&lt;/code&gt; is a keyword, so what it desugars onto cannot be
behind an import a program has not written — while &lt;strong&gt;nothing in the language desugars onto reading&lt;/strong&gt;.
A program that never takes input never has these names, and one that does said so.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;FdReader&lt;/span&gt;
    fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    bad: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;fd_reader&lt;/span&gt;(fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;FdReader&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;FdReader&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;find_byte&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, c: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
&lt;span class=&quot;hl-function&quot;&gt;line_text&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;try_line_text&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Utf8Error&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;LineEnding&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Lf&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;CrOrLf&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Lines&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;getline&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;try_getline&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Utf8Error&lt;/span&gt;]]

&lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(r: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Lines&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;console_lines&lt;/span&gt;(r: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Lines&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;lines_ending&lt;/span&gt;(r: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;, ending: &lt;span class=&quot;hl-type&quot;&gt;LineEnding&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Lines&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole module. Its shape is &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Writer&lt;/code&gt;&lt;/a&gt; turned around, deliberately: one
method on bytes, a latch rather than a &lt;code&gt;Result&lt;/code&gt;, and &lt;code&gt;*self&lt;/code&gt; on both so a source can be stateful and
still object-safe for a raw trait object — which is what lets a reader need no allocator.&lt;/p&gt;
&lt;h2 id=&quot;the-latch-is-required-not-declared&quot;&gt;The latch is required, not declared&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Reader&lt;/code&gt; requires &lt;code&gt;Fallible&lt;/code&gt; rather than declaring a &lt;code&gt;failed&lt;/code&gt; of its own, and so does &lt;code&gt;Writer&lt;/code&gt;. That
is what lets &lt;strong&gt;one type be a reader and a writer at once&lt;/strong&gt;: a trait’s members become the implementing
type’s, so two traits each declaring their own &lt;code&gt;failed&lt;/code&gt; could not both be implemented for one file.
An open file is both, which is why &lt;a href=&quot;/library/fs/&quot;&gt;&lt;code&gt;sysl.fs&lt;/code&gt;&lt;/a&gt; works at all.&lt;/p&gt;
&lt;p&gt;Leaving it out is caught at the &lt;code&gt;impl&lt;/code&gt;, with the line to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    src: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;sysl.io.Reader&apos; requires &apos;sysl.Fallible&apos;, so &apos;Memory&apos; has to implement that too — write &apos;impl sysl.Fallible for Memory&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;failed&lt;/code&gt; &lt;strong&gt;defaults to &lt;code&gt;false&lt;/code&gt;&lt;/strong&gt;, so a source that cannot fail — an in-memory buffer, a fixed device —
writes &lt;code&gt;impl Fallible for X&lt;/code&gt; with no block at all and says nothing about failure.&lt;/p&gt;
&lt;h2 id=&quot;read-answers-with-the-prefix-it-filled&quot;&gt;&lt;code&gt;read&lt;/code&gt; answers with the prefix it filled&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    src: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src.len - &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at

        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; into.len &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; n = into.len

        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; into[i] = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src[&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at + i]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at += n
        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n]
    &lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;m
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; window: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; got = r.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(window)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(got.len, got[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], got[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; more = r.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(window)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(more.len, more[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 97 104
4 97
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It hands back a slice rather than a count, and that is the one place this surface improves on
&lt;code&gt;read(2)&lt;/code&gt;.&lt;/strong&gt; A slice already &lt;em&gt;is&lt;/em&gt; a length and a pointer: &lt;code&gt;got.len&lt;/code&gt; is the count and &lt;code&gt;got&lt;/code&gt; is what to
look at, so there is no way to be handed the one and forget to apply it to the other — which is the
mistake &lt;code&gt;read(2)&lt;/code&gt;‘s signature invites every time it is called. It costs nothing, since a view is three
words either way.&lt;/p&gt;
&lt;p&gt;The caller supplies the storage, and it has to be writable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;, stdin}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; frozen: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad = r.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(frozen)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;[]const byte&apos; views elements it may not write, and a &apos;[]byte&apos; is a licence to write them — so the one does not become the other
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the &lt;a href=&quot;/reference/types/&quot;&gt;read-only view rule&lt;/a&gt; in the direction it does not travel. A &lt;code&gt;[]T&lt;/code&gt; goes
where a &lt;code&gt;[]const T&lt;/code&gt; is wanted; the reverse would be a licence nobody granted.&lt;/p&gt;
&lt;h2 id=&quot;empty-means-the-end-failed-means-it-ended-badly&quot;&gt;Empty means the end; &lt;code&gt;failed&lt;/code&gt; means it ended badly&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Reading empty says end of input and says only that.&lt;/strong&gt; Whether input ended &lt;em&gt;badly&lt;/em&gt; is a separate
question, and the two are separate because a caller who does not care should not have to ask, and a
caller who does should not have to unwrap a &lt;code&gt;Result&lt;/code&gt; at every read to find out.&lt;/p&gt;
&lt;p&gt;That mapping is &lt;code&gt;read(2)&lt;/code&gt;‘s own — zero for the end, &lt;code&gt;-1&lt;/code&gt; for a failure — so nothing is being conflated
to make the surface tidy.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;, lines}

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Flaky&lt;/span&gt;
    left: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    bad: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Flaky&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Flaky&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.bad

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Flaky&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.left &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
            &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.bad = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.left -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;x&apos;&lt;/span&gt;)
        into[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Flaky&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-type&quot;&gt;Flaky&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;f)
    n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n, f.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The loop ended and the question is still answerable.&lt;/strong&gt; That is the whole reason the next section’s
cursor is shaped the way it is.&lt;/p&gt;
&lt;h2 id=&quot;lines-borrows-its-reader&quot;&gt;&lt;code&gt;lines&lt;/code&gt; borrows its reader&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;, lines}

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    src: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src.len - &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at

        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; into.len &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; n = into.len
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;

        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; into[i] = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src[&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at + i]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at += n
        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n]
    &lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Memory&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; text = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Memory&lt;/span&gt;(text.bytes, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;m)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(line)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(), m.at)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[alpha][beta][gamma]
false 17
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This reader hands back at most six bytes at a time, so &lt;code&gt;&amp;quot;beta\r\n&amp;quot;&lt;/code&gt; spans two reads and &lt;code&gt;&amp;quot;gamma&amp;quot;&lt;/code&gt;
arrives with no newline after it at all. Both come out whole, and the &lt;code&gt;\r&lt;/code&gt; is gone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trailing &lt;code&gt;\r&lt;/code&gt; leaves with the &lt;code&gt;\n&lt;/code&gt;&lt;/strong&gt;, so text written on either system reads the same. That is
&lt;code&gt;bufio.Scanner&lt;/code&gt;‘s choice rather than C &lt;code&gt;getline&lt;/code&gt;‘s, and it is the right one for a language whose
&lt;code&gt;string&lt;/code&gt; is bytes: a program that did not strip it would find &lt;code&gt;line == &amp;quot;beta&amp;quot;&lt;/code&gt; false on half the
world’s files.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lines&lt;/code&gt; takes a &lt;code&gt;*Reader&lt;/code&gt;, and the &lt;code&gt;&amp;amp;&lt;/code&gt; is not decoration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{lines, stdin}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(r)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a *sysl.io.Reader points at a value, so it needs an address — write &apos;&amp;amp;&apos; in front of the sysl.io.FdReader to take one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;for&lt;/code&gt; iterates a &lt;em&gt;copy&lt;/em&gt; of its iterator.&lt;/strong&gt; A &lt;code&gt;Lines&lt;/code&gt; that owned its reader would latch a failure
onto a copy the caller cannot reach, and &lt;code&gt;failed&lt;/code&gt; would be decorative — you could ask it, and the
answer would be about a cursor that no longer exists. Borrowing leaves the reader named in the
caller’s scope, which is what makes &lt;code&gt;r.failed()&lt;/code&gt; answerable &lt;em&gt;after&lt;/em&gt; the loop, the only moment the
question matters. The price is one line at the call site.&lt;/p&gt;
&lt;h3 id=&quot;three-more-decisions-inside-the-cursor&quot;&gt;Three more decisions inside the cursor&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;It scans the slice &lt;code&gt;read&lt;/code&gt; returned, not the one it offered.&lt;/strong&gt; Those are the same memory for a reader
that fills what it was given, so the distinction is free — and it is what lets a reader hand back a
view of a buffer of &lt;em&gt;its own&lt;/em&gt;, never touching the offered one, and still be read correctly. Taking the
&lt;em&gt;length&lt;/em&gt; from the answer and the &lt;em&gt;bytes&lt;/em&gt; from the offer is how the two could have disagreed, and there
is nowhere for them to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A line that fits in one read is never copied.&lt;/strong&gt; The cursor scans its buffer in place; only a line
spanning two reads is gathered, into a &lt;code&gt;Buf[u8]&lt;/code&gt; that is then reused. So the cost is proportional to
the input rather than to the input times the number of refills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A line is found with &lt;code&gt;memchr&lt;/code&gt;&lt;/strong&gt;, through &lt;code&gt;find_byte&lt;/code&gt; — libc’s scans a word at a time where a sysl
loop could not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.find_byte

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;find_byte&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a,b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;,&apos;&lt;/span&gt;)).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;find_byte&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;z&apos;&lt;/span&gt;)).&lt;span class=&quot;hl-function&quot;&gt;is_none&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That function is &lt;a href=&quot;/reference/memory/&quot;&gt;what pointer difference is for&lt;/a&gt;: &lt;code&gt;memchr&lt;/code&gt; answers &lt;em&gt;where&lt;/em&gt; with
an address, and an index is that address minus the first. It is public because a program scanning for
a delimiter of its own wants exactly it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An empty read ends the cursor for good.&lt;/strong&gt; A caller reading again past the end gets &lt;code&gt;None&lt;/code&gt; every
time rather than a second chance, which is right for the sources &lt;code&gt;read(2)&lt;/code&gt; serves.&lt;/p&gt;
&lt;h3 id=&quot;validation-happens-where-the-bytes-arrive&quot;&gt;Validation happens where the bytes arrive&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;getline&lt;/code&gt; yields a &lt;code&gt;string&lt;/code&gt;, not bytes — so input is checked for well-formed UTF-8 at the boundary it
came in at, which is &lt;a href=&quot;/reference/types/&quot;&gt;where the language puts that check&lt;/a&gt;. Ill-formed input stops
the program, naming the byte offset within the line.&lt;/p&gt;
&lt;p&gt;That severity is affordable &lt;strong&gt;because the layer underneath is public&lt;/strong&gt;. A caller who would rather
inspect than trap reads bytes through &lt;code&gt;Reader&lt;/code&gt; and validates them itself with
&lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;from_utf8&lt;/code&gt;&lt;/a&gt;, which is what having two layers is for. &lt;code&gt;line_text&lt;/code&gt; is exported for the
same reason: a program doing its own framing can still get the &lt;code&gt;\r&lt;/code&gt; handling and the validation
without reimplementing either.&lt;/p&gt;
&lt;h3 id=&quot;when-stopping-is-the-wrong-severity&quot;&gt;When stopping is the wrong severity&lt;/h3&gt;
&lt;p&gt;Reading a file you expect to be text, stopping is right — there is nothing sensible to do with the
rest, and carrying on puts the mistake a long way from its cause. Reading a serial port it is not,
and on a freestanding target it is worse than not: &lt;code&gt;exit&lt;/code&gt; there is a halt with no supervisor to
notice it, so one mistyped byte hangs the board.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;try_getline&lt;/code&gt; is the same walk reporting instead, and &lt;code&gt;try_line_text&lt;/code&gt; the same conversion. Two
answers nest — the &lt;code&gt;Option&lt;/code&gt; says whether there was a line at all, the &lt;code&gt;Result&lt;/code&gt; says whether it was
text:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{lines, stdin}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;r)

&lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
    c.&lt;span class=&quot;hl-function&quot;&gt;try_getline&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(line) -&amp;gt;
            line &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
                &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(s) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
                &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;not text, at byte&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.offset)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;getline&lt;/code&gt; is written in terms of it, so there is one place that decides where a line ends and one
that decides what to do about bytes that are not text.&lt;/p&gt;
&lt;h3 id=&quot;a-terminal-does-not-end-a-line-the-way-a-file-does&quot;&gt;A terminal does not end a line the way a file does&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;lines()&lt;/code&gt; splits on &lt;code&gt;\n&lt;/code&gt;, which is right for a file and for a pipe. &lt;strong&gt;A terminal sends a bare &lt;code&gt;\r&lt;/code&gt;
when Enter is pressed&lt;/strong&gt;, so a cursor splitting on LF never sees a line at all: it waits forever,
prints nothing, and looks hung, with nothing to grep for, because nothing has gone wrong — the line
has not ended.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;console_lines&lt;/code&gt; is the same cursor taking CR, LF and CRLF alike.&lt;/strong&gt; Which is right is a property of
where the bytes came from, which the library cannot know: a &lt;code&gt;\r&lt;/code&gt; in the middle of a pipe’s line is a
&lt;code&gt;\r&lt;/code&gt;, and a &lt;code&gt;\r&lt;/code&gt; from a console is a line. So the caller says, and &lt;code&gt;lines()&lt;/code&gt; is unchanged.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.*

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Typed&lt;/span&gt;
    src: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Typed&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Typed&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Typed&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; n &amp;lt; into.len &amp;amp;&amp;amp; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at &amp;lt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src.len
            into[n] = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src[&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at]
            &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
            n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; keys = &lt;span class=&quot;hl-type&quot;&gt;Typed&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;three&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;console_lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;keys)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, line, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[ one ]
[ two ]
[ three ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A bare &lt;code&gt;\r&lt;/code&gt; ends the line immediately rather than waiting to see whether an &lt;code&gt;\n&lt;/code&gt; follows&lt;/strong&gt;, because
on a bare-CR terminal it never does and waiting inside the read would hang until the next keystroke.
What that costs is that the &lt;code&gt;\n&lt;/code&gt; of a &lt;code&gt;\r\n&lt;/code&gt; may arrive in a &lt;em&gt;later read&lt;/em&gt; than its &lt;code&gt;\r&lt;/code&gt;, so the cursor
remembers it is owed one across the refill — which is the case a hand-rolled console reader gets
wrong, producing a spurious empty line between every pair.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lines_ending(r, e)&lt;/code&gt; is the two written out, for a caller holding the policy as a value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Echo and editing are not a line cursor’s business&lt;/strong&gt; — one is about the &lt;em&gt;terminal&lt;/em&gt; and the other
about the &lt;em&gt;line&lt;/em&gt; — and they have to come from somewhere, because a terminal in raw mode shows nothing
as it is typed and a mistake cannot be corrected without them.&lt;/p&gt;
&lt;p&gt;They come from &lt;a href=&quot;/library/term/#reading-a-line-sysl-term-edit&quot;&gt;&lt;code&gt;sysl.term.edit&lt;/code&gt;&lt;/a&gt;, which is this trait’s
other consumer: it edits where nothing else will, and hands back whole lines through the same
&lt;code&gt;Iterate[string]&lt;/code&gt; a &lt;code&gt;Lines&lt;/code&gt; does. &lt;strong&gt;So the two are interchangeable at a call site&lt;/strong&gt;, and which one a
program wants is decided by whether anything else is already doing the editing — the kernel, on a
cooked terminal, and nothing at all over a serial cable.&lt;/p&gt;
&lt;h2 id=&quot;reading-from-memory-and-writing-to-it-bytes-reader-and-bytes-writer&quot;&gt;Reading from memory, and writing to it — &lt;code&gt;bytes_reader&lt;/code&gt; and &lt;code&gt;bytes_writer&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Every &lt;code&gt;Reader&lt;/code&gt; and every &lt;code&gt;Writer&lt;/code&gt; above is a file descriptor, and for a long time that was all there
was — which made a whole class of code awkward to reach: anything taking a &lt;code&gt;*Reader&lt;/code&gt; could only be
exercised by arranging for real input to arrive on a real descriptor.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{bytes_reader, bytes_writer, lines}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; src = &lt;span class=&quot;hl-function&quot;&gt;bytes_reader&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out = &lt;span class=&quot;hl-function&quot;&gt;bytes_writer&lt;/span&gt;()

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;src)
        out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(line.bytes)
        out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(out.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;one|two|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;bytes_reader&lt;/code&gt; &lt;strong&gt;borrows&lt;/strong&gt; what it reads rather than copying it, so one over a large buffer costs
three words; what that asks is that the bytes outlive the reader, which is the ordinary rule for a
slice. A &lt;code&gt;bytes_writer&lt;/code&gt; grows to fit, and &lt;code&gt;view()&lt;/code&gt; hands back everything written so far — a caller
wanting text calls &lt;code&gt;from_utf8&lt;/code&gt; on that view and gets to decide what an ill-formed sequence means,
which is right here, because whatever wrote those bytes is the thing under suspicion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;bytes_reader_at_most(b, n)&lt;/code&gt; hands back at most &lt;code&gt;n&lt;/code&gt; bytes per read, however much room it was
offered&lt;/strong&gt;, and it earns its place: anything reading a stream has cases that arise &lt;em&gt;only&lt;/em&gt; when a unit
of input straddles two reads — the two bytes of a &lt;code&gt;\r\n&lt;/code&gt;, an escape sequence, the continuation bytes
of one character. Those are exactly the cases a hand-rolled reader gets wrong, and a reader that
always empties itself in one go can never produce them. It is also what a slow source honestly looks
like: a serial port hands over what has arrived, not what was asked for.&lt;/p&gt;
&lt;h2 id=&quot;fdreader-and-stdin&quot;&gt;&lt;code&gt;FdReader&lt;/code&gt; and &lt;code&gt;stdin&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{lines, stdin}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;r)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(line)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; r.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;input ended badly&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;stdin()&lt;/code&gt; names the descriptor a program is started with, so a caller does not have to know it is
zero, and &lt;code&gt;fd_reader(fd)&lt;/code&gt; takes any other. &lt;code&gt;FdReader&lt;/code&gt; is the &lt;strong&gt;only&lt;/strong&gt; reader the library supplies —
the mirror of &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;ByteSink&lt;/code&gt;&lt;/a&gt; being the only writer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That symmetry is what makes the freestanding story two functions long.&lt;/strong&gt; The seams a target with no
C library replaces are exactly &lt;code&gt;putbytes&lt;/code&gt;‘ body and &lt;code&gt;FdReader.read&lt;/code&gt;‘s. Swap those two for a &lt;code&gt;write&lt;/code&gt;
and a &lt;code&gt;read&lt;/code&gt; syscall and everything above them is unchanged: every renderer, every &lt;code&gt;Display&lt;/code&gt;, the
whole of &lt;code&gt;lines&lt;/code&gt;, and every &lt;code&gt;impl Reader&lt;/code&gt; a program wrote for itself.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/fs/&quot;&gt;&lt;code&gt;sysl.fs&lt;/code&gt;&lt;/a&gt; — files and paths, and the capability that gates them.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Installation</title>
    <link href="https://sysl.sh/getting-started/installation/"/>
    <id>https://sysl.sh/getting-started/installation/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Install the compiler from the tap, or build it from source.</summary>
    <content type="html">&lt;h2 id=&quot;install&quot;&gt;Install&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;brew install sysl-lang/tap/sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a native binary — there is no JVM under it and nothing to start up. It brings &lt;strong&gt;LLVM&lt;/strong&gt; with
it, which sysl needs at runtime: the compiler emits textual LLVM IR and hands it to &lt;code&gt;clang&lt;/code&gt; to
assemble and link, and &lt;code&gt;llvm-ar&lt;/code&gt; is what builds a library into a &lt;code&gt;.syslib&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It also brings &lt;strong&gt;pkgconf&lt;/strong&gt;. A package that binds an installed C library can name it — &lt;code&gt;requires { pkg_config { sdl3 = &amp;quot;…&amp;quot; } }&lt;/code&gt; — and sysl asks &lt;code&gt;pkg-config&lt;/code&gt; where that library’s headers and link line
are, so building against SDL3 or cairo needs no flags. macOS ships no &lt;code&gt;pkg-config&lt;/code&gt; and the libraries
do not bring one, so the formula does.&lt;/p&gt;
&lt;p&gt;Check it, and see what it offers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl --version
sysl --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;macOS on Apple silicon, and Linux on x86_64 and arm64.&lt;/strong&gt; The tap picks the right one for the
machine it is run on. Anything else builds from source, below.&lt;/p&gt;
&lt;p&gt;The Linux binaries need &lt;strong&gt;glibc 2.34 or newer&lt;/strong&gt; — Ubuntu 22.04, Debian 12, RHEL 9, and anything
later. That is a property of the machine they were built on rather than of sysl, and it is the one
way an install can fail that the formula cannot check for you: &lt;code&gt;version GLIBC_2.34 not found&lt;/code&gt; from
the dynamic loader is this, and not a corrupted download. On an older distribution, build from
source.&lt;/p&gt;
&lt;h2 id=&quot;your-first-compile&quot;&gt;Your first compile&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;echo &apos;main()
    print(&amp;quot;Hello, sysl!&amp;quot;)&apos; &amp;gt; hello.sysl
sysl run hello.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first run prints a line on stderr about building the standard module. That is expected and it
happens once — see below.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sysl build&lt;/code&gt; compiles without running, leaving an executable you can ship:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build hello.sysl -o hello
./hello
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;build-from-source&quot;&gt;Build from source&lt;/h2&gt;
&lt;p&gt;The compiler is a Scala 3 cross-project, so the path in is a clone and an sbt build. You want this if
you are working &lt;em&gt;on&lt;/em&gt; sysl, or if you are on a platform the tap has no binary for.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;JDK 17+&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;the compiler is written in Scala and runs on the JVM&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;sbt 1.12+&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;builds it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;clang&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;sysl emits textual LLVM IR; clang assembles and links it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;llvm-ar&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;only for building a library — a &lt;code&gt;.syslib&lt;/code&gt; is an &lt;code&gt;ar&lt;/code&gt; archive of objects&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;pkg-config&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;only for a package that names an installed C library; without it, say where the library is with &lt;code&gt;--include-path&lt;/code&gt; and &lt;code&gt;--link-path&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;clang&lt;/code&gt; is the only one most systems already have — &lt;code&gt;pkg-config&lt;/code&gt; is common on Linux and absent from a
stock macOS. On macOS the Xcode command-line tools supply
one; on Debian and Ubuntu it is the &lt;code&gt;clang&lt;/code&gt; package.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;llvm-ar&lt;/code&gt; matters only when you build a library of your own, and it has to be the LLVM one: a
&lt;code&gt;.syslib&lt;/code&gt; holds objects for the machine it was built &lt;em&gt;for&lt;/em&gt;, and a platform archiver indexes only
its own format and silently drops the rest. On a Mac, Homebrew keeps its LLVM deliberately off the
&lt;code&gt;PATH&lt;/code&gt;, so sysl looks in &lt;code&gt;/opt/homebrew/opt/llvm/bin&lt;/code&gt; as well. &lt;code&gt;--ar&lt;/code&gt; names one anywhere else.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/sysl-lang/sysl.git
cd sysl
sbt syslJVM/compile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The JVM target is the one to develop against. JS and Native cross-targets exist in the build, and the
Native one is what the released binary is built from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;SYSL_RELEASE=1 sbt syslNative/nativeLink
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without &lt;code&gt;SYSL_RELEASE&lt;/code&gt; that links in debug mode, which is much faster and is what you want while
working on the compiler.&lt;/p&gt;
&lt;h3 id=&quot;check-it&quot;&gt;Check it&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;./run-example.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That compiles &lt;code&gt;examples/hello.sysl&lt;/code&gt; all the way to a native binary and runs it. If you see
&lt;code&gt;Hello, sysl!&lt;/code&gt; followed by a page of output, everything is in place.&lt;/p&gt;
&lt;p&gt;To run a different file, name it — and anything after a &lt;code&gt;--&lt;/code&gt; goes to the program rather than to
sysl:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;./run-example.sh examples/args.sysl -- -n one two
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under the script is the CLI, which you can call directly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sbt &amp;quot;syslJVM/run run examples/hello.sysl&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-standard-library&quot;&gt;The standard library&lt;/h2&gt;
&lt;p&gt;Every program is compiled against the standard module, and &lt;strong&gt;its source ships with the compiler&lt;/strong&gt;.
An install puts it at &lt;code&gt;share/sysl/library&lt;/code&gt; under the install prefix — on a Homebrew Mac that is
&lt;code&gt;$(brew --prefix)/share/sysl/library&lt;/code&gt; — and the compiler finds it from its own location, the way
&lt;code&gt;rustc&lt;/code&gt; finds its sysroot. Running out of a checkout, it is the &lt;code&gt;library/&lt;/code&gt; directory in the tree.
Nothing has to be configured, and there is no variable to set.&lt;/p&gt;
&lt;p&gt;The directory was called &lt;code&gt;lib/&lt;/code&gt; until it was renamed, and both spellings are still looked for with
the new one first — so a compiler installed before the change, and a checkout that has not been
updated, both go on working.&lt;/p&gt;
&lt;p&gt;It is meant to be read. The library is ordinary sysl, laid out as an ordinary sysl library, and
every function in it is one a program could have written; &lt;code&gt;sysl build-lib &amp;lt;root&amp;gt; --std&lt;/code&gt; is the same
command that builds anybody else’s.&lt;/p&gt;
&lt;p&gt;You do not have to build the artifact, either: when nothing usable is at the default path, the
compiler builds it out of that source, says so on stderr, and gets on with the compilation. A fresh
install just works.&lt;/p&gt;
&lt;p&gt;It goes in your cache directory — &lt;code&gt;~/Library/Caches/sysl/&lt;/code&gt; on macOS, &lt;code&gt;~/.cache/sysl/&lt;/code&gt; on Linux, or
wherever &lt;code&gt;XDG_CACHE_HOME&lt;/code&gt; points — under a fingerprint of the library it was built from. So it is
built once per machine rather than once per project, nothing is written into your source tree, and
installing a compiler with a different library gets its own entry instead of a stale hit.
Nothing there is ever evicted, and everything in it is derived: deleting the directory costs one
rebuild.&lt;/p&gt;
&lt;p&gt;Two flags matter when you want something other than that. &lt;code&gt;--std-lib &amp;lt;path&amp;gt;&lt;/code&gt; names an artifact
explicitly, and an artifact you named is never rebuilt behind your back — if it will not read, the
compilation stops and says so. &lt;code&gt;--no-std-lib&lt;/code&gt; compiles the standard module from its source instead
of linking a prebuilt one, with no toolchain involved at all, which is the path the compiler’s own
test suite takes.&lt;/p&gt;
&lt;h2 id=&quot;optimization&quot;&gt;Optimization&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;-O&lt;/code&gt; names the level handed to clang, spelled the way clang spells one — &lt;code&gt;-O2&lt;/code&gt;, &lt;code&gt;-Os&lt;/code&gt;, &lt;code&gt;-O0&lt;/code&gt; — and
it reaches every object a build produces rather than only the final link. It can also be written
&lt;code&gt;--optimize 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The default is &lt;strong&gt;&lt;code&gt;-O1&lt;/code&gt;&lt;/strong&gt;, not off. That is worth knowing because it is unusual: &lt;code&gt;-O0&lt;/code&gt; is a different
instruction selector rather than merely a slower one, it is the mode a back end’s own test suite
covers least, and a real miscompile was found living there. If you drop to &lt;code&gt;-O0&lt;/code&gt; to make something
easier to debug and the behaviour changes, suspect that before your program.&lt;/p&gt;
&lt;h2 id=&quot;if-something-goes-wrong&quot;&gt;If something goes wrong&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;clang: command not found&lt;/code&gt;&lt;/strong&gt; — sysl got as far as emitting IR and had nothing to hand it to.
Install clang and try again. Installing from the tap brings LLVM with it, so this is a
built-from-source problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;llvm-ar&lt;/code&gt; complaints when building a library&lt;/strong&gt; — you have the platform archiver, not LLVM’s.
Point at LLVM’s with &lt;code&gt;--ar /path/to/llvm-ar&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;cannot find the standard module&apos;s source&lt;/code&gt;&lt;/strong&gt; — the compiler could not find the library it ships
with, and the message lists every path it tried. From a package install that means the install is
incomplete: reinstall it. From a checkout it usually means the working directory is not in the tree.
Either way &lt;code&gt;SYSL_LIB=/path/to/library&lt;/code&gt; names the library root outright, where the root is the
directory holding &lt;code&gt;sysl&lt;/code&gt; — that is, the &lt;code&gt;library&lt;/code&gt; above &lt;code&gt;library/sysl&lt;/code&gt;, not &lt;code&gt;library/sysl&lt;/code&gt; itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;sbt is slow on the first run&lt;/strong&gt; — it is downloading Scala and the dependency tree. This happens
once.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Inline assembly</title>
    <link href="https://sysl.sh/reference/inline-assembly/"/>
    <id>https://sysl.sh/reference/inline-assembly/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Machine instructions, in an arm per architecture — where operands are values and the compiler owns the constraint string, the escaping, and the labels.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;asm&lt;/code&gt; reaches the instructions no library can wrap: the privileged ones, the ones that talk to a bus
rather than to memory, and the handful that change the machine the library is running on. It is the
one construct that steps outside the language, and it is shaped so that stepping outside costs as
little as possible — you supply instructions, and nothing else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What you do not supply is the interesting part.&lt;/strong&gt; Which register an operand lands in, how the
value gets there, what the block destroys, how a label avoids colliding with its own second
expansion, how an operand is spelled in the emitted template: each is something the compiler knows,
and each is something that, written by hand, is a comment nothing checks.&lt;/p&gt;
&lt;p&gt;sysl does &lt;strong&gt;not&lt;/strong&gt; ship named functions for “disable interrupts” or “flush the TLB” that expand to
each machine’s instruction. Assembly is the primitive; the architecture layer above it is ordinary
sysl that you write. What the language contributes is that the layer can be &lt;em&gt;checked&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;one-arm-per-architecture&quot;&gt;One arm per architecture&lt;/h2&gt;
&lt;p&gt;An &lt;code&gt;asm&lt;/code&gt; statement is a head with architecture arms indented under it. Exactly one is selected — the
one naming the processor being compiled for — and the others contribute nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;arch_cli&lt;/span&gt;()
    asm
        [x86_64]           &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64]          &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;msr daifset, #2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [riscv64, riscv32] &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrci mstatus, 8&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [thumb]            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cpsid i&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [craft]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrr t0, status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;li t1, -3&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;and t0, t0, t1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrw status, t0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            clobbers &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;t0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [wasm32]           unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a wasm module has no interrupts to disable&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An arm names one processor or several, spelled as &lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;#if&lt;/code&gt;&lt;/a&gt; spells them:
&lt;code&gt;aarch64&lt;/code&gt;, &lt;code&gt;x86_64&lt;/code&gt;, &lt;code&gt;riscv64&lt;/code&gt;, &lt;code&gt;riscv32&lt;/code&gt;, &lt;code&gt;thumb&lt;/code&gt;, &lt;code&gt;x86&lt;/code&gt;, &lt;code&gt;wasm32&lt;/code&gt;, &lt;code&gt;craft&lt;/code&gt;. A name outside that
set is an error rather than a machine nobody has heard of.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;wasm32&lt;/code&gt; is the one that is not a processor&lt;/strong&gt;, and it will not carry instructions at all: a wasm
module has no registers to name and no assembler behind it. Its arm is therefore always empty or
&lt;code&gt;unavailable&lt;/code&gt; — both forms are below — which makes it the standing reminder that these arms are
about &lt;em&gt;targets&lt;/em&gt; rather than about chips.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;craft&lt;/code&gt; is 16-bit, and its arms are the ones worth reading twice.&lt;/strong&gt; It has three-operand
arithmetic and eight registers, so &lt;code&gt;mv&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; are spelled as RISC-V spells them — but it has no
logical immediate and no bit-clear on a control register, so clearing one bit of &lt;code&gt;status&lt;/code&gt; is a
read-modify-write through two scratch registers rather than the one instruction every other machine
here writes. That is what a deliberately small instruction set costs, stated where somebody can see
it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;riscv32&lt;/code&gt; and &lt;code&gt;thumb&lt;/code&gt; are one board’s two halves&lt;/strong&gt;, which is why they are usually written together
in what follows. The RP2350 boots either a pair of Cortex-M33s or a pair of RV32IMAC cores, and a
microcontroller is what inline assembly is mostly for. &lt;code&gt;thumb&lt;/code&gt; rather than &lt;code&gt;arm&lt;/code&gt; names the Arm one
because a Cortex-M executes Thumb only — an arm written for A32 would assemble for a machine that
cannot run it, and the name is what says so.&lt;/p&gt;
&lt;p&gt;Here is a whole program. &lt;code&gt;yield&lt;/code&gt;, &lt;code&gt;pause&lt;/code&gt; and &lt;code&gt;nop&lt;/code&gt; are each their machine’s hint that a spin loop is
spinning, which is about as small as a real use of this construct gets:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;spin_hint&lt;/span&gt;()
    asm
        [x86_64]           &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pause&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64, thumb]   &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [riscv64, riscv32] &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nop&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [craft]            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nop&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [wasm32]

&lt;span class=&quot;hl-function&quot;&gt;spin_hint&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hinted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hinted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Square brackets rather than a &lt;code&gt;match&lt;/code&gt; arm’s &lt;code&gt;-&amp;gt;&lt;/code&gt;.&lt;/strong&gt; Brackets are already what sysl writes around
things resolved at compile time — a type parameter list, &lt;code&gt;Option[T]&lt;/code&gt; — and the arrow is what it
writes between a runtime pattern and its body. An architecture is not a value being tested: the arms
not chosen do not exist in the output at all.&lt;/p&gt;
&lt;h2 id=&quot;every-architecture-needs-an-answer&quot;&gt;Every architecture needs an answer&lt;/h2&gt;
&lt;p&gt;The arms must cover every processor a target can be built for, not merely the one you are building
for now. A missing arm is an error on &lt;strong&gt;every&lt;/strong&gt; build:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;halt&lt;/span&gt;()
    asm
        [x86_64] &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hlt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;halt&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this assembly has no arm for &apos;aarch64&apos;, &apos;riscv64&apos;, &apos;riscv32&apos;, &apos;thumb&apos;, &apos;wasm32&apos; or &apos;craft&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the rule &lt;code&gt;#if&lt;/code&gt; follows one level up, where every condition is checked in the branches being
skipped as well as the one being taken. Here it reaches past whether a branch &lt;em&gt;parses&lt;/em&gt; to whether one
&lt;em&gt;exists&lt;/em&gt; — so a forgotten processor is found by whoever forgot it, rather than by whoever first
builds for the machine that was left out.&lt;/p&gt;
&lt;h3 id=&quot;when-there-is-genuinely-no-answer&quot;&gt;When there is genuinely no answer&lt;/h3&gt;
&lt;p&gt;Some assembly is unportable in principle rather than by omission. &lt;code&gt;outb&lt;/code&gt; and &lt;code&gt;inb&lt;/code&gt; are x86’s; every
other processor here reaches devices through memory and has no equivalent at all. Such an
architecture says so, and says why:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;port_out&lt;/span&gt;(port: &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;, value: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;outb {value}, {port}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; port : &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; value : &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;al&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64, riscv64, riscv32, thumb, craft, wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;port I/O is x86-only; devices are reached through memory&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The x86-64 build compiles that. A build for a processor the arm covers is refused, and the reason
travels into the diagnostic — which is the whole of what this form buys over leaving the arm out,
since leaving it out fails &lt;em&gt;every&lt;/em&gt; build instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;port_out&lt;/span&gt;()
    asm
        [x86_64] &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;outb %al, %dx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64, riscv64, riscv32, thumb, craft, wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;port I/O is x86-only; devices are reached through memory&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;port_out&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;port I/O is x86-only; devices are reached through memory
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;when-the-answer-is-no-instruction&quot;&gt;When the answer is no instruction&lt;/h3&gt;
&lt;p&gt;An arm written with nothing under it is an answer too: this processor needs no instruction. A memory
barrier is free on a machine that never reordered the accesses in question, and &lt;code&gt;unavailable&lt;/code&gt; would
be false there — the operation is available, it simply costs nothing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;barrier&lt;/span&gt;()
    asm
        [x86_64]
        [aarch64]          &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dmb ish&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [thumb]            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dmb sy&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [riscv64, riscv32] &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;fence rw, rw&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [craft]
        [wasm32]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An empty arm cannot be confused with a forgotten one, because a forgotten arm is not empty — it is
absent, and absent is the error above.&lt;/p&gt;
&lt;h2 id=&quot;operands-are-values-not-registers&quot;&gt;Operands are values, not registers&lt;/h2&gt;
&lt;p&gt;An operand names a variable already in scope, gives its direction, and gives the register class or
the machine register it must occupy. The template refers to it by that same name in braces:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;copy&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;movl {n}, {v}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; n : reg
            out v : reg
        [aarch64, thumb]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mov {v}, {n}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; n : reg
            out v : reg
        [riscv64, riscv32, craft]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mv {v}, {n}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; n : reg
            out v : reg
        [wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;there are no registers for an operand to land in&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    v

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;copy&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;reg&lt;/code&gt; means &lt;em&gt;any general-purpose register the allocator likes&lt;/em&gt;, and it is the only class there is.
Where an instruction demands a particular register, name it — quoted, because it is the assembler’s
name and not sysl’s:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;out_byte&lt;/span&gt;(port: &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;, value: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;outb {value}, {port}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; port : &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; value : &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;al&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64, riscv64, riscv32, thumb, craft, wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;port I/O is x86-only&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A bare word is sysl’s and a quoted word is the assembler’s.&lt;/strong&gt; That rule decides every case in the
construct: &lt;code&gt;reg&lt;/code&gt; is a class this language names, &lt;code&gt;&amp;quot;dx&amp;quot;&lt;/code&gt; is a register only the assembler knows, and
instruction text is quoted because sysl does not read it.&lt;/p&gt;
&lt;p&gt;The class slot is required even though &lt;code&gt;reg&lt;/code&gt; is currently the only class. Writing it keeps every
operand line one shape, so a second class arrives as a peer rather than as the exception to an
invisible default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;:&lt;/code&gt; here is not a type annotation.&lt;/strong&gt; An operand names a variable that already has a type, so
there is nothing left to declare — the slot holds a class or a register.&lt;/p&gt;
&lt;h3 id=&quot;what-an-operand-may-be&quot;&gt;What an operand may be&lt;/h3&gt;
&lt;p&gt;An operand must be a plain variable, and its type must fit a general-purpose register: the integers,
the pointers, &lt;code&gt;bool&lt;/code&gt;. A float needs a floating class, which does not exist yet.&lt;/p&gt;
&lt;p&gt;Reading and writing the same variable is refused, because it is two operands and so possibly two
registers — the instructions would read one and write another:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;addl {n}, {n}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; n : reg
            out n : reg
        [aarch64, thumb, riscv64, riscv32, craft]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;add {n}, {n}, {n}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; n : reg
            out n : reg
        [wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;there are no registers for an operand to land in&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;both read and written here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Only the &lt;strong&gt;selected&lt;/strong&gt; arm’s operands are checked, since the others describe machines this build is
not for. So a mistake in an arm is reported by a build for that arm’s processor — which is the same
bargain exhaustiveness makes, one level down.&lt;/p&gt;
&lt;h2 id=&quot;what-the-block-destroys&quot;&gt;What the block destroys&lt;/h2&gt;
&lt;p&gt;An arm may name registers it destroys beyond its operands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nop&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            clobbers &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rax&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rdx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64, riscv64, riscv32, thumb, craft, wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x86 only here&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Memory and the condition flags are assumed clobbered, always&lt;/strong&gt;, and cannot currently be given
back. That is the conservative direction on purpose: assuming them costs optimization quality across
a handful of instructions, and not assuming them costs a value kept in a register the block
overwrote — a wrong answer with nothing to point at.&lt;/p&gt;
&lt;p&gt;Registers cannot be treated the same way. “Everything is clobbered” is a legal assumption and a
useless one, so the registers an arm destroys are the one part of its effect you have to state.&lt;/p&gt;
&lt;h2 id=&quot;what-the-compiler-owns&quot;&gt;What the compiler owns&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Operand substitution and its escaping.&lt;/strong&gt; &lt;code&gt;$&lt;/code&gt; is LLVM’s own operand marker, so a &lt;code&gt;$&lt;/code&gt; you write — an
x86 immediate, &lt;code&gt;movq $1, %rsi&lt;/code&gt; — is doubled by the compiler rather than by you. A doubled brace is a
literal one, which is not a nicety: ARM writes register lists as &lt;code&gt;{r0-r3}&lt;/code&gt;, so &lt;code&gt;push {{lr}}&lt;/code&gt; is how
you spell &lt;code&gt;push {lr}&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Label uniqueness.&lt;/strong&gt; A label in an arm is local to that arm’s expansion, and a block emitted twice
gets two distinct labels. A label in inline assembly is otherwise a global symbol, and the second
definition is a duplicate the assembler rejects for reasons you cannot do anything about from where
you are standing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Line joining.&lt;/strong&gt; Instructions are separate strings on separate lines, each able to carry a comment.
This is the difference between an assembly routine that can be read and a six-instruction spinlock
written on one line with &lt;code&gt;\n&lt;/code&gt; between the instructions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The constraint string&lt;/strong&gt;, which you never write, because a constraint that disagrees with the
instruction text is not detectable by reading either one.&lt;/p&gt;
&lt;h2 id=&quot;the-words-this-construct-spends&quot;&gt;The words this construct spends&lt;/h2&gt;
&lt;p&gt;None of them is reserved. &lt;code&gt;asm&lt;/code&gt;, &lt;code&gt;unavailable&lt;/code&gt;, &lt;code&gt;out&lt;/code&gt;, &lt;code&gt;reg&lt;/code&gt; and &lt;code&gt;clobbers&lt;/code&gt; are contextual: each is
recognized in exactly one position and is an ordinary identifier everywhere else — including inside
an assembly block, in any other position.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; reg = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; clobbers = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; asm = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
    out + reg + clobbers + asm

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;in&lt;/code&gt; is a reserved word already, for &lt;code&gt;for x in xs&lt;/code&gt;, and is reused here rather than added to.&lt;/p&gt;
&lt;h2 id=&quot;where-assembly-may-not-go&quot;&gt;Where assembly may not go&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Not in a &lt;code&gt;require&lt;/code&gt; or &lt;code&gt;ensure&lt;/code&gt; condition&lt;/strong&gt; — and there is no check that says so, because there is
no way to write it: a contract’s condition is an expression and assembly is a statement. A contract
is a claim the compiler reasons about and an assembly block is precisely what it cannot reason
about, so the two never meeting is a property to rely on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing about a block’s contents is understood, including whether control comes back.&lt;/strong&gt; The
compiler does not read the instructions, so it cannot know that a jump to a reset vector never
returns — and it does not try. A function declared &lt;code&gt;-&amp;gt; never&lt;/code&gt; with an assembly body is taken at its
word, exactly as anything else declared not to return is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;arch_reset&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;never&lt;/span&gt;
    asm
        [x86_64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cli&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1: hlt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;jmp 1b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [aarch64]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;msr daifset, #2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1: wfi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b 1b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [thumb]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cpsid i&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1: wfi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b 1b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [riscv64, riscv32]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrci mstatus, 8&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1: wfi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;j 1b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [craft]
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrr t0, status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;li t1, -3&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;and t0, t0, t1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;csrw status, t0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;wfi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
            clobbers &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;t0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;t1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        [wasm32] unavailable &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a wasm module cannot halt its host&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The promise is yours to keep here, which is true of the instructions themselves anyway.&lt;/p&gt;
&lt;h2 id=&quot;what-is-not-here-yet&quot;&gt;What is not here yet&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;inout&lt;/code&gt;&lt;/strong&gt; — a read-modify-write operand. The instructions wanting one are the exchange and
compare-exchange family, which &lt;a href=&quot;/library/&quot;&gt;&lt;code&gt;sysl.sync&lt;/code&gt;&lt;/a&gt; already covers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Giving memory and the flags back&lt;/strong&gt;, which is an optimization over an answer that is currently
always correct.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A floating register class.&lt;/strong&gt; It cannot be a single one: bare-metal RISC-V has no floating
registers to name.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>hashmap</title>
    <link href="https://sysl.sh/guides/hashmap/"/>
    <id>https://sysl.sh/guides/hashmap/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The trait system under load — bounds, what they promise, and ownership all having to agree at once.</summary>
    <content type="html">&lt;p&gt;A hash map, generic in its key and its value. Chained: a bucket is a list of entries, an entry is a
&lt;code&gt;&amp;amp;Entry&lt;/code&gt; so the list can hold itself, and the bucket array grows by doubling with everything rehashed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: the trait system under load.&lt;/strong&gt; A container is where bounds, the behaviour they promise,
and ownership all have to agree at the same time — the map hashes and compares a key it knows nothing
else about, it holds keys and values it did not make, and it hands entries back out while still
owning them. Nothing else in the set asks for all three at once.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;There was no &lt;code&gt;Hash&lt;/code&gt; in the core catalogue.&lt;/strong&gt; There were &lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; — enough to sort with,
not enough to key on — so the map declared its own, with an &lt;code&gt;impl&lt;/code&gt; for every key type it wanted to
support. That was never a style problem. &lt;a href=&quot;/reference/traits/&quot;&gt;Coherence&lt;/a&gt; lets an &lt;code&gt;impl&lt;/code&gt; live only
with its trait or with its type, so two libraries that each declare a &lt;code&gt;Hash&lt;/code&gt; can &lt;strong&gt;never&lt;/strong&gt; share a
key type’s implementation, and a program using both writes the same hash twice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Hash&lt;/code&gt; is now a &lt;a href=&quot;/library/core/&quot;&gt;core trait&lt;/a&gt;, which deleted a trait, two &lt;code&gt;impl&lt;/code&gt;s and an avalanche
function from the program. The built-in mixing is the same splitmix64 finalizer the map used to
carry, in the one place every container can reach it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An enum has no zero value, so an array of them could not be declared.&lt;/strong&gt;
&lt;code&gt;var cells: [16]Option[&amp;amp;Entry[K, V]]&lt;/code&gt; is refused. Answered by the repeat form &lt;code&gt;[None; n]&lt;/code&gt;, which
fills storage from a &lt;em&gt;value&lt;/em&gt; instead of from a zero — before that, it was sixteen &lt;code&gt;None&lt;/code&gt;s written
out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Generically it was worse, and the reason has since narrowed.&lt;/strong&gt; A repeat needs a value in its value
position and a bound could promise none, so a generic container could not make its own storage unless
it already held something to fill it with. A trait member may now have no receiver, so a bound &lt;em&gt;can&lt;/em&gt;
promise a value and &lt;code&gt;[K.blank(); n]&lt;/code&gt; is ordinary code.&lt;/p&gt;
&lt;p&gt;What is left is worth being exact about, because it is a real remaining limit rather than a fixed
one: no trait sysl ships declares such a member, so a container over &lt;em&gt;every&lt;/em&gt; &lt;code&gt;K&lt;/code&gt; still cannot make a
&lt;code&gt;[16]K&lt;/code&gt;. A container over the types a program names can, by declaring the trait itself. The map’s
table stays &lt;code&gt;Option[…]&lt;/code&gt; — and now because &lt;code&gt;None&lt;/code&gt; needs nothing of &lt;code&gt;K&lt;/code&gt; and &lt;code&gt;V&lt;/code&gt;, rather than because
nothing else was available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage could not be asked for at a size worked out while running.&lt;/strong&gt; The table was a fixed
directory of fixed blocks with its capacity in its own type: it doubled up to &lt;code&gt;max_blocks&lt;/code&gt; and then
stopped, staying correct with lengthening chains. Answered by an array form written where a &lt;code&gt;[]T&lt;/code&gt; is
expected making &lt;a href=&quot;/reference/arrays/&quot;&gt;storage of its own&lt;/a&gt; that the view owns — so the table became one
flat run of buckets that doubles for as long as there are keys. That deleted a directory, a block,
two constructors, two constants, and the ceiling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bucket is named rather than re-indexed.&lt;/strong&gt; &lt;code&gt;ref bucket = self.cell[self.index(k)]&lt;/code&gt; names the slot,
so &lt;code&gt;put&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; each hash once and walk the table once instead of writing the path out at every
read and write. That is &lt;a href=&quot;/reference/memory/&quot;&gt;&lt;code&gt;ref&lt;/code&gt;&lt;/a&gt; doing the job it exists for, in the first program
that wanted it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/hashmap&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/bytecode/&quot;&gt;bytecode&lt;/a&gt; — the module system, end to end.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The harness module</title>
    <link href="https://sysl.sh/library/harness/"/>
    <id>https://sysl.sh/library/harness/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.harness` — a test framework that runs on the target: named tests, a located failure with both values rendered, three verdicts and a tally, with no allocator, no operating system and no debug host underneath.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.harness&lt;/code&gt; is how a program checks itself &lt;strong&gt;on the machine it was built for&lt;/strong&gt;. It is the same
shape as C’s &lt;a href=&quot;https://www.throwtheswitch.org/unity&quot;&gt;Unity&lt;/a&gt;, and it exists for the same reason: the
host’s test runner cannot follow the code onto a board.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;/getting-started/cli/&quot;&gt;&lt;code&gt;sysl test&lt;/code&gt;&lt;/a&gt; is the host’s answer and cannot be this one.&lt;/strong&gt; It starts a
process per test, selects one by &lt;code&gt;argv&lt;/code&gt;, and reads the verdict out of an exit status. A
microcontroller has no processes, no &lt;code&gt;argv&lt;/code&gt; and nobody to read an exit status. So the checking has to
be written in the language and linked into the image, and what comes out is a report on a wire.&lt;/p&gt;
&lt;p&gt;The two are not rivals. Use &lt;code&gt;sysl test&lt;/code&gt; for everything that can run on the machine you are typing on
— it is faster, it isolates each test in its own process, and it needs no arrangements. Reach for
this when the thing you want to check only exists on the target: a driver against real registers, a
timing loop, arithmetic at a width the host does not have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing here allocates, opens anything, or asks the system for a service.&lt;/strong&gt; Its state is a fixed
number of bytes laid into the image, and every value it prints renders itself into a sink rather than
into a fresh string.&lt;/p&gt;
&lt;h2 id=&quot;a-suite&quot;&gt;A suite&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.harness.*

&lt;span class=&quot;hl-function&quot;&gt;adds&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;check_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;holds&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one is less than two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;adds&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;adds)
&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;holds&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;holds)
&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;page&amp;gt;:9:adds:PASS
&amp;lt;page&amp;gt;:10:holds:PASS
2 tests, 0 failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The file is &lt;code&gt;&amp;lt;page&amp;gt;&lt;/code&gt; because this example is a block on a web page; where you run it, it is your
file’s name.&lt;/p&gt;
&lt;p&gt;A test is an ordinary function of no arguments, and &lt;code&gt;run&lt;/code&gt; names it and calls it. &lt;strong&gt;The name is
written twice on purpose&lt;/strong&gt; — once as the function and once as the string — because the string is what
the report says, and a report that said &lt;code&gt;adds&lt;/code&gt; when the interesting thing was &lt;em&gt;addition after the
clock was reconfigured&lt;/em&gt; would be worse for having been derived automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;adds&lt;/code&gt; is a pointer to a function, not a closure.&lt;/strong&gt; &lt;code&gt;run&lt;/code&gt; takes &lt;code&gt;*extern() -&amp;gt; unit&lt;/code&gt;, which is one
word and one copy of &lt;code&gt;run&lt;/code&gt; for the whole suite; a bare arrow would be a bound over &lt;code&gt;Fn&lt;/code&gt;, monomorphized
per test — thirty tests, thirty copies of the runner — and flash is what a target has least of. The
cost is the &lt;code&gt;&amp;amp;&lt;/code&gt;, and the restriction that a test body captures nothing, which is what a test body is
anyway.&lt;/p&gt;
&lt;h2 id=&quot;a-failure-says-where-and-what-the-values-were&quot;&gt;A failure says where, and what the values were&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.harness.*

&lt;span class=&quot;hl-function&quot;&gt;adds&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;check_eq&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;adds&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;adds)
&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;page&amp;gt;:4:adds:FAIL: got 4, want 5
1 tests, 1 failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A passing test reports the line of the &lt;code&gt;run&lt;/code&gt; that named it and a failing one the line of the check
that failed&lt;/strong&gt; — 6 and 4 here. Both fall out of the same rule and neither is a special case: &lt;code&gt;run&lt;/code&gt;,
&lt;code&gt;skip&lt;/code&gt; and every check take &lt;code&gt;file&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt; as defaulted parameters, and a default is evaluated at
the call, so &lt;code&gt;__FILE__&lt;/code&gt; and &lt;code&gt;__LINE__&lt;/code&gt; written once in each declaration hold whatever line the reader
wrote. You never pass either.&lt;/p&gt;
&lt;p&gt;The line is &lt;code&gt;file:line:test:verdict&lt;/code&gt;, which is Unity’s order, so the editors and CI filters that
already read that format read this one.&lt;/p&gt;
&lt;p&gt;That is the whole difference between this and a program printing characters as it goes. A board that
says &lt;code&gt;abcdyx4&lt;/code&gt; has told you something went wrong and nothing about which check, on which line, with
which values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;got&lt;/code&gt; then &lt;code&gt;want&lt;/code&gt;&lt;/strong&gt;, which is the order &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;assert_eq&lt;/code&gt;&lt;/a&gt; takes next door and the order
a failure is read in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A failing check does not stop the test.&lt;/strong&gt; Unity aborts with &lt;code&gt;longjmp&lt;/code&gt;; sysl has none, and an unwind
that skipped a scope would skip the releases that scope owes. So a failure is recorded and the test
runs on — and only the &lt;strong&gt;first&lt;/strong&gt; failure in each test is reported, because the ones after it are
usually the same failure seen again through worse state.&lt;/p&gt;
&lt;h3 id=&quot;the-checks&quot;&gt;The checks&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;check(cond, msg = &amp;quot;&amp;quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a condition that has to hold&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;check_eq[T: Eq + Display](got, want)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;two values that have to be equal, both rendered when they are not&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;check_slice_eq[T: Eq + Display](got, want)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same for a &lt;code&gt;[]const T&lt;/code&gt;, naming the index that differs&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;One generic member stands in for Unity’s several hundred assertion macros and does more than they
can: &lt;code&gt;TEST_ASSERT_EQUAL_*&lt;/code&gt; covers a fixed list of C’s own types and falls back to a hex dump of the
bytes for anything a program defined, while a bound reaches &lt;strong&gt;any&lt;/strong&gt; type at all that can say whether
two of it are equal and write itself down.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;check_slice_eq&lt;/code&gt; says where, because a report that two slices differ sends its reader to find out —
and finding out is a loop nobody wants to write at each call, least of all on a board where the way
to look is a debugger and a stopped core:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.harness.*

&lt;span class=&quot;hl-function&quot;&gt;bytes&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;check_slice_eq&lt;/span&gt;([&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)], [&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)])

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;bytes)
&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;page&amp;gt;:4:bytes:FAIL: got 2, want 9 at index 1
1 tests, 1 failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Length first, since a length mismatch explains every index after the shorter one.&lt;/p&gt;
&lt;h2 id=&quot;three-verdicts-because-a-board-needs-the-third&quot;&gt;Three verdicts, because a board needs the third&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.harness.*

&lt;span class=&quot;hl-function&quot;&gt;reads_adc&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;check&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;reads_adc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;reads_adc)
&lt;span class=&quot;hl-function&quot;&gt;skip&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;reads_thermocouple&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no part fitted&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;finish&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;page&amp;gt;:6:reads_adc:PASS
&amp;lt;page&amp;gt;:7:reads_thermocouple:SKIP: no part fitted
1 tests, 0 failed, 1 skipped
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;On the host a test that cannot run is usually a test that should be deleted; on a target it is
routine&lt;/strong&gt; — the part is not fitted, the bus is wired for the other variant, the flash is the smaller
one. Counting those as passes says something false and counting them as failures says something
worse, so they are counted as themselves.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;skip&lt;/code&gt; takes the &lt;em&gt;name&lt;/em&gt; rather than the body, because the body is exactly what is not going to be
called.&lt;/p&gt;
&lt;h2 id=&quot;saying-where-the-report-goes&quot;&gt;Saying where the report goes&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;attach&lt;/code&gt; points the framework at a writer of your own, which is what a board does before it runs
anything:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.harness.*
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; board.*

&lt;span class=&quot;hl-function&quot;&gt;attach&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;console&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Given none, it writes to standard output — resolved on &lt;strong&gt;first use&lt;/strong&gt;, which matters to every program
that never mentions testing: a module’s storage is initialized in every image the library is linked
into, and a sink stored eagerly would put a trait object through the reference counter, whose release
path names &lt;code&gt;free&lt;/code&gt;. A program on a bare board would acquire a call to an allocator it has not got. A
null pointer is a stored zero and reaches nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A board’s console is ordinary sysl.&lt;/strong&gt; A UART is a volatile store through a pointer, which is a
&lt;a href=&quot;/reference/statements/&quot;&gt;language feature&lt;/a&gt;, so reaching one needs no &lt;code&gt;asm&lt;/code&gt;, no semihosting and no C
library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;board&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt;
    data: volatile &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;UART&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0x10000000&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; regs: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Uart&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;UART&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;putc&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    regs.data = c

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Console&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Console&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Console&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Console&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, bytes: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; bytes &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;putc&lt;/span&gt;(b)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Console&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; uart: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Console&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0usize&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;console&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; = uart&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a real one — QEMU’s &lt;code&gt;virt&lt;/code&gt; puts a 16550 at &lt;code&gt;0x10000000&lt;/code&gt;, and the compiler’s own board tests
use these lines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Writer&lt;/code&gt; requires &lt;code&gt;Fallible&lt;/code&gt;, so the empty &lt;code&gt;impl Fallible&lt;/code&gt; is not a formality&lt;/strong&gt; — it takes the
default &lt;code&gt;failed&lt;/code&gt;, which answers false. A UART that cannot fail has nothing to add.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Console&lt;/code&gt; has no fields, so its receiver is a null pointer.&lt;/strong&gt; A trait object is two words, a method
table and a datum, and &lt;code&gt;write&lt;/code&gt; here never looks at the datum — everything it needs is the module’s
own &lt;code&gt;regs&lt;/code&gt;. Given nothing to point at, &lt;code&gt;ptr_cast(0usize)&lt;/code&gt; is the honest spelling; the alternative
would be to take the address of a temporary, which is a dangling pointer with better manners.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And it has to be a module of its own rather than the file your statements are in.&lt;/strong&gt; An &lt;code&gt;impl&lt;/code&gt;
member cannot see a root file’s top-level bindings, so &lt;code&gt;write&lt;/code&gt; could reach neither &lt;code&gt;regs&lt;/code&gt; nor &lt;code&gt;putc&lt;/code&gt;.
One directory down it is ordinary code.&lt;/p&gt;
&lt;h2 id=&quot;the-verdict-and-what-to-do-with-it&quot;&gt;The verdict, and what to do with it&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tests_run() -&amp;gt; int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;how many ran&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;failures() -&amp;gt; int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;how many failed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skipped() -&amp;gt; int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;how many were skipped&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;finish() -&amp;gt; i32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;print the tally, and answer &lt;code&gt;0&lt;/code&gt; if everything passed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiet: bool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;when true, nothing is printed and only the counters move&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;reset()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;zero the counters, for a suite that runs more than once&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;finish&lt;/code&gt; returns rather than exits, and that is the whole of what makes this framework portable.&lt;/strong&gt;
A hosted program writes &lt;code&gt;exit(finish())&lt;/code&gt;. A board has no &lt;code&gt;exit&lt;/code&gt;: semihosting has &lt;code&gt;SYS_EXIT&lt;/code&gt;, RISC-V’s
&lt;code&gt;virt&lt;/code&gt; has a magic register, a real one has whatever pin somebody soldered. None of that belongs
inside a framework that would then only build for the target it had heard of — so &lt;code&gt;finish&lt;/code&gt; hands the
number back and the board signals it however it signals things.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reset&lt;/code&gt; deliberately leaves the sink alone. A board attaches once at startup, and a reset that undid
that would send the second pass of a looping self-test to a console the board does not have.&lt;/p&gt;
&lt;h2 id=&quot;what-it-is-not&quot;&gt;What it is not&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It does not discover tests.&lt;/strong&gt; &lt;code&gt;run&lt;/code&gt; is a call, so the suite is a list you wrote. On a host &lt;code&gt;sysl test&lt;/code&gt; collects &lt;code&gt;@test&lt;/code&gt; functions for you; here there is no runner to do the collecting, and a list
in source is the honest form.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It has no fixtures, no setup and no teardown.&lt;/strong&gt; A test body is a function; what it needs, it
calls first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It does not time anything.&lt;/strong&gt; A clock is the board’s and there is no portable one to ask.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Generics</title>
    <link href="https://sysl.sh/reference/generics/"/>
    <id>https://sysl.sh/reference/generics/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Type parameters, bidirectional inference, bounds checked at the definition, and monomorphization.</summary>
    <content type="html">&lt;p&gt;A &lt;strong&gt;type parameter list&lt;/strong&gt; in square brackets makes a function, struct, or enum generic. A parameter
name stands for a type not yet known, and may appear anywhere a type may — a parameter type, a return
type, a field type, a variant payload, a local annotation.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;]
    first: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;
    second: &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), p.first, p.second)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 hi 1 one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three further declarations take parameters without declaring a type of their own: an &lt;strong&gt;&lt;code&gt;impl&lt;/code&gt; block&lt;/strong&gt;,
whose subject is a generic type or a composed shape applied to them; a &lt;strong&gt;member&lt;/strong&gt;, which may be generic
over types of its own beyond its type’s; and a &lt;strong&gt;trait&lt;/strong&gt;, which is then a family of promises rather
than one. All three are on &lt;a href=&quot;/reference/traits/&quot;&gt;traits&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;means-type-application-in-a-type-indexing-in-an-expression&quot;&gt;&lt;code&gt;[]&lt;/code&gt; means type application in a type, indexing in an expression&lt;/h2&gt;
&lt;p&gt;Square brackets are reused for two things, disambiguated by &lt;strong&gt;position&lt;/strong&gt;, with no new token:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;in a &lt;strong&gt;type&lt;/strong&gt;, &lt;code&gt;Box[int]&lt;/code&gt; and &lt;code&gt;Result[Box[int], string]&lt;/code&gt; &lt;em&gt;apply&lt;/em&gt; type arguments to a generic type,
and nesting is ordinary;&lt;/li&gt;
&lt;li&gt;in an &lt;strong&gt;expression&lt;/strong&gt;, &lt;code&gt;a[0]&lt;/code&gt; &lt;em&gt;indexes&lt;/em&gt;, and never reads as a type application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The reuse is unambiguous because a type and an expression never occupy the same grammatical slot.
What it looks like it costs is &lt;strong&gt;explicit type arguments at a call head&lt;/strong&gt; — &lt;code&gt;id[int](7)&lt;/code&gt; reads as
“index &lt;code&gt;id&lt;/code&gt; by &lt;code&gt;int&lt;/code&gt;, then call” — but only to the parser. The compiler resolves the head first, and
a function is not a thing that can be indexed, so there is no second reading to protect:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;](&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;](&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The nearest binding wins&lt;/strong&gt;, which is the rule every call form follows. A local standing over a
function’s name makes the brackets an index again, and its author is never told about a feature they
did not reach for.&lt;/p&gt;
&lt;h2 id=&quot;writing-the-type-arguments&quot;&gt;Writing the type arguments&lt;/h2&gt;
&lt;p&gt;Five heads take the list. A &lt;strong&gt;value&lt;/strong&gt; argument is written exactly as a type one is, since the two
share a list and a position:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;what it names&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;id[int](7)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a function, qualified or not&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;chunk[8]()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value parameter — &lt;code&gt;[const N: usize]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Pair[int, real](1, 2.5)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a constructor&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;x.pick[int](3)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a method — its &lt;strong&gt;own&lt;/strong&gt; parameters, not the receiver’s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Maybe[int].Just(1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a variant, which is a construction of its type&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_arg[int](ap)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a special form: &lt;code&gt;va_arg&lt;/code&gt; and &lt;code&gt;ptr_cast&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Inference is still what supplies them nearly everywhere&lt;/strong&gt;, and a list inference would have found is
noise. What earns the syntax is a signature neither direction of inference reaches — a kernel whose
width is a value parameter it names in no argument and answers &lt;code&gt;unit&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](a: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, out: []&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i + &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt; &amp;lt;= a.len
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; l: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = b.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(i)

        out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(i, l + r)
        i += &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; add&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; ys: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;50.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;60.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;70.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;80.0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;](xs[..], ys[..], out[..])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(out[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], out[&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11 88
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written without the brackets there is nothing anywhere to say what &lt;code&gt;W&lt;/code&gt; is, and the message says so
rather than naming an annotation that cannot exist:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](a: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;, out: []&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: &amp;lt;&lt;span class=&quot;hl-type&quot;&gt;W&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = a.&lt;span class=&quot;hl-function&quot;&gt;load&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

    out.&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, v)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; add&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: [&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(xs[..], out[..])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;W&apos; is in neither the parameters of &apos;add&apos; nor its result
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Two things stay inferred.&lt;/strong&gt; A &lt;strong&gt;type pack&lt;/strong&gt; — &lt;code&gt;..A&lt;/code&gt; — stands for a list of types rather than one and
has no expression spelling, so its instantiation is always solved. And an &lt;strong&gt;associated function
selected from an applied type&lt;/strong&gt;, &lt;code&gt;Box[int].of(1)&lt;/code&gt;, reads its type’s parameters and its own from a
single solve; the annotation on the binding reaches it, and unlike the kernel above there is always
one, since an associated function has a result.&lt;/p&gt;
&lt;p&gt;There is also a &lt;strong&gt;hole shared with the address form&lt;/strong&gt;: the brackets read the &lt;em&gt;expression&lt;/em&gt; grammar, so
a type the two grammars do not spell alike has no form there. &lt;code&gt;[]int&lt;/code&gt;, &lt;code&gt;weak T&lt;/code&gt;, &lt;code&gt;volatile T&lt;/code&gt;,
&lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; and a callable are refused by the parser. The annotation reaches every one of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The address form came first&lt;/strong&gt;: &lt;code&gt;&amp;amp;f[T]&lt;/code&gt; names one instantiation of a generic function, and the case
that earned it is a C callback whose signature mentions the type parameter nowhere. See
&lt;a href=&quot;/reference/ffi/&quot;&gt;the FFI reference&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;construction&quot;&gt;Construction&lt;/h2&gt;
&lt;p&gt;Applying a generic type names a concrete instance: &lt;code&gt;Box[int]&lt;/code&gt; is the type of a box of &lt;code&gt;int&lt;/code&gt;,
&lt;code&gt;Pair[int, string]&lt;/code&gt; a pair. &lt;strong&gt;Constructing one is the ordinary construction&lt;/strong&gt;, with the type arguments
inferred from the arguments — &lt;code&gt;Box(41)&lt;/code&gt;, &lt;code&gt;Pair(1, &amp;quot;one&amp;quot;)&lt;/code&gt; — or written on the name, which means what
the annotation means: &lt;code&gt;Pair[int, real](1, 2.5)&lt;/code&gt; fixes the instantiation and checks the fields against
it. The memory mode is the usual per-declaration choice: &lt;code&gt;Box(41)&lt;/code&gt; is a value unless a &lt;code&gt;&amp;amp;Box[int]&lt;/code&gt; is
expected.&lt;/p&gt;
&lt;h2 id=&quot;inference-is-bidirectional&quot;&gt;Inference is bidirectional&lt;/h2&gt;
&lt;p&gt;Type arguments are inferred, and from two directions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;From the arguments.&lt;/strong&gt; &lt;code&gt;id(7)&lt;/code&gt; infers &lt;code&gt;T = int&lt;/code&gt;, and inference reaches &lt;em&gt;through&lt;/em&gt; a generic
construction, so every nested parameter is solved at once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;From the expected type&lt;/strong&gt;, when the arguments cannot determine a parameter. A nullary generic has
nothing in its argument list to fix &lt;code&gt;T&lt;/code&gt;, so the declaration supplies it and the return type flows
&lt;em&gt;inward&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;empty&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; e: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;empty&lt;/span&gt;()

e &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(v) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;none
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The model is &lt;strong&gt;unification&lt;/strong&gt;: each parameter is solved by matching the declared parameter and return
types against the actual argument types and the expected type. When a parameter is left undetermined by
&lt;strong&gt;both&lt;/strong&gt; directions, that is a compile error asking for an annotation on the binding — never a silent
default and never a stuck inference variable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A literal is consulted last&lt;/strong&gt;, because a literal has no type of its own to offer. It takes one from
where it appears, and a parameter still being solved is not yet a place that can give it one. So what
is already a type settles the parameter first, then the expected type, and a literal’s default only
where nothing else reached it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, c: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = a + b + c

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;250u8&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;253
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a &lt;code&gt;u8&lt;/code&gt; because one argument knew and two did not, while &lt;code&gt;id(7)&lt;/code&gt; is still an &lt;code&gt;int&lt;/code&gt; because none
did. Once the parameter is a type the literals are read against it — the same order the operand rule
uses inside an expression.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A parameter is solved to the type that was &lt;em&gt;written&lt;/em&gt;.&lt;/strong&gt; Where that is a
&lt;a href=&quot;/reference/declarations/#type-declarations&quot;&gt;transparent subtype&lt;/a&gt;, the parameter carries the subtype
rather than the base it is stored as — and it does so however the call said which type it is at:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; written = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;]()
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; expected: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(written), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(expected))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;150 150
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The routes have to agree, because from the reader’s side they are three ways of saying one thing.
Writing &lt;code&gt;Age&lt;/code&gt; at the call, handing an &lt;code&gt;Age&lt;/code&gt; as an argument, and annotating the binding &lt;code&gt;Age&lt;/code&gt; are each
a way of naming the type this call is at; an answer that depended on which one was available would be
an answer about the &lt;em&gt;call&lt;/em&gt; rather than about the type.&lt;/p&gt;
&lt;p&gt;That a transparent subtype &lt;strong&gt;is&lt;/strong&gt; its base — an &lt;code&gt;Age&lt;/code&gt; stands where an &lt;code&gt;int&lt;/code&gt; is asked for, and the
reverse — is unchanged, and holds for every value that flows. A type parameter is not a value: it is
the name a body is written about, and the body may ask it something its base would answer
differently. &lt;code&gt;T::Max&lt;/code&gt; is the only such question there is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;null&lt;/code&gt; is not consulted at all — it waits&lt;/strong&gt;, and what separates it from a literal is that it has no
default to be consulted &lt;em&gt;for&lt;/em&gt;. The argument that cannot contribute is set aside, the rest solve the
parameter, and it is then read against what they said:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = a == b

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;x, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;x))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Either order answers alike, since waiting is not queueing — and setting it aside cannot lose the
solution, because an argument with no type of its own has nothing to unify. Where nothing else
reached the parameter it is refused rather than defaulted: inference does not invent a pointee.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;null&apos; takes its type from its context, and there is none here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A parameter that names no type parameter is not part of the question&lt;/strong&gt;, and its argument is checked
against it exactly as a plain callee’s is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(n)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is worth saying because inference has to look at the arguments before it knows what anything is,
which would otherwise cost a generic callee the rules that need an expected type — a parameter’s type
fixing an unsuffixed literal, and the coercions to &lt;code&gt;&amp;amp;T&lt;/code&gt; and to a trait object. A declaration having a
&lt;code&gt;T&lt;/code&gt; somewhere does not make its &lt;code&gt;usize&lt;/code&gt; any less a &lt;code&gt;usize&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;members-and-associated-functions&quot;&gt;Members and associated functions&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A method never asks the question.&lt;/strong&gt; Its receiver already &lt;em&gt;is&lt;/em&gt; a &lt;code&gt;Box[int]&lt;/code&gt;, so the type’s arguments
are read rather than solved.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An associated function has no receiver&lt;/strong&gt;, which puts it in the position a generic free function is
always in — so it is inferred by exactly the rule above and needs no machinery of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;of&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(x)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;of&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;41
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Self&lt;/code&gt; in the signature is the type applied to its own parameters, so writing &lt;code&gt;-&amp;gt; Self&lt;/code&gt; and writing
&lt;code&gt;-&amp;gt; Box[T]&lt;/code&gt; infer alike.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A member’s own type parameters are inferred the same way.&lt;/strong&gt; The receiver says what the &lt;em&gt;type’s&lt;/em&gt;
arguments are and nothing about the member’s, which leaves those exactly where the rule already
reaches:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;]
    first: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;
    second: &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;with&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;U&lt;/span&gt;](&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;U&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;U&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.v, x)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = b.&lt;span class=&quot;hl-function&quot;&gt;with&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.first, p.second)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two lists are held to their bounds separately and under the name each was written in. That they
must not collide is the one thing the two-list form adds, and it is settled by refusing a member that
spells one of its own the way its type spells one of its.&lt;/p&gt;
&lt;h2 id=&quot;bounds&quot;&gt;Bounds&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A type parameter is bounded by a trait, and the bound is what the body of a generic is allowed to
assume about the parameter.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;an-unbounded-parameter-permits-only-what-every-type-supports&quot;&gt;An unbounded parameter permits only what every type supports&lt;/h3&gt;
&lt;p&gt;With no bound, &lt;code&gt;T&lt;/code&gt; may be used only for the operations every sysl value has — which, because of the
memory model, is a genuinely useful set: &lt;strong&gt;copied, assigned, passed, returned, and stored&lt;/strong&gt; in a struct
field, an enum payload, an array, or a slice.&lt;/p&gt;
&lt;p&gt;That set is exactly &lt;code&gt;id[T]&lt;/code&gt;, &lt;code&gt;Box[T]&lt;/code&gt;, &lt;code&gt;Pair[A, B]&lt;/code&gt;, and every other container: they move data around
without inspecting it, and they need no bound.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;keep&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(x)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;keep&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;keep&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.v, b.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 hi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every sysl value is copyable&lt;/strong&gt; — assignment copies, and copying a value holding a &lt;code&gt;&amp;amp;T&lt;/code&gt; retains it —
so there is &lt;strong&gt;no &lt;code&gt;Copy&lt;/code&gt; bound to write, ever.&lt;/strong&gt; That is a real simplification over Rust, where &lt;code&gt;T&lt;/code&gt; is
move-by-default and &lt;code&gt;T: Copy&lt;/code&gt; / &lt;code&gt;T: Clone&lt;/code&gt; litter generic signatures. Here, “hold and hand along any
&lt;code&gt;T&lt;/code&gt;“ is the free, unmarked baseline.&lt;/p&gt;
&lt;p&gt;What an unbounded &lt;code&gt;T&lt;/code&gt; may &lt;strong&gt;not&lt;/strong&gt; do is anything that assumes structure: no operator, no method call,
no field access, no index. Each is a capability some types have and others do not, so each requires a
bound that guarantees it — and each is refused &lt;strong&gt;at the definition&lt;/strong&gt;, naming the bound to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = a + b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs &apos;T: sysl.Add&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A subscript is among them, because a subscript &lt;em&gt;is&lt;/em&gt; &lt;code&gt;Index&lt;/code&gt;‘s one method, so it is asked of the bounds
exactly as a dot call is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A field is the exception that proves the rule.&lt;/strong&gt; Every other unlicensed use names the bound that
would allow it — the diagnostic’s whole job is to say what to write. A field names none, because a
trait promises &lt;em&gt;behaviour&lt;/em&gt; and a field is &lt;em&gt;layout&lt;/em&gt;, so no bound could ever supply one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = x.v

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;T&apos; is a type parameter, so it has no fields to read — a field is layout, and no trait declares a property &apos;v&apos; that a bound could promise instead
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is therefore settled outright at the definition rather than deferred to the types that turn up:
&lt;code&gt;first[T](x: T) = x.v&lt;/code&gt; is wrong even if every call happens to pass a type with a &lt;code&gt;v&lt;/code&gt;. Reaching a
value’s data through a generic means going through a member the bound declares, which is also what lets
two types satisfy one bound while storing the value differently.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x.v&lt;/code&gt; is spelled like a field and need not be one, so the diagnostic is reached only after looking for
a &lt;strong&gt;property&lt;/strong&gt; of that name: a property is behaviour, a trait may declare one, and reading it through a
bound is as ordinary as calling a method.&lt;/p&gt;
&lt;h3 id=&quot;a-bound-is-a-trait-written-t-trait&quot;&gt;A bound is a trait, written &lt;code&gt;[T: Trait]&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = a + b

&lt;span class=&quot;hl-function&quot;&gt;smaller&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; a &amp;lt; b &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;smaller&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;a + b&lt;/code&gt; inside &lt;code&gt;sum&lt;/code&gt; type-checks &lt;strong&gt;because&lt;/strong&gt; &lt;code&gt;T: Add&lt;/code&gt; promises the operator; drop the bound and &lt;code&gt;sum&lt;/code&gt;
fails &lt;em&gt;at its own definition&lt;/em&gt;, pointing at the line that made the unsupported assumption. &lt;strong&gt;That is the
whole payoff over the template model: the error lands on the definition that is wrong, not on some
caller three files away that instantiated it with the wrong type.&lt;/strong&gt; It is the Swift/Kotlin/Scala
consensus — all three check bounds at the definition, and only C++ defers to instantiation.&lt;/p&gt;
&lt;p&gt;Operators are available through bounds because &lt;a href=&quot;/reference/expressions/#operator-dispatch&quot;&gt;operators &lt;em&gt;are&lt;/em&gt; trait
methods&lt;/a&gt;: &lt;code&gt;+&lt;/code&gt; is &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt; is &lt;code&gt;Ord&lt;/code&gt;, &lt;code&gt;==&lt;/code&gt; is &lt;code&gt;Eq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multiple bounds join with &lt;code&gt;+&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;[T: Ord + Hash]&lt;/code&gt; requires both. The &lt;code&gt;+&lt;/code&gt; reads unambiguously in a
bound position, since it stands between trait names rather than values.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bound is the trait &lt;em&gt;applied&lt;/em&gt;&lt;/strong&gt;, so it carries the trait’s own type arguments where it has any:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;means&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[X: Sink[int]]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the body’s &lt;code&gt;x.put(…)&lt;/code&gt; takes an &lt;code&gt;int&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[X: Into[Y], Y]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;and &lt;code&gt;Y&lt;/code&gt; is solved at the call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[X: Into[Y], Y: Display]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a body that may also print what the conversion yields&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The arguments are ordinary types, which is what lets one name another parameter of the same
declaration — and what a body may then do with that parameter is what &lt;em&gt;its&lt;/em&gt; bounds promise. Inference
does not run backwards through a bound: a parameter appearing only there is solved from the result type
or annotated.&lt;/p&gt;
&lt;h3 id=&quot;a-trait-object-satisfies-a-bound-on-the-trait-it-dispatches-through&quot;&gt;A trait object satisfies a bound on the trait it dispatches through&lt;/h3&gt;
&lt;p&gt;A bound asks whether the members it names can be called on the value. A &lt;code&gt;*Trait&lt;/code&gt; or a &lt;code&gt;&amp;amp;Trait&lt;/code&gt; has
forgotten which type it holds, but it carries a &lt;strong&gt;table&lt;/strong&gt; of exactly those members — so it answers
yes, and one generic function takes both a concrete type and the object erased from it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(o))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12
12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nothing about &lt;a href=&quot;#monomorphization&quot;&gt;monomorphization&lt;/a&gt; is bent to allow it.&lt;/strong&gt; An object type is a
concrete type — a pair of words — so the body is instantiated at &lt;code&gt;&amp;amp;Shape&lt;/code&gt; exactly as it is at &lt;code&gt;Rect&lt;/code&gt;,
once each. What differs between the two instantiations is what &lt;code&gt;x.area()&lt;/code&gt; compiles to: a direct call
in one, an indirect call through the table in the other. That is the same difference the two
instantiations would have had anyway, and it is decided the same way — by looking at the type the
parameter was bound to.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is total, and that is a property of object safety rather than a promise made here.&lt;/strong&gt; A trait
with a member that cannot be dispatched — one mentioning &lt;code&gt;Self&lt;/code&gt; away from its receiver, say — has no
object &lt;em&gt;at all&lt;/em&gt; in sysl, rather than an object missing that member. So a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; existing is already
the proof that every member of &lt;code&gt;Shape&lt;/code&gt; is reachable through it, and there is no “this method is
unavailable on the object” case for a bound to trip over.&lt;/p&gt;
&lt;p&gt;It follows for &lt;strong&gt;required&lt;/strong&gt; traits with no rule of its own. &lt;code&gt;trait Shape: Display&lt;/code&gt; puts &lt;code&gt;Display&lt;/code&gt;‘s
slots in the object’s table, and a bound on a trait is already satisfied wherever a bound on one that
requires it is — so a &lt;code&gt;show[T: Display](x: T)&lt;/code&gt; takes the same &lt;code&gt;o&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;What an object still does not satisfy is a bound on any &lt;em&gt;other&lt;/em&gt; trait: the table is what answers, and
a trait with no slots in it has nothing to answer with.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Weighed&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;weight&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

&lt;span class=&quot;hl-function&quot;&gt;heft&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Weighed&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = x.&lt;span class=&quot;hl-function&quot;&gt;weight&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;heft&lt;/span&gt;(o))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;heft&apos; requires its type parameter &apos;T&apos; to implement &apos;Weighed&apos;, but &amp;amp;Shape does not
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Satisfying a bound is not the same as being erasable again.&lt;/strong&gt; A bound asks what may be &lt;em&gt;called&lt;/em&gt;
through a value; forming an object asks what may be &lt;em&gt;assembled&lt;/em&gt; from its type, and a table is laid
out from a type’s implementations. An object has none, so a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; cannot be turned into a
&lt;code&gt;&amp;amp;Display&lt;/code&gt; even though &lt;code&gt;Display&lt;/code&gt;‘s slots are sitting inside its table — a run of slots in one table
is not a table of its own ([traits]({{&amp;lt; ref “traits” &amp;gt;}})).&lt;/p&gt;
&lt;h3 id=&quot;a-type-s-own-parameters-carry-bounds-too&quot;&gt;A type’s own parameters carry bounds too&lt;/h3&gt;
&lt;p&gt;The same bracketed list, in the same place, means the same thing on a struct or an enum — and that is
where the type says what it assumes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;SortedPair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;]
    lo: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    hi: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;ordered&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.lo &amp;lt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.hi
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; SortedPair&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;SortedPair&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;ordered&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It buys two things, worth stating separately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everything applying the type must supply it&lt;/strong&gt;, wherever the application is written — a declared
parameter, a result, a field of another type, a variant’s payload, a construction:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;SortedPair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;]
    lo: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    hi: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; SortedPair&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;SortedPair&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;SortedPair&apos; requires its type parameter &apos;T&apos; to implement &apos;sysl.Ord&apos;, but P does not
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where the argument is itself a type parameter, the answer is what &lt;em&gt;its&lt;/em&gt; own bounds promise, so a
function taking a &lt;code&gt;SortedPair[U]&lt;/code&gt; must bound &lt;code&gt;U&lt;/code&gt; by at least what &lt;code&gt;SortedPair&lt;/code&gt; asks. A bound is
satisfied by a bound, one step out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And the type’s members may assume it, so they are checked at their definition.&lt;/strong&gt; That is what having
somewhere to write the bound is &lt;em&gt;for&lt;/em&gt;: a member of a generic type is walked once, with the parameters
standing in for themselves, by the same pass that walks a bounded generic function — so a method
calling something no bound licenses is reported on its own line whether or not anything instantiates the
type. A generic type’s fields are laid out once the same way, which is what catches a field applying
another bounded type to this one’s parameter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bound is declared once, at the type, and is in force everywhere its parameters appear&lt;/strong&gt; — a
member’s signature and body, a field’s type, a variant’s payload. It is not restated per member.
Restating it is Rust’s rule and its own users regret it; declaring once is the Swift/Kotlin behaviour
and the one that matches how the bound reads.&lt;/p&gt;
&lt;h2 id=&quot;a-parameter-may-carry-a-default&quot;&gt;A parameter may carry a default&lt;/h2&gt;
&lt;p&gt;A parameter of a &lt;strong&gt;trait&lt;/strong&gt;, a &lt;strong&gt;struct&lt;/strong&gt;, or an &lt;strong&gt;enum&lt;/strong&gt; may name the type to use where a use leaves it
out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;]
    x: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = p.x + p.y

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;bound comes first and the default last&lt;/strong&gt; — &lt;code&gt;[R: Show = Self]&lt;/code&gt; — and either may be written without
the other. Four rules govern them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Defaults are filled left to right&lt;/strong&gt;, each resolved under the arguments already fixed, so a default
may name a parameter written &lt;strong&gt;before&lt;/strong&gt; it, and naming one written after it is the forward reference
it looks like.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;They are a suffix.&lt;/strong&gt; A parameter with no default may not come after one that has, because arguments
are written in order and nothing could leave out the earlier one and still supply the later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The filling happens before anything is keyed on the arguments&lt;/strong&gt;, so &lt;code&gt;Pair[int]&lt;/code&gt; and &lt;code&gt;Pair[int, int]&lt;/code&gt;
are one instantiation rather than two that happen to have the same fields.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A default is exposed like a field.&lt;/strong&gt; A public declaration may not default to a type that reaches
less far than it does, or a caller who leaves the argument out ends up holding something they could
not have written and cannot name. And a default may not lead back to the declaration it belongs to,
directly or through another’s.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Self&lt;/code&gt; is the case the feature exists for.&lt;/strong&gt; In a trait’s default it means the implementing type,
exactly as in a method’s signature — so &lt;code&gt;impl Scale for P&lt;/code&gt; is the &lt;code&gt;impl Scale[P] for P&lt;/code&gt; it reads as,
and &lt;code&gt;[T: Scale]&lt;/code&gt; asks for &lt;code&gt;Scale[T]&lt;/code&gt;. A struct and an enum have no implementing type, so &lt;code&gt;Self&lt;/code&gt; in one
of their defaults is refused. Neither has a &lt;strong&gt;trait object&lt;/strong&gt;: an object has forgotten which type it
holds, so a default of &lt;code&gt;Self&lt;/code&gt; has nothing to name and the argument is written out.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only those three declarations may carry one.&lt;/strong&gt; A function’s, a method’s, and an &lt;code&gt;impl&lt;/code&gt; block’s type
parameters are &lt;em&gt;solved&lt;/em&gt; from what they are given rather than written where they are used, so there is
no argument list with a gap for a default to fill:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;T&apos; is a type parameter of the function &apos;f&apos;, whose type parameters are solved from what it is given rather than written where it is used — so &apos;= int&apos; has nothing to stand in for
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What would be useful there is a fallback for an inference that found nothing, which is a different
feature; &lt;code&gt;f[T = int](x: T)&lt;/code&gt; is refused rather than quietly meaning that.&lt;/p&gt;
&lt;h2 id=&quot;converting-through-a-parameter&quot;&gt;Converting through a parameter&lt;/h2&gt;
&lt;p&gt;A conversion is the one capability with no bound to promise it, because a conversion is between the
concrete scalar kinds rather than something a trait declares. &lt;strong&gt;Both directions are written, and both
are checked at each instantiation&lt;/strong&gt; rather than at the definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;low&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;(b)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;low&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;321&lt;/span&gt;), n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;65 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;T(b)&lt;/code&gt; is a conversion written where the parameter’s name stands, resolved at each instantiation, so
the two directions of one conversion are one rule. An instantiation at a &lt;strong&gt;constrained subtype&lt;/strong&gt; or a
&lt;strong&gt;simple enum&lt;/strong&gt; takes that type’s own checked cast, since the scalar conversion has no meaning for
either and the form written under the type’s name does — so &lt;code&gt;T(x)&lt;/code&gt; at an &lt;code&gt;Age&lt;/code&gt; is the &lt;code&gt;Age(x)&lt;/code&gt; a
reader would have written, trap included.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Construction is deliberately not among the forms it reaches.&lt;/strong&gt; A struct’s positional constructor
takes a field list rather than a value, and a generic body filling in an unknown struct’s fields by
position is not something to arrive at by accident:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; P&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;(b)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;cannot convert byte to P
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;T(b)&lt;/code&gt; stays a &lt;strong&gt;conversion&lt;/strong&gt; at every instantiation, so at a struct it is refused exactly as &lt;code&gt;u8(x)&lt;/code&gt;
at one is — naming the struct, and not quietly becoming a constructor. What a container that wants to
build a &lt;code&gt;T&lt;/code&gt; reaches for is a bound that says so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The parameter wins over a declaration of the same name&lt;/strong&gt;, which closes an inconsistency rather than
opening one: &lt;code&gt;var y: T&lt;/code&gt; inside a &lt;code&gt;[T]&lt;/code&gt; body has always meant the parameter, so &lt;code&gt;T(x)&lt;/code&gt; one line later
means it too.&lt;/p&gt;
&lt;h2 id=&quot;monomorphization&quot;&gt;Monomorphization&lt;/h2&gt;
&lt;p&gt;Each distinct set of type arguments produces its &lt;strong&gt;own&lt;/strong&gt; specialized function or aggregate. &lt;code&gt;id&lt;/code&gt;
called at &lt;code&gt;int&lt;/code&gt; and at &lt;code&gt;real&lt;/code&gt; emits two functions; a &lt;code&gt;Box[int]&lt;/code&gt; and a &lt;code&gt;Box[string]&lt;/code&gt; are two distinct
layouts. The IR carries exactly one definition per instantiation, not one per call.&lt;/p&gt;
&lt;p&gt;That is why bounds can be checked once at the definition yet lower to direct, monomorphic code with no
dictionary passed at runtime.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The cost is code size&lt;/strong&gt;, the standard monomorphization tradeoff — C++ templates and Rust generics
make the same one. It is the right default for a systems language, where the direct, inlinable call
matters and &lt;a href=&quot;/reference/traits/#the-two-dispatch-strategies&quot;&gt;the dynamic path&lt;/a&gt; is available when one
copy is preferable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recursion is fine.&lt;/strong&gt; A recursive generic function recurses at a &lt;em&gt;fixed&lt;/em&gt; instantiation, so it
monomorphizes like any other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;variance-does-not-arise&quot;&gt;Variance does not arise&lt;/h2&gt;
&lt;p&gt;There is no variance question in sysl, by construction. Variance is about when &lt;code&gt;G[A]&lt;/code&gt; may stand in for
&lt;code&gt;G[B]&lt;/code&gt;, and that needs a subtyping relation to be interesting — which sysl does not have among concrete
types. There is no inheritance, and a trait bound is a constraint rather than a supertype relation
between values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Animal&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;noise&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Cat&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Animal&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;noise&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;meow&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Box&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;hear&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Animal&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = b.v.&lt;span class=&quot;hl-function&quot;&gt;noise&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Cat&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hear&lt;/span&gt;(c))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;b&apos; of &apos;hear&apos; is Box[&amp;amp;Animal], but Box[Cat] was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Box[Cat]&lt;/code&gt; and &lt;code&gt;Box[&amp;amp;Animal]&lt;/code&gt; are simply unrelated types. That deletes an entire category of design
difficulty that afflicts languages with nominal subtyping, and it should stay deleted: polymorphism
over a set of types is expressed by a bound or a trait object, never by a covariant container.&lt;/p&gt;
&lt;h2 id=&quot;a-parameter-may-stand-for-a-value&quot;&gt;A parameter may stand for a value&lt;/h2&gt;
&lt;p&gt;A type parameter stands for a &lt;strong&gt;type&lt;/strong&gt;. A parameter written &lt;code&gt;const&lt;/code&gt; stands for a &lt;strong&gt;value&lt;/strong&gt; — which is
what lets one declaration cover every array length:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](xs: [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t = t + xs[i]
    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: [&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(a))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(b))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
150
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;N&lt;/code&gt; is inferred from the argument exactly as a type parameter is: matching &lt;code&gt;[3]int&lt;/code&gt; against &lt;code&gt;[N]int&lt;/code&gt;
binds &lt;code&gt;N&lt;/code&gt; to 3, the way matching &lt;code&gt;Box[int]&lt;/code&gt; against &lt;code&gt;Box[T]&lt;/code&gt; binds &lt;code&gt;T&lt;/code&gt;. Inside the body &lt;code&gt;N&lt;/code&gt; is an
ordinary &lt;code&gt;usize&lt;/code&gt; — it can be looped to, computed with, and passed on.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;total&lt;/code&gt; at &lt;code&gt;N = 3&lt;/code&gt; and at &lt;code&gt;N = 5&lt;/code&gt; are two functions, the same way &lt;code&gt;id&lt;/code&gt; at &lt;code&gt;int&lt;/code&gt; and at &lt;code&gt;real&lt;/code&gt; are
two: the value joins the type arguments the instantiation is keyed on, so the length is a constant
inside each copy.&lt;/p&gt;
&lt;h3 id=&quot;it-is-the-same-const-as-everywhere-else&quot;&gt;It is the same &lt;code&gt;const&lt;/code&gt; as everywhere else&lt;/h3&gt;
&lt;p&gt;A constant is declared &lt;code&gt;const NAME: Type = expr&lt;/code&gt;. A value parameter is that declaration with the
initializer left for the caller, so &lt;code&gt;[const N: usize]&lt;/code&gt; is existing grammar in a new position rather
than a new idea.&lt;/p&gt;
&lt;p&gt;The marker is not decoration. &lt;code&gt;[N: usize]&lt;/code&gt; on its own is indistinguishable from a bounded type
parameter — &lt;code&gt;[T: Ord]&lt;/code&gt; has the same shape — and only name resolution could tell them apart, by asking
whether the thing after the colon is a trait or a type. A trait name misspelled into a type name
would then silently change what kind of parameter it is.&lt;/p&gt;
&lt;h3 id=&quot;which-values&quot;&gt;Which values&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Integers, &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, and a simple enum’s variants.&lt;/strong&gt; A value parameter puts a value into a
type’s &lt;em&gt;identity&lt;/em&gt;, so the compiler has to decide when two of them are the same value and has to write
one into a mangled name — and each of these compares and mangles.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;type&lt;/strong&gt; declares its value parameters the same way, and its arguments are written out rather than
inferred, because a type has no call to infer them from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    data: [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Flag&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; buf: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; on: &lt;span class=&quot;hl-type&quot;&gt;Flag&lt;/span&gt;[&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Flag&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(buf.data.len, on.v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Buf[2]&lt;/code&gt; and &lt;code&gt;Buf[4]&lt;/code&gt; are two types with two layouts, and neither stands where the other is wanted.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;member&lt;/strong&gt; reads the parameter as an ordinary value of its declared type, and the two lengths are
two bodies rather than one compiled at whichever came first:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    used: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;room&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt; - &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.used
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Buf&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;room&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;room&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Floats are excluded: &lt;code&gt;NaN != NaN&lt;/code&gt; under the ordinary comparison, which would make a type unequal to
itself. Strings are excluded until two spellings of one text are one value.&lt;/p&gt;
&lt;h3 id=&quot;what-may-be-written-with-n&quot;&gt;What may be written with &lt;code&gt;N&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;N&lt;/code&gt; may stand as an array’s length, and a body may compute with it freely. What neither may do is
carry the result of a computation into a &lt;strong&gt;type&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](xs: [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = xs

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this length does arithmetic on &apos;N&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Deciding that &lt;code&gt;N + 1&lt;/code&gt; and &lt;code&gt;1 + N&lt;/code&gt; are one type — and that &lt;code&gt;2 * N&lt;/code&gt; and &lt;code&gt;N + N&lt;/code&gt; are — is type-level
arithmetic, which is a feature of its own.&lt;/p&gt;
&lt;p&gt;Writing a &lt;strong&gt;type&lt;/strong&gt; parameter where a length belongs is refused for the mirror reason, since a length
is a value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](xs: [&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;T&apos; is a type parameter, and an array&apos;s length is a value rather than a type
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-it-is-for-a-fixed-array-renders&quot;&gt;What it is for: a fixed array renders&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;impl[const N: usize, T: Display] Display for [N]T&lt;/code&gt; is one block covering every array there is, which
is why &lt;code&gt;print&lt;/code&gt; takes one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[1, 2, 3]
[x, y]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Before this, a length was part of a type’s &lt;em&gt;shape&lt;/em&gt;: &lt;code&gt;[2]T&lt;/code&gt; and &lt;code&gt;[3]T&lt;/code&gt; were two shapes with no way to
be generic over the difference, so no library could implement a trait for arrays in general.&lt;/p&gt;
&lt;p&gt;An array still has two shapes an &lt;code&gt;impl&lt;/code&gt; may match — the length written out, and the length as a
parameter — and the written-out one is more specific, so it is found first. A block for &lt;code&gt;[2]T&lt;/code&gt; still
wins over a block for &lt;code&gt;[N]T&lt;/code&gt; on arrays of two, which is the same “written-out beats a parameter”
ordering &lt;code&gt;override&lt;/code&gt; uses.&lt;/p&gt;
&lt;h3 id=&quot;a-member-declares-its-own&quot;&gt;A member declares its own&lt;/h3&gt;
&lt;p&gt;A method’s parameter list is its own, exactly as a function’s is — so it may take a value parameter
that the &lt;em&gt;type’s&lt;/em&gt; parameters know nothing about. The type’s are fixed by the receiver; the member’s
are solved at the call:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Sum&lt;/span&gt;
    seen: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, xs: [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.seen = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.seen + &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Sum&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;Sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.seen)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
2
5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both calls reach one written method and neither passes a length, because &lt;code&gt;N&lt;/code&gt; is read off the argument
the same way it is for a free function.&lt;/p&gt;
&lt;h2 id=&quot;a-parameter-may-stand-for-a-list-of-types&quot;&gt;A parameter may stand for a list of types&lt;/h2&gt;
&lt;p&gt;A type parameter stands for one type and a &lt;code&gt;const&lt;/code&gt; parameter for one value. A parameter written &lt;code&gt;..&lt;/code&gt;
stands for a &lt;strong&gt;list of types&lt;/strong&gt; — a &lt;em&gt;pack&lt;/em&gt; — which is what lets one declaration cover every tuple:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;joined&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](t: (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;)) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;.len
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; i &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; s = s + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

        s = s + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(t.i)

    s

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;joined&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;joined&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.5&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1-2
1-two-true-4.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things are new there and each does one job.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;..A&lt;/code&gt; declares the pack&lt;/strong&gt;, and &lt;code&gt;(..A)&lt;/code&gt; is the tuple of it — the only &lt;em&gt;spelling&lt;/em&gt; a pack has, wherever
it is declared.
It matches a tuple of any arity, and the arity is inferred from the argument exactly as an array’s
length is: a &lt;code&gt;(int, string, bool)&lt;/code&gt; matched against &lt;code&gt;(..A)&lt;/code&gt; binds &lt;code&gt;A&lt;/code&gt; to those three.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The bound distributes over the members.&lt;/strong&gt; &lt;code&gt;[..A: Display]&lt;/code&gt; says every type in &lt;code&gt;A&lt;/code&gt; implements
&lt;code&gt;Display&lt;/code&gt;, and that is the whole of the bound syntax a pack needs — the ordinary &lt;code&gt;[T: Display]&lt;/code&gt; read
over a list. It is what makes the membership answerable before any body is compiled, so a tuple
holding something unprintable is refused where it is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;joined&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](t: (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;)) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(t.&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;joined&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;Display
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for const&lt;/code&gt; is unrolled.&lt;/strong&gt; Its range must be known when the program is compiled — &lt;code&gt;A.len&lt;/code&gt; is how
many types the pack stands for — and the body is repeated once per value, with &lt;code&gt;i&lt;/code&gt; folded in as a
compile-time &lt;code&gt;usize&lt;/code&gt;. Each copy is type-checked &lt;strong&gt;on its own&lt;/strong&gt;, which is the point: the parts of a
tuple have different types, so &lt;code&gt;t.i&lt;/code&gt; is a different selection in each copy and one written line
covers all of them.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;t.i&lt;/code&gt; at a compile-time &lt;code&gt;i&lt;/code&gt; is the selection &lt;code&gt;t.0&lt;/code&gt; already is, with the position arriving as a
constant rather than as a literal. It reaches the parts of a tuple and nothing else — a struct’s
fields have names, and a number does not address one.&lt;/p&gt;
&lt;h3 id=&quot;what-a-for-const-will-not-do&quot;&gt;What a &lt;code&gt;for const&lt;/code&gt; will not do&lt;/h3&gt;
&lt;p&gt;A range computed at run time cannot be unrolled, and the ordinary &lt;code&gt;for&lt;/code&gt; is what walks one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;must be known at compile time
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; are refused as well. There is no loop at run time for either to act on: the
copies are straight-line code inside whatever the &lt;code&gt;for const&lt;/code&gt; was written in, so a &lt;code&gt;break&lt;/code&gt; would
leave &lt;em&gt;that&lt;/em&gt; loop — one copy at a time, and silently. A loop written inside the body is an ordinary
loop and breaks out of itself as usual.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;return&lt;/code&gt; does work, and it is what &lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; on a tuple are written with — an unrolled copy is
straight-line code in the enclosing function, so a &lt;code&gt;return&lt;/code&gt; in one is an ordinary return.&lt;/p&gt;
&lt;h3 id=&quot;what-it-is-for-the-catalog-covers-every-tuple&quot;&gt;What it is for: the catalog covers every tuple&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;impl[..A: Display] Display for (..A)&lt;/code&gt; is one block covering every tuple there is, and &lt;code&gt;Eq&lt;/code&gt;, &lt;code&gt;Ord&lt;/code&gt;
and &lt;code&gt;Hash&lt;/code&gt; are each one more. Before this, a tuple’s arity was part of its &lt;em&gt;shape&lt;/em&gt;: a pair and a
triple were two shapes with no way to be generic over the difference, so the library wrote a row per
arity and stopped at three — and a tuple of four parts implemented nothing.&lt;/p&gt;
&lt;p&gt;A tuple now has three shapes an &lt;code&gt;impl&lt;/code&gt; may match, and they are found most specific first: the tuple
written out in full, then one arity, then every arity.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Tag&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pair&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Tag&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two ints&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;two ints pair any
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the same “written-out beats a parameter” ordering an array’s two shapes have, one rung
longer — and the &lt;code&gt;override&lt;/code&gt; is the separate rule it has always been. Coherence says where a block
may be written; &lt;code&gt;override&lt;/code&gt; says which of two blocks that both have a home answers. A block for a
tuple &lt;strong&gt;written out in full&lt;/strong&gt; is the specific one, so it is the one that says so.&lt;/p&gt;
&lt;h3 id=&quot;a-member-declares-one-too-unless-a-trait-requires-it&quot;&gt;A member declares one too, unless a trait requires it&lt;/h3&gt;
&lt;p&gt;A pack stands in a method’s own parameter list on the same terms a value parameter does, and for the
same reason — the list belongs to the member:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Row&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, t: (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;))
        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;.len
            &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(t.i).len
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Row&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;Row&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

r.&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;trait’s&lt;/strong&gt; member is refused, and not for a reason about packs. No member a trait requires may
declare parameters of its own of any kind: a table slot cannot hold a function that does not exist
until a call names its types. A pack is one more way of writing that list, so it meets the rule
already there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Take&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, t: (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;)) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;declares type parameters of its own, which a trait&apos;s member may not
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;struct&lt;/code&gt;, an &lt;code&gt;enum&lt;/code&gt; and a &lt;code&gt;trait&lt;/code&gt; are refused a pack for a different reason — their parameters
&lt;strong&gt;are&lt;/strong&gt; their shape, and there is nothing to spread a list over. A member has no shape of its own, so
that reason never reached one.&lt;/p&gt;
&lt;h3 id=&quot;this-is-not-variadic-functions&quot;&gt;This is not variadic functions&lt;/h3&gt;
&lt;p&gt;A pack is a compile-time list of &lt;em&gt;types&lt;/em&gt;. C’s ellipsis is a run-time walk over untyped storage
(&lt;a href=&quot;/reference/ffi/&quot;&gt;ffi&lt;/a&gt;), and the two share nothing. There is also no pack &lt;strong&gt;expansion&lt;/strong&gt;: a pack
cannot be spread into a call’s arguments, and &lt;code&gt;(..A, int)&lt;/code&gt; cannot append to one. The unrolled loop
stands in for expansion, in the one direction the catalog needs.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-not-here&quot;&gt;What is deliberately not here&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;absent&lt;/th&gt;&lt;th&gt;why, and what to write instead&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;explicit type arguments &lt;strong&gt;at a call&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;id[int](7)&lt;/code&gt; collides with indexing; annotate what receives the result. At an &lt;strong&gt;address&lt;/strong&gt; they are written — &lt;code&gt;&amp;amp;f[T]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;where&lt;/code&gt; clauses&lt;/td&gt;&lt;td&gt;the inline &lt;code&gt;[T: A + B]&lt;/code&gt; list is the settled baseline; an out-of-line form is a possible ergonomic addition&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;type-level arithmetic (&lt;code&gt;[N + 1]T&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;a value parameter may stand as a length but not be computed with in a type; deciding that &lt;code&gt;N + 1&lt;/code&gt; and &lt;code&gt;1 + N&lt;/code&gt; are one type is a feature of its own&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;pack expansion (&lt;code&gt;f(..a)&lt;/code&gt;, &lt;code&gt;(..A, int)&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;a pack may be matched and walked, not spread into an argument list or appended to; &lt;code&gt;for const&lt;/code&gt; is what stands in for it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;higher-kinded parameters (&lt;code&gt;F[_]&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;excluded&lt;/strong&gt;, not deferred — it pushes inference toward undecidable, and abstraction over containers is served by traits and bounds&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first of those has one position where the annotation costs more than a word. A &lt;strong&gt;nullary&lt;/strong&gt; generic
has no argument to be inferred from, so &lt;code&gt;buf()&lt;/code&gt; and &lt;code&gt;map()&lt;/code&gt; are solved by what receives the result and
nothing else — and &lt;code&gt;buf[u8]()&lt;/code&gt; is the first thing a reader tries. That form is refused &lt;strong&gt;by name&lt;/strong&gt;,
naming the annotation that stands in for it, rather than by a general complaint about a callee that is
not a name.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Functions</title>
    <link href="https://sysl.sh/tour/functions/"/>
    <id>https://sysl.sh/tour/functions/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>An expression after `=`, or an indented block. Defaults, names at the call, and closures.</summary>
    <content type="html">&lt;h2 id=&quot;two-bodies&quot;&gt;Two bodies&lt;/h2&gt;
&lt;p&gt;A function is a name, a parameter list, a return type, and a body. When the body is one expression
it goes after &lt;code&gt;=&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a + b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;3 + 4 =&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 + 4 = 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When it is more than that, indent it under the header and drop the &lt;code&gt;=&lt;/code&gt;. The trailing expression is
what the function yields — there is no &lt;code&gt;return&lt;/code&gt; to write, though &lt;code&gt;return&lt;/code&gt; exists for leaving early:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; doubled = n * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; doubled &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;big&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;60&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;big small
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An optional &lt;code&gt;end&lt;/code&gt; marker closes a declaration and names it. It is worth writing on anything long
enough that the closing indentation is off the screen:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;factorial&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; acc = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; acc *= i

    acc
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; factorial&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;factorial&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3628800
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A function that returns nothing simply says nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(what: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;***&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, what, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;***&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;announce&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no return type&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;*** no return type ***
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;defaults-and-names-at-the-call-site&quot;&gt;Defaults, and names at the call site&lt;/h2&gt;
&lt;p&gt;A parameter may carry a default, and defaults fill from the right — so what a call writes decides
how many are taken:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(text: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, open: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, close: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = open + text + close

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;half&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;tag&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[all] &amp;lt;half] {none}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default is an expression evaluated at each call, not one value computed once and shared. That
matters as soon as a default allocates: every call gets its own.&lt;/p&gt;
&lt;p&gt;An argument may also be given by name, which is what rescues a call site that would otherwise be a
row of anonymous literals:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;window&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, width: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;80&lt;/span&gt;, height: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;24&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(width) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(height) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; at &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(x) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(y)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;window&lt;/span&gt;(width = &lt;span class=&quot;hl-number&quot;&gt;132&lt;/span&gt;, y = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;132x24 at 0,10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A positional argument may not follow a named one — once a call starts naming, it names.&lt;/p&gt;
&lt;h2 id=&quot;one-name-several-functions&quot;&gt;One name, several functions&lt;/h2&gt;
&lt;p&gt;A name may be declared more than once. Which declaration a call means is decided by the arguments it
passes — how many, and what type each is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;int $x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;str $x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;int 1
str a
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Never by what they return, though: two declarations differing only in the result have no call that
tells them apart, and the second is refused where it is written. The
&lt;a href=&quot;/reference/declarations/#overloading&quot;&gt;reference&lt;/a&gt; has the rest, including what happens when a call
fits two of them.&lt;/p&gt;
&lt;h2 id=&quot;closures&quot;&gt;Closures&lt;/h2&gt;
&lt;p&gt;A function that takes a function writes the parameter’s type with an arrow. One parameter needs no
parentheses; two or more, or none, take them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)
&lt;span class=&quot;hl-function&quot;&gt;combine&lt;/span&gt;(f: (&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(a, b)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(x -&amp;gt; x + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;combine&lt;/span&gt;((a, b) -&amp;gt; a * b, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A closure body sees the names around it, which is what makes it worth having rather than passing a
plain function pointer. Naming one captures it, and there is no capture list to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; factor = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(x -&amp;gt; x * factor, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;50
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-capture-does-exactly&quot;&gt;What capture does, exactly&lt;/h2&gt;
&lt;p&gt;This is the one place closures will surprise you if you arrive from Kotlin, Swift or JavaScript, so
it is worth meeting now rather than in a debugger. &lt;strong&gt;Capturing a value copies it in.&lt;/strong&gt; The closure
gets its own, and writing to it does not touch the original:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;each3&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(i)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;each3&lt;/span&gt;(i -&amp;gt; total += i * i)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the outer total is still&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the outer total is still 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing went wrong there. &lt;code&gt;total&lt;/code&gt; is an &lt;code&gt;int&lt;/code&gt; — a value — and capturing a value copies it, so the
closure incremented a copy that went away when it did. This is not a special rule for closures; it
is the same copy discipline a by-value parameter or a struct field follows, applied at the moment
the closure is formed.&lt;/p&gt;
&lt;p&gt;To accumulate, capture something that &lt;em&gt;is&lt;/em&gt; shared. A &lt;code&gt;&amp;amp;T&lt;/code&gt; is a counted reference, so capturing one
retains it rather than copying what it points at, and everybody sees the same object:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-function&quot;&gt;each3&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(i)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; seen: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;each3&lt;/span&gt;(i -&amp;gt; seen.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(i * i))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;collected:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, seen.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;collected: 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which of the two you get is decided by the captured variable’s &lt;em&gt;type&lt;/em&gt;, not by anything written at
the capture site — so it is the same question the &lt;a href=&quot;/tour/memory/&quot;&gt;memory chapter&lt;/a&gt; is about, and
knowing that chapter is knowing this rule.&lt;/p&gt;
&lt;p&gt;The compiler also works out how long a closure needs to live. One that does not outlive its frame
is inlined and costs nothing; one that escapes — stored in a field, returned — is heap-boxed and
counted. You do not choose between them, and you cannot get it wrong.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/structs/&quot;&gt;structs and methods&lt;/a&gt; — giving a type some data, and then some behaviour.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The fs module</title>
    <link href="https://sysl.sh/library/fs/"/>
    <id>https://sysl.sh/library/fs/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.fs` — files and paths, in three tiers; `IoError` and why it is an enum; and `requires os`, the capability that decides whether the module exists at all.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.fs&lt;/code&gt; is the first module in this section that a target may simply &lt;strong&gt;not have&lt;/strong&gt;. Its files open
with two lines rather than one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;sysl&lt;/span&gt;.fs
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;requires&lt;/span&gt;(os)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing here is language, and nothing here can be given a body on a target with no filesystem under
it: a freestanding image has no &lt;code&gt;fopen&lt;/code&gt; to call and no &lt;code&gt;errno&lt;/code&gt; to read. So the clause is not a
warning — it is a fact about which module exists, and it is checked at the &lt;strong&gt;import&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_os&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.exists

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this reaches &apos;sysl.fs&apos;, which requires &apos;os&apos;, and this module declared &apos;no os&apos; — an environment capability gates which modules exist, so a module that gave one up may not reach one that needs it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the difference between &lt;code&gt;os&lt;/code&gt; and &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;alloc&lt;/code&gt;&lt;/a&gt; worth holding on to. &lt;code&gt;alloc&lt;/code&gt; is
checked on what a module &lt;em&gt;calls&lt;/em&gt;, because the standard library has allocating and non-allocating
halves running through the middle of it. &lt;code&gt;os&lt;/code&gt; is checked on the &lt;strong&gt;module boundary&lt;/strong&gt;, because it
decides which modules exist at all — there is no half of &lt;code&gt;sysl.fs&lt;/code&gt; that works without one.&lt;/p&gt;
&lt;h2 id=&quot;three-tiers-and-the-line-between-them-is-the-allocator&quot;&gt;Three tiers, and the line between them is the allocator&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;tier&lt;/th&gt;&lt;th&gt;names&lt;/th&gt;&lt;th&gt;what it costs&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;whole file&lt;/td&gt;&lt;td&gt;&lt;code&gt;read_text&lt;/code&gt;, &lt;code&gt;read_bytes&lt;/code&gt;, &lt;code&gt;write_text&lt;/code&gt;, &lt;code&gt;write_bytes&lt;/code&gt;, &lt;code&gt;append_text&lt;/code&gt;, &lt;code&gt;append_bytes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;storage the size of the file — allocates by nature&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;open file&lt;/td&gt;&lt;td&gt;&lt;code&gt;open&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;append&lt;/code&gt;, &lt;code&gt;open_update&lt;/code&gt;, &lt;code&gt;create_update&lt;/code&gt;, and &lt;code&gt;File&lt;/code&gt;‘s members&lt;/td&gt;&lt;td&gt;a buffer the caller already has&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;path&lt;/td&gt;&lt;td&gt;&lt;code&gt;exists&lt;/code&gt;, &lt;code&gt;readable&lt;/code&gt;, &lt;code&gt;writable&lt;/code&gt;, &lt;code&gt;is_file&lt;/code&gt;, &lt;code&gt;is_dir&lt;/code&gt;, &lt;code&gt;size_of&lt;/code&gt;, &lt;code&gt;make_dir&lt;/code&gt;, &lt;code&gt;remove_file&lt;/code&gt;, &lt;code&gt;remove_dir&lt;/code&gt;, &lt;code&gt;rename&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one C call each&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Reading a whole file &lt;em&gt;is&lt;/em&gt; asking for storage the size of the file&lt;/strong&gt;, so the top tier could not have
been written any other way. Keeping it apart from &lt;code&gt;File&lt;/code&gt; is what lets the middle tier stay honest:
opening and reading in chunks needs only a buffer the caller brought, and works in a module that must
not allocate.&lt;/p&gt;
&lt;h2 id=&quot;the-whole-file-tier&quot;&gt;The whole-file tier&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{write_text, read_text, append_text, read_bytes, remove_file, exists}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; path = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-1.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(path, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;read_text&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().len)

&lt;span class=&quot;hl-function&quot;&gt;append_text&lt;/span&gt;(path, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;again&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;read_bytes&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;().len)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;read_text&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(path))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
12
hello
again
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of these &lt;strong&gt;opens, does the one thing, and closes&lt;/strong&gt; — and closes through &lt;code&gt;defer&lt;/code&gt;, so the handle is
released down the failing paths too. That is the idiom the module is written to demonstrate: a
scope releases what the scope said it would. A &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; is the other way to
say it and wants the handle behind a &lt;code&gt;&amp;amp;T&lt;/code&gt;; these functions never let one escape, so the scope is
enough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;read_bytes&lt;/code&gt; reads in chunks and grows rather than sizing itself from the file’s length first.&lt;/strong&gt;
That costs a little copying and buys the case that matters — a file being written while this reads it,
and anything whose length is not a fact until the read ends. The loop stops on the first empty read,
and asks &lt;em&gt;afterwards&lt;/em&gt; whether the reading ended badly, which is the split
&lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;Reader&lt;/code&gt;&lt;/a&gt; was built around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bytes that are not UTF-8 stop the program&lt;/strong&gt; rather than becoming an error case. That is deliberate:
answering with an error instead would put a case in &lt;code&gt;IoError&lt;/code&gt; that no filesystem ever reports, and
would make every program reading its own configuration handle a failure that means its build is
broken. The severity is affordable because the layer underneath is public — a caller who would rather
inspect than trap reads &lt;code&gt;read_bytes&lt;/code&gt; and validates it with
&lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;from_utf8&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ioerror&quot;&gt;&lt;code&gt;IoError&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;NotFound&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;PermissionDenied&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;AlreadyExists&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;NotADirectory&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;IsADirectory&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;DirectoryNotEmpty&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;TooManyOpenFiles&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;NoSpaceLeft&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Interrupted&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;NotOpen&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Other&lt;/span&gt;(code: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every &lt;code&gt;Result&lt;/code&gt; this module hands back carries one. &lt;strong&gt;It is an enum rather than a bare &lt;code&gt;int&lt;/code&gt; for the
reason &lt;code&gt;Result&lt;/code&gt; carries its error as a type parameter at all&lt;/strong&gt;: a caller that wants to act on &lt;em&gt;why&lt;/em&gt;
wants to match, and a match over named cases is exhaustive where a comparison against a number is a
guess that compiled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The cases are the ones a program branches on, and everything else arrives as &lt;code&gt;Other&lt;/code&gt; carrying the
number.&lt;/strong&gt; A library that mapped every &lt;code&gt;errno&lt;/code&gt; to a name of its own would be a table nobody could keep
current and a program could not extend — and the number is what a reader looks up anyway.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;code()&lt;/code&gt; answers for every case, not only &lt;code&gt;Other&lt;/code&gt;: the named ones hand back the code they were
recognised from, which keeps the question answerable without a second table. &lt;code&gt;message()&lt;/code&gt; is a sentence
in the terms the operation was asked in rather than in C’s, and the &lt;code&gt;Display&lt;/code&gt; impl is what makes
&lt;code&gt;print(e)&lt;/code&gt; say it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.read_text

&lt;span class=&quot;hl-function&quot;&gt;read_text&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-missing.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(s) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s.len)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e, e.&lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;refused: no such file or directory 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;errno&lt;/code&gt; is read at the failure, not wherever the caller got round to asking.&lt;/strong&gt; Every call in the
module reports with a private &lt;code&gt;why()&lt;/code&gt; that reads it on the spot, because there is nothing between the
two that could overwrite it — and &lt;code&gt;fclose&lt;/code&gt; is a call like any other, which sets &lt;code&gt;errno&lt;/code&gt; to whatever
&lt;em&gt;it&lt;/em&gt; thought.&lt;/p&gt;
&lt;h2 id=&quot;file&quot;&gt;&lt;code&gt;File&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;closed&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;flush&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;seek&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, to: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;at_end&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(path: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]          &lt;span class=&quot;hl-comment&quot;&gt;// an existing file, for reading&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;create&lt;/span&gt;(path: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]        &lt;span class=&quot;hl-comment&quot;&gt;// makes one, or empties one that was there&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;append&lt;/span&gt;(path: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]        &lt;span class=&quot;hl-comment&quot;&gt;// writes at the end&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;open_update&lt;/span&gt;(path: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]   &lt;span class=&quot;hl-comment&quot;&gt;// read and write; fails if it is not there&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;create_update&lt;/span&gt;(path: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;File&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;] &lt;span class=&quot;hl-comment&quot;&gt;// read and write; empties what was there&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;File&lt;/code&gt; is C’s buffered &lt;code&gt;FILE *&lt;/code&gt;, not a file descriptor, and that is the load-bearing choice.&lt;/strong&gt; A
descriptor would mean &lt;code&gt;open(2)&lt;/code&gt;, and &lt;code&gt;open(2)&lt;/code&gt; means &lt;code&gt;O_CREAT&lt;/code&gt;, &lt;code&gt;O_TRUNC&lt;/code&gt; and &lt;code&gt;O_APPEND&lt;/code&gt; — three
constants whose values differ between platforms and which nothing in the program could check.
&lt;code&gt;fopen&lt;/code&gt; takes a &lt;strong&gt;mode string&lt;/strong&gt;, which C standardises, so the same three intentions cross the boundary
as text that is right everywhere. The five functions above are named for what they &lt;em&gt;mean&lt;/em&gt; rather than
for the mode string each becomes.&lt;/p&gt;
&lt;p&gt;The buffering comes with it, and is the second reason: a &lt;code&gt;Writer&lt;/code&gt; that reached the operating system
once per &lt;code&gt;write&lt;/code&gt; would make rendering into a file cost a system call per fragment, and
&lt;a href=&quot;/library/core/&quot;&gt;the rendering surface&lt;/a&gt; writes in fragments.&lt;/p&gt;
&lt;p&gt;What is given up is the descriptor itself. A program that needs one — to poll it, to hand it to a
child — should say &lt;code&gt;open(2)&lt;/code&gt; for itself, which is what &lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;sysl.io&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;FdReader&lt;/code&gt; is
already shaped for. The two live side by side on purpose: &lt;code&gt;Reader&lt;/code&gt; is about bytes arriving, not about
where a program got its handle.&lt;/p&gt;
&lt;h3 id=&quot;it-is-a-reader-and-a-writer-whole&quot;&gt;It is a &lt;code&gt;Reader&lt;/code&gt; and a &lt;code&gt;Writer&lt;/code&gt;, whole&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{write_text, open, remove_file}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.lines

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; path = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-3.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(path, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;f)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(line)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(), f.&lt;span class=&quot;hl-function&quot;&gt;at_end&lt;/span&gt;())

f.&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[alpha][beta][gamma]
false true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lines(&amp;amp;f)&lt;/code&gt; works over a file with nothing in &lt;code&gt;sysl.fs&lt;/code&gt; knowing about lines, because &lt;code&gt;impl Reader for File&lt;/code&gt; is the trait unmodified. Everything that renders into a sink renders into a file for the same
reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That is also why &lt;code&gt;Fallible&lt;/code&gt; is a &lt;em&gt;required&lt;/em&gt; trait rather than a member each of them declares.&lt;/strong&gt;
&lt;code&gt;failed&lt;/code&gt; takes no arguments, so a &lt;code&gt;failed&lt;/code&gt; from &lt;code&gt;Reader&lt;/code&gt; and another from &lt;code&gt;Writer&lt;/code&gt; would be two
members of one name on one type and a call could not say which it meant — on a file, which is both.
One shared latch leaves a single answer that each of them reaches.&lt;/p&gt;
&lt;p&gt;Reaching a trait member still needs the trait in scope:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.open

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-3.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; window: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

f.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(window)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;sysl.fs.File has &apos;read&apos; from sysl.io.Reader, and that trait is not in scope here — import it to reach the member
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;position-and-size&quot;&gt;Position and size&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{write_text, open, size_of, remove_file}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; path = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-4.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(path, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;0123456789&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;size_of&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; window: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

f.&lt;span class=&quot;hl-function&quot;&gt;seek&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; got = f.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(window)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), got.len, got[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

f.&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10
10 4 54
10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;size&lt;/code&gt; asks the file rather than measuring it.&lt;/strong&gt; It was a seek to the end and back — four calls to
answer one question — because the alternative was &lt;code&gt;fstat&lt;/code&gt;, and &lt;code&gt;struct stat&lt;/code&gt; is laid out differently
by each platform’s headers: a program transcribing one holds numbers nothing checks, and being wrong
about them reads the wrong bytes rather than failing. A shim beside the module reads the header and
one field crosses, so the refusal costs nothing here any more. It never moves the position, which is
why &lt;code&gt;tell&lt;/code&gt; still reports 10 afterwards — where the seek version moved it and put it back, leaving it
at the end of the file if anything failed in between.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Where there is no shim, the seek is still what runs.&lt;/strong&gt; &lt;code&gt;sysl.fs&lt;/code&gt; requires &lt;code&gt;os&lt;/code&gt; rather than &lt;code&gt;posix&lt;/code&gt;,
so it reaches a Windows target that has no per-OS directory here — and &lt;code&gt;fseek&lt;/code&gt;/&lt;code&gt;ftell&lt;/code&gt; are ISO C, so
that path goes on working exactly as it did.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;size_of(path)&lt;/code&gt; is the same question without an open file in hand; it opens, asks, and closes, so a
missing file answers &lt;code&gt;NotFound&lt;/code&gt; rather than zero — the distinction a caller sizing a buffer needs and
the one a bare number could not carry.&lt;/p&gt;
&lt;h3 id=&quot;closing-and-using-a-file-after-it&quot;&gt;Closing, and using a file after it&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{create, remove_file}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; path = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-5.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-function&quot;&gt;create&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

f.&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;closed&lt;/span&gt;(), f.&lt;span class=&quot;hl-function&quot;&gt;at_end&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_ok&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(f.&lt;span class=&quot;hl-function&quot;&gt;seek&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;(), f.&lt;span class=&quot;hl-function&quot;&gt;seek&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;code&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; window: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; got = f.&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(window)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(got.len, f.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;())

&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(path).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true
true
the file is not open 9
0 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four rules are in that output.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closing is the program’s to do, and &lt;code&gt;defer f.close()&lt;/code&gt; is how it is written.&lt;/strong&gt; Dropping a &lt;code&gt;File&lt;/code&gt;
without closing it leaks the handle until the program exits, the same as in C.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; is the other way to arrange it, and &lt;code&gt;File&lt;/code&gt; deliberately does not
have one: a destructor runs for a value held behind a &lt;code&gt;&amp;amp;T&lt;/code&gt;, so giving &lt;code&gt;File&lt;/code&gt; one would mean a heap
box per open file and would take the choice away from a program that would rather not have one. What
a destructor is for is the resource that dies where no &lt;code&gt;defer&lt;/code&gt; can be written — inside a container,
inside a struct inside a container — and a handle a function opens and closes is not that.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;close&lt;/code&gt; is idempotent, and the second call is not merely tolerated — it is the case &lt;code&gt;defer&lt;/code&gt;
creates.&lt;/strong&gt; A function that closes on one path and defers the close for the others reaches the end
having done both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every other member checks the flag first, and none of them may skip it.&lt;/strong&gt; &lt;code&gt;fclose&lt;/code&gt; releases the
handle, so the pointer the struct holds afterwards names storage C has freed; reaching it would be a
use-after-free rather than a call that fails. What comes back instead is &lt;code&gt;NotOpen&lt;/code&gt;, which is &lt;code&gt;EBADF&lt;/code&gt; —
the code the operating system reports for the same mistake made one layer down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A read on a closed file latches rather than answering quietly empty.&lt;/strong&gt; An empty read means &lt;em&gt;end of
input&lt;/em&gt;, and a program told that would conclude it had read the whole file when what it had done was
close it too early. So &lt;code&gt;got.len&lt;/code&gt; is 0 &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;failed()&lt;/code&gt; is true, and the two together are the truth.&lt;/p&gt;
&lt;p&gt;A failure from &lt;code&gt;close&lt;/code&gt; is a real one, incidentally: the flush it performs is where a full disk finally
reports. A program that cares about its output checks the close and not only the writes.&lt;/p&gt;
&lt;h3 id=&quot;copies-share-one-handle&quot;&gt;Copies share one handle&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;File&lt;/code&gt; is a struct and therefore a value, so passing one to a function makes a second &lt;code&gt;File&lt;/code&gt;. It
holds its state behind a &lt;code&gt;&amp;amp;FileState&lt;/code&gt; rather than holding the pointer directly, and that is what makes
&lt;code&gt;close&lt;/code&gt; answerable at all: &lt;strong&gt;every copy shares one state&lt;/strong&gt;, so closing either is closing the file, and
closing it twice is harmless rather than a use-after-free. A value type holding the pointer would have
made that mistake easy.&lt;/p&gt;
&lt;h2 id=&quot;the-path-tier&quot;&gt;The path tier&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{write_text, exists, is_file, is_dir, readable, writable, rename, remove_file, size_of}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-6a.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-6b.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(a, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;is_file&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;is_dir&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;readable&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;writable&lt;/span&gt;(a))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;is_dir&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;is_file&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;rename&lt;/span&gt;(a, b).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(b), &lt;span class=&quot;hl-function&quot;&gt;size_of&lt;/span&gt;(b).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(b).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;exists&lt;/span&gt;(b), &lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(b).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true false true true
true false
false true 1
false no such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;exists&lt;/code&gt; answers &lt;code&gt;false&lt;/code&gt; for a path that exists under a directory the program may not search&lt;/strong&gt;,
which is the one way it differs from the question it looks like it is asking. That case cannot be told
from absence without a second call whose answer would already be stale — and every caller that
matters, one about to open the file, gets the truth from the open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is_dir&lt;/code&gt; asks by opening the path as a directory.&lt;/strong&gt; &lt;code&gt;DIR *&lt;/code&gt; is opaque, so it needs nothing about the
platform beyond two symbols, which is what makes it the one question about a path’s &lt;em&gt;kind&lt;/em&gt; the module
can answer honestly. &lt;code&gt;is_file&lt;/code&gt; is then “exists and is not a directory” — a device or a socket answers
true, which is right for what callers use it for: whether opening it as a file could work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;remove_file&lt;/code&gt; refuses a directory rather than removing it.&lt;/strong&gt; It is &lt;code&gt;unlink&lt;/code&gt;, where C’s own &lt;code&gt;remove&lt;/code&gt;
quietly does either; two names for two intentions is what lets a program that meant one of them find
out it had the other. &lt;code&gt;remove_dir&lt;/code&gt; is &lt;code&gt;rmdir&lt;/code&gt; and needs the directory empty, reporting
&lt;code&gt;DirectoryNotEmpty&lt;/code&gt; — the one code in the whole set whose number the two platforms disagree about,
which is why it is read through a call rather than written as a literal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;rename&lt;/code&gt; replaces whatever was at the destination&lt;/strong&gt;, is one operation as far as anything watching is
concerned when both paths are on the same filesystem, and &lt;em&gt;fails&lt;/em&gt; rather than copying when they are
not. That is &lt;code&gt;rename(2)&lt;/code&gt;‘s contract and worth knowing, since a program moving a file across devices
has to read and write it itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;make_dir&lt;/code&gt; makes one directory and needs its parent to be there.&lt;/strong&gt; Making a chain is a loop over
path separators, and where a separator &lt;em&gt;is&lt;/em&gt; is a question about paths rather than about the
filesystem — which this module does not answer. It asks for &lt;code&gt;0o777&lt;/code&gt;, letting the process umask narrow
it: asking for less would override the environment’s decision rather than defer to it.&lt;/p&gt;
&lt;h3 id=&quot;listing-a-directory&quot;&gt;Listing a directory&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.{entries, make_dir, write_text, remove_file, remove_dir}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; dir = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-entries&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;remove_dir&lt;/span&gt;(dir)          &lt;span class=&quot;hl-comment&quot;&gt;// in case an earlier run of this page left it behind&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;make_dir&lt;/span&gt;(dir).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(dir + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/one.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(dir + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/two.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; names = &lt;span class=&quot;hl-function&quot;&gt;entries&lt;/span&gt;(dir).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(names.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(names.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; || names.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(dir + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/one.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;remove_file&lt;/span&gt;(dir + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/two.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()
&lt;span class=&quot;hl-function&quot;&gt;remove_dir&lt;/span&gt;(dir).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;entries&lt;/span&gt;(dir).&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
true
no such file or directory
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.&lt;/code&gt; and &lt;code&gt;..&lt;/code&gt; are left out&lt;/strong&gt;, because every caller drops them: a program listing a directory is
asking what is &lt;em&gt;in&lt;/em&gt; it, and a recursive walk that forgets the filter does not terminate. &lt;strong&gt;The order
is the filesystem’s&lt;/strong&gt; — not sorted, and not stable between two listings of one directory. A program
that wants an order applies one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A name that is not UTF-8 stops the program&lt;/strong&gt;, exactly as &lt;code&gt;read_text&lt;/code&gt; does with a file’s contents
and for the same reason: answering with an error would put a case in &lt;code&gt;IoError&lt;/code&gt; that no filesystem
ever reports. POSIX names are bytes, so this is reachable rather than theoretical.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is the one thing in the module answered by C rather than by a bare &lt;code&gt;extern&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;readdir&lt;/code&gt; hands
back a &lt;code&gt;struct dirent&lt;/code&gt; whose name field sits at an offset the two platforms disagree about, which is
the transcription the rest of the module refuses — so a four-line shim returns the &lt;code&gt;char *&lt;/code&gt; and
nothing in sysl learns the layout. It sits in a &lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt; directory
(&lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;), which is what keeps it off a target with no directories to list.&lt;/p&gt;
&lt;h2 id=&quot;what-is-absent-and-why&quot;&gt;What is absent, and why&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Anything &lt;code&gt;stat&lt;/code&gt; would answer&lt;/strong&gt; — timestamps, ownership, a mode — for the reason &lt;code&gt;size&lt;/code&gt; is a seek.&lt;/p&gt;
&lt;p&gt;The rule the whole module is written under is one sentence: &lt;strong&gt;a question that can be answered by a
call whose signature is all there is to get right is answered here, and one that cannot is absent.&lt;/strong&gt;
No C structure is transcribed. One header &lt;em&gt;is&lt;/em&gt; included, in the shim behind &lt;code&gt;entries&lt;/code&gt;, which is the
shape the rest of this list should take as it shrinks: a question C can answer in three lines is
answered by C, and one that would need a structure transcribed into sysl is still not answered at all.
Where that leaves a gap, an &lt;code&gt;extern&lt;/code&gt; of one’s own — or a &lt;code&gt;.c&lt;/code&gt; of one’s own — is the honest way across
it, and &lt;a href=&quot;/reference/ffi/&quot;&gt;foreign functions&lt;/a&gt; is where that is written up.&lt;/p&gt;
&lt;h2 id=&quot;argument-types&quot;&gt;Argument types&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.write_text

&lt;span class=&quot;hl-function&quot;&gt;write_text&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-x.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;text&apos; of &apos;sysl.fs.write_text&apos; is string, but int was given
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.write_bytes

&lt;span class=&quot;hl-function&quot;&gt;write_bytes&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-x.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;bytes&apos; of &apos;sysl.fs.write_bytes&apos; is []const byte, but string was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;write_bytes&lt;/code&gt; wants bytes and &lt;code&gt;s.bytes&lt;/code&gt; is how a &lt;code&gt;string&lt;/code&gt; supplies them — free, since a &lt;code&gt;string&lt;/code&gt;
already is a validated &lt;code&gt;[]u8&lt;/code&gt;. &lt;code&gt;write_text&lt;/code&gt; is the same call with that step written in.&lt;/p&gt;
&lt;p&gt;And every one of these answers with a &lt;code&gt;Result&lt;/code&gt;, which has to be opened before the file inside it is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.fs.open

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp/sysl-fs-doc-x.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

f.&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;type &apos;sysl$Result&apos; has no method &apos;close&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; inside a function that returns a &lt;code&gt;Result&lt;/code&gt;, or &lt;code&gt;unwrap()&lt;/code&gt; in a program that would rather stop, are
the two ways through. &lt;a href=&quot;/reference/errors/&quot;&gt;Errors and contracts&lt;/a&gt; has the rest.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt; — the float functions, and the integer traits.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Coming from C</title>
    <link href="https://sysl.sh/getting-started/from-c/"/>
    <id>https://sysl.sh/getting-started/from-c/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>What translates straight across, what changes shape, and the refusals a C program runs into first.</summary>
    <content type="html">&lt;p&gt;Most of C comes across unchanged. You still choose where a value lives, you still have a pointer,
you still have &lt;code&gt;sizeof&lt;/code&gt;, and there is still no runtime underneath deciding things for you. What
changes is a short list, and this page is that list — read it and the &lt;a href=&quot;/tour/&quot;&gt;tour&lt;/a&gt; will mostly be
confirming what you already expected.&lt;/p&gt;
&lt;h2 id=&quot;the-map&quot;&gt;The map&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;C&lt;/th&gt;&lt;th&gt;sysl&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;unsigned&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;byte&lt;/code&gt;, &lt;code&gt;uint&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a width is a &lt;strong&gt;type&lt;/strong&gt;; nothing promotes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T *&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;*T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same pointer, spelled so you can grep for it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;malloc&lt;/code&gt; / &lt;code&gt;free&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;construct where a &lt;code&gt;&amp;amp;T&lt;/code&gt; is expected; the count frees it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T a[N]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[N]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a fixed array — it converts to a view, and the length comes with it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;T *&lt;/code&gt; plus a length&lt;/td&gt;&lt;td&gt;&lt;code&gt;[]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one value that carries the length&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;const T *&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[]const T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the read-only-ness is in the type and travels with it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;char *&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;validated UTF-8, with a length, and no terminator&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same thing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;union&lt;/code&gt; and a tag beside it&lt;/td&gt;&lt;td&gt;&lt;code&gt;enum&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one construct, and the arms are checked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;typedef&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;type&lt;/code&gt;, or &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c type&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;type&lt;/code&gt; narrows or renames a scalar; a bare alias is refused. &lt;code&gt;c type&lt;/code&gt; is for a typedef in a &lt;em&gt;header&lt;/em&gt;, whose width the C compiler answers for&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;#define MAX 512&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;const MAX: usize = 512&lt;/code&gt;&lt;/td&gt;&lt;td&gt;folded into every use, no storage, usable as an array bound&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;static&lt;/code&gt; at file scope&lt;/td&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a header&lt;/td&gt;&lt;td&gt;a module&lt;/td&gt;&lt;td&gt;no &lt;code&gt;#include&lt;/code&gt;, no include guard, no forward declaration&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;NULL&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;td&gt;on a &lt;code&gt;*T&lt;/code&gt; and nowhere else&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;errno&lt;/code&gt;, a returned &lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Result[T, E]&lt;/code&gt; and &lt;code&gt;?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assert.h&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;assert&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; / &lt;code&gt;ensure&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;printf&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;print&lt;/code&gt;, and &lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a function pointer&lt;/td&gt;&lt;td&gt;&lt;code&gt;*extern(A) -&amp;gt; R&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;_Alignof&lt;/code&gt;, &lt;code&gt;offsetof&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt;, &lt;code&gt;offsetof&lt;/code&gt;&lt;/td&gt;&lt;td&gt;over any type&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;volatile T *&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;volatile&lt;/code&gt; on the &lt;strong&gt;field&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;the storage is qualified, not the pointer to it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;goto&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a labelled &lt;code&gt;break&lt;/code&gt; / &lt;code&gt;continue&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-allocation-is-a-construction&quot;&gt;The allocation is a construction&lt;/h2&gt;
&lt;p&gt;There is no &lt;code&gt;malloc&lt;/code&gt; and no &lt;code&gt;free&lt;/code&gt;, and no keyword took their place. Writing an ordinary
construction where a &lt;code&gt;&amp;amp;T&lt;/code&gt; is expected is what puts the object on the heap:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    next: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; head: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(head.value)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Node(1, None)&lt;/code&gt; is the same expression that would have built a value; the annotation &lt;code&gt;&amp;amp;Node&lt;/code&gt; is what
makes it a heap object with a count. When the last reference goes, so does the object — there is no
line to write and no line you can forget to write.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;weak Node&lt;/code&gt; is the other half of the same story, and it is the field a C programmer will reach for
without thinking. A parent pointer, a back-link, an entry in an index: in C those are just pointers,
and the reason they work is that they do not own. &lt;code&gt;weak&lt;/code&gt; is that, said out loud — it does not keep
the object alive, and reading it is a question rather than an assumption.&lt;/p&gt;
&lt;h2 id=&quot;an-array-converts-and-the-length-comes-with-it&quot;&gt;An array converts, and the length comes with it&lt;/h2&gt;
&lt;p&gt;In C, an array in an expression becomes a pointer to its first element and &lt;strong&gt;the length is gone&lt;/strong&gt; —
which is why every C function taking a buffer takes a count beside it, and why the two can disagree.
sysl has the same convenience and none of the loss: an array converts where a view is asked for, and
what it converts to carries the length.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; buf: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

buf[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
buf[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; view: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = buf

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(view.len, view[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;[4]int&lt;/code&gt; is the storage; &lt;code&gt;[]int&lt;/code&gt; is a view of it — three words rather than one: owner, pointer,
length. So a function that takes a buffer takes one parameter, and the call reads as it does in C:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;(xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;xs.len &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; xs[i] = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], a[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], a.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 0 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;a&lt;/code&gt; is still a &lt;code&gt;[3]int&lt;/code&gt;, and &lt;code&gt;zero&lt;/code&gt; cannot be told a wrong length because it was not told one. The
explicit &lt;code&gt;a[..]&lt;/code&gt; writes the same conversion; what you reach for it for is &lt;em&gt;part&lt;/em&gt; of the array rather
than all of it — &lt;code&gt;a[1..]&lt;/code&gt;, &lt;code&gt;a[..&amp;lt;2]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Every index through a view is bounds-checked against the length it carries. That is the one cost
sysl adds here, and it buys the class of bug C’s decay makes unfindable.&lt;/p&gt;
&lt;h2 id=&quot;widths-are-types-and-nothing-promotes&quot;&gt;Widths are types, and nothing promotes&lt;/h2&gt;
&lt;p&gt;C’s usual arithmetic conversions are absent. &lt;code&gt;byte&lt;/code&gt; arithmetic is &lt;code&gt;byte&lt;/code&gt; arithmetic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(small + &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(small) + &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;44 300
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first wraps at 256 because both operands are &lt;code&gt;byte&lt;/code&gt;; the second is &lt;code&gt;int&lt;/code&gt; arithmetic because the
conversion was written. Neither happened by accident, and no rule about ranks or signedness has to be
recalled to predict which one you got. &lt;a href=&quot;/tour/values/&quot;&gt;Values&lt;/a&gt; has the family, which is open — &lt;code&gt;u12&lt;/code&gt;
and &lt;code&gt;i5&lt;/code&gt; are types you may write.&lt;/p&gt;
&lt;h2 id=&quot;a-string-is-not-a-char&quot;&gt;A string is not a &lt;code&gt;char *&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s.len, s.chars.&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six &lt;strong&gt;bytes&lt;/strong&gt; and five &lt;strong&gt;characters&lt;/strong&gt;, and the difference is the point: a &lt;code&gt;string&lt;/code&gt; is UTF-8 that has
been validated, and it carries its length rather than ending at a NUL. &lt;code&gt;s.len&lt;/code&gt; is bytes because that
is what indexing and slicing are in; &lt;code&gt;s.chars&lt;/code&gt; walks scalar values. There is no cheap byte that is
also a character, so the two are never confused.&lt;/p&gt;
&lt;p&gt;When you need C’s shape at a boundary, &lt;code&gt;cstring(s)&lt;/code&gt; builds one — a terminator and a pointer, for
passing to a C function. &lt;a href=&quot;/reference/strings/&quot;&gt;Strings&lt;/a&gt; has both directions.&lt;/p&gt;
&lt;h2 id=&quot;a-tagged-union-is-one-construct&quot;&gt;A tagged union is one construct&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(side: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Shape&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r)  -&amp;gt; r * r
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(a)  -&amp;gt; a * a

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In C this is a struct holding a tag and a union, and nothing checks that the tag you branched on is
the member you read. Here the tag and the payload are one value, the payload is reachable only
through the arm that established it, and a &lt;code&gt;match&lt;/code&gt; missing an arm is a compile error rather than a
silent fall-through. &lt;code&gt;Circle(2.0)&lt;/code&gt; constructs — there is no &lt;code&gt;Shape.&lt;/code&gt; to write, because a variant name
belongs to its enum.&lt;/p&gt;
&lt;h2 id=&quot;the-pointer-is-still-there&quot;&gt;The pointer is still there&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;*T&lt;/code&gt; is C’s pointer with C’s rules, and it is deliberately the ugly one to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    next: &lt;span class=&quot;hl-keyword&quot;&gt;weak&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p == &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 4 16 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;null&lt;/code&gt; belongs to &lt;code&gt;*T&lt;/code&gt; alone. Selection through one is ordinary — &lt;code&gt;p.field&lt;/code&gt; is C’s &lt;code&gt;p-&amp;gt;field&lt;/code&gt;, with
no operator of its own to remember — and it is unchecked, exactly as it is in C. That is what a raw
pointer is &lt;em&gt;for&lt;/em&gt;: it is how you talk to hardware, to a foreign library, and to memory you are
managing yourself, and the compiler stays out of it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sizeof&lt;/code&gt; and &lt;code&gt;alignof&lt;/code&gt; take any type, not just a name, and answer with what the target actually
lays out.&lt;/p&gt;
&lt;h2 id=&quot;two-refusals-worth-meeting-early&quot;&gt;Two refusals worth meeting early&lt;/h2&gt;
&lt;p&gt;A reference is never null, so there is no failure to test for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &amp;amp;Point always points at a live object — an absent one is Option[&amp;amp;Point]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole trade: C’s &lt;code&gt;T *&lt;/code&gt; answers two questions at once — &lt;em&gt;where is it&lt;/em&gt; and &lt;em&gt;is there one&lt;/em&gt;
— and sysl splits them. &lt;code&gt;&amp;amp;T&lt;/code&gt; is the first, &lt;code&gt;Option[&amp;amp;T]&lt;/code&gt; is both, and &lt;code&gt;*T&lt;/code&gt; is still there for when
you want C’s answer.&lt;/p&gt;
&lt;p&gt;Nor does a reference do arithmetic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = p + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got &amp;amp;Point and int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Walking memory is a &lt;code&gt;*T&lt;/code&gt;‘s job, and a &lt;code&gt;[]T&lt;/code&gt; is what you want nine times out of ten — it is the
pointer-and-length pair C makes you carry by hand, with the bounds check that pair was always for.&lt;/p&gt;
&lt;h2 id=&quot;what-c-has-and-sysl-does-not&quot;&gt;What C has and sysl does not&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A &lt;code&gt;static&lt;/code&gt; inside a function.&lt;/strong&gt; There is no per-function persistent storage, and there is no
module-level &lt;code&gt;var&lt;/code&gt; either — &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt; has why the keyword is taken. State
that outlives a call goes in a struct the caller owns and passes in, which is what a C program
ends up doing anyway the first time it needs two of anything.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An untagged union.&lt;/strong&gt; A &lt;code&gt;union&lt;/code&gt; whose discriminant lives somewhere else has no spelling. Where
the discriminant is real, an &lt;code&gt;enum&lt;/code&gt; is it; where the point is reinterpreting bytes, that is
&lt;code&gt;ptr_cast&lt;/code&gt; and it is in &lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A bitfield &lt;em&gt;declarator&lt;/em&gt;.&lt;/strong&gt; There is no &lt;code&gt;unsigned x : 5&lt;/code&gt;, and nothing is missing by its absence:
inside a &lt;code&gt;@packed&lt;/code&gt; struct a &lt;code&gt;u5&lt;/code&gt; field already occupies exactly five bits, so a width is written
where every other width is. What sysl adds is that the two things C leaves to the implementation —
which end the bits fill from, and whether one may cross a byte — are fixed by the language.
&lt;code&gt;volatile unsigned x : 3&lt;/code&gt; carries over as well, and means what it means in C: a volatile access of
the container, so a write is a read-modify-write of it.
&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; has the rules.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;goto&lt;/code&gt;.&lt;/strong&gt; Not even a reserved word. A labelled &lt;code&gt;break&lt;/code&gt; or &lt;code&gt;continue&lt;/code&gt; reaches the case that
actually comes up, which is leaving a nested loop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The preprocessor.&lt;/strong&gt; No macros, no textual inclusion, no include guards. &lt;code&gt;const&lt;/code&gt; covers a
&lt;code&gt;#define&lt;/code&gt; of a value, a module covers a header, and &lt;code&gt;#if&lt;/code&gt; covers platform gating —
&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; has the closed set of symbols it may test.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-sysl-checks-that-c-does-not&quot;&gt;What sysl checks that C does not&lt;/h2&gt;
&lt;p&gt;Every index against a length. Every &lt;code&gt;match&lt;/code&gt; for a missing arm. Every &lt;strong&gt;numeric&lt;/strong&gt; conversion, because
none of those is implicit — a value never changes width on its own, whatever the surrounding
expression wants. Every contract you write with &lt;code&gt;require&lt;/code&gt; and &lt;code&gt;ensure&lt;/code&gt;, in every build: there is no
release mode that drops them, and no flag that strips a bounds check either. And a reference that is
counted rather than freed by hand, which is the one that turns a class of bug into a class of
question you no longer have to ask.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; implicit is a different kind of thing, and none of it loses information. An ordinary
construction becomes a &lt;code&gt;&amp;amp;T&lt;/code&gt; where one is expected, a &lt;code&gt;&amp;amp;x&lt;/code&gt; becomes a trait object where one is
expected, an array form written where a &lt;code&gt;[]T&lt;/code&gt; is wanted makes storage of its own, and a &lt;code&gt;[]T&lt;/code&gt; is
accepted where a &lt;code&gt;[]const T&lt;/code&gt; is wanted — the direction that takes a permission away, never the one
that grants it. Each of those adds an owner or removes a licence. None of them changes a value’s
width, which is the implicit conversion C actually has and the one this page is about.&lt;/p&gt;
&lt;h2 id=&quot;you-do-not-have-to-start-over&quot;&gt;You do not have to start over&lt;/h2&gt;
&lt;p&gt;A language is adopted a file at a time or not at all, and both directions across the boundary are
open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;sysl on top, your C underneath.&lt;/strong&gt; An &lt;code&gt;extern&lt;/code&gt; declares a symbol the linker already has, and
&lt;code&gt;@link(&amp;quot;z&amp;quot;)&lt;/code&gt; names the library that resolves it. Nothing is generated and no header is parsed — you
write the declarations you use and no more, and one nothing calls costs the output nothing. A &lt;code&gt;.c&lt;/code&gt;
file dropped in any module of the tree is compiled with it, which is how the parts a header hides — a
macro, a &lt;code&gt;sizeof&lt;/code&gt; only the header knows, an untagged union — get reached at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your C on top, sysl underneath.&lt;/strong&gt; &lt;code&gt;@export&lt;/code&gt; publishes a plain, unmangled symbol, entered under your
machine’s C convention — so a struct crosses it by value exactly as it does one of your own functions
— and &lt;code&gt;sysl build-c&lt;/code&gt; writes a static archive and a C header for your existing build to consume:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mylib_add&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;$ sysl build-c mylib -o libmylib.a
wrote libmylib.a
wrote libmylib.a.h
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;libmylib.a.h&amp;quot;

int main(void) { return mylib_add(2, 3); }
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;$ clang main.c libmylib.a -o app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The exported signatures are the C-shaped ones — scalars, pointers, function pointers — because that
is what a C prototype can say. What you write is a &lt;strong&gt;boundary file&lt;/strong&gt;: one module whose job is the
surface, holding the handful of functions the C side calls, with everything behind it written in
whatever shapes sysl prefers. That is the same facade a C++ or Rust library grows for the same
reason, and &lt;a href=&quot;/reference/ffi/&quot;&gt;the FFI reference&lt;/a&gt; has the whole of what may cross.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: the &lt;a href=&quot;/tour/&quot;&gt;tour&lt;/a&gt;, which starts from the beginning and does not assume you read this.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Your first program</title>
    <link href="https://sysl.sh/getting-started/first-program/"/>
    <id>https://sysl.sh/getting-started/first-program/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A file with no ceremony in it, and what the compiler did with it.</summary>
    <content type="html">&lt;p&gt;Put this in &lt;code&gt;hello.sysl&lt;/code&gt;, anywhere you like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Hello, sysl!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; width = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; height = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;area =&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, width * height)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl run hello.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(From a source checkout instead of an installed binary, that is
&lt;code&gt;sbt &amp;quot;syslJVM/run run hello.sysl&amp;quot;&lt;/code&gt;.)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Hello, sysl!
area = 42
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-is-not-there&quot;&gt;What is not there&lt;/h2&gt;
&lt;p&gt;No &lt;code&gt;main&lt;/code&gt;. No imports. No class wrapped around the statements to give them somewhere to live. A
sysl file is a module, and statements written at its top level run in order — so the smallest
program is the code you actually meant to write.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;main&lt;/code&gt; is available when you want one, and you want one as soon as you care about the program’s
arguments:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;started as:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, args[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(args.len - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;argument(s) given&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;print&lt;/code&gt; came from &lt;code&gt;sysl&lt;/code&gt;, the standard module — the one module a file may write the names of without
importing it, because it holds what the language desugars onto. It takes any number of arguments,
converts each one to text, and separates them with spaces.&lt;/p&gt;
&lt;h2 id=&quot;what-the-compiler-did&quot;&gt;What the compiler did&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;run&lt;/code&gt; is one command of several, and it did four things in a row: parsed and checked the source,
emitted textual LLVM IR, handed that to &lt;code&gt;clang&lt;/code&gt; to assemble and link against the standard library
archive, and ran the binary that came out. The binary is real — there is no interpreter and no VM
underneath it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;build&lt;/code&gt; stops after producing that binary instead of running it, and &lt;code&gt;test&lt;/code&gt; runs the &lt;code&gt;@test&lt;/code&gt;
functions in a directory. The tour uses &lt;code&gt;run&lt;/code&gt; throughout.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-next&quot;&gt;Where to go next&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/tour/&quot;&gt;tour&lt;/a&gt; starts here and builds up. It is meant to be read in order, and every program in
it is one you can paste into a file and run.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/getting-started/cli/&quot;&gt;The command line&lt;/a&gt; is the other direction: the rest of the subcommands, the
flags they share, and what each one leaves as an exit status. Nothing in the tour needs it.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>fft</title>
    <link href="https://sysl.sh/guides/fft/"/>
    <id>https://sysl.sh/guides/fft/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A transform kept beside the definition it rearranges, and checked against it.</summary>
    <content type="html">&lt;p&gt;The discrete Fourier transform, twice: the O(n log n) one everybody uses and the O(n²) one that is
the definition.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Having both is the point.&lt;/strong&gt; The fast transform is a &lt;em&gt;rearrangement&lt;/em&gt; of the slow one, and a
rearrangement is exactly the kind of thing that can be subtly wrong and still produce plausible
numbers — so the slow one is kept as the thing to compare against. Published values then anchor the
pair, since two implementations by the same author agreeing proves only that they agree.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: an algorithm checked against its own definition.&lt;/strong&gt; Every other program in the set is
checked against values somebody else wrote down, and this one is too — but it also carries the thing
it is supposed to be equal to, and runs it. A spot check accepts a plausible number; the definition
does not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The complex arithmetic used to be this program’s own, and is now
&lt;a href=&quot;/library/complex/&quot;&gt;&lt;code&gt;sysl.math.complex&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; That is the ordinary end of a guide program’s life: it
was written here because there was nothing to import, the friction it turned up is what moved the
language, and once the type existed there was no reason for a second copy of it. Nothing in the
language knows what a complex number is — the &lt;a href=&quot;/reference/expressions/&quot;&gt;operator traits&lt;/a&gt; are still
the whole mechanism, and the program still leans on them hardest.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The width of an integer type is askable, and the first draft said it was not.&lt;/strong&gt; This is a finding
that got &lt;em&gt;retracted&lt;/em&gt;, which is worth as much as one that stands. The header originally recorded that
the machine word width could not be obtained at a type parameter; it can —
&lt;code&gt;count_ones() + count_zeros()&lt;/code&gt; is the width by construction, at whatever &lt;code&gt;Self&lt;/code&gt; turned out to be. That
is what &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt; means by keeping the second of that pair rather than leaving it
to a subtraction, and it means nothing has to hard-code 64.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What actually stops the closed form is the empty shift.&lt;/strong&gt; &lt;code&gt;Bits.reverse_bits&lt;/code&gt; reverses the whole
width, so bit-reversing an index would be &lt;code&gt;v.reverse_bits() &amp;gt;&amp;gt; (w - bits)&lt;/code&gt; — and a one-sample
transform reaches that with &lt;code&gt;bits&lt;/code&gt; at zero, since &lt;code&gt;bit_width(1)&lt;/code&gt; is &lt;code&gt;trailing_zeros(1)&lt;/code&gt;, which is
zero. A shift by the full width is the case the instruction does not define, so the loop stays.&lt;/p&gt;
&lt;p&gt;That is the more useful shape of finding: not “the language cannot express this” but “the language
expresses it and the &lt;em&gt;machine&lt;/em&gt; has an edge case”, which no amount of language design removes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trait written for somebody else’s type has to find a name that is still free.&lt;/strong&gt; What survived the
move to the library is &lt;code&gt;sum&lt;/code&gt; — the generic total that starts at a value the type promised rather than
at &lt;code&gt;xs[0]&lt;/code&gt;, which is what keeps an empty sequence from needing an &lt;code&gt;Option&lt;/code&gt; in the signature. The
trait behind it wanted a &lt;code&gt;zero() -&amp;gt; Self&lt;/code&gt;, and could not have one: a trait’s members become the
implementing type’s, and &lt;code&gt;Complex&lt;/code&gt; already declares a &lt;code&gt;zero&lt;/code&gt;. So the member is called &lt;code&gt;identity&lt;/code&gt;, for
what it is rather than for the value it answers. The more ordinary the concept, the likelier that
collision is — and there is no way to name the member the trait &lt;em&gt;means&lt;/em&gt; apart from the name it goes
under.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/fft&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/sha2/&quot;&gt;sha2&lt;/a&gt; — one algorithm at two widths.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The foreign interface</title>
    <link href="https://sysl.sh/reference/ffi/"/>
    <id>https://sysl.sh/reference/ffi/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`extern`, link names, intrinsics, function addresses, variadics, opaque handles, interrupt handlers, and a library that carries C.</summary>
    <content type="html">&lt;p&gt;sysl has no functions built into the compiler that a program could not have written. &lt;code&gt;Option&lt;/code&gt; and
&lt;code&gt;Result&lt;/code&gt; are library enums, &lt;code&gt;unwrap&lt;/code&gt; is a library member, &lt;code&gt;print&lt;/code&gt; is library sysl reached by a
desugaring. &lt;strong&gt;The one thing a program genuinely cannot write for itself is the first call out of
sysl&lt;/strong&gt; — into libc on a hosted target, into a driver primitive on a bare one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;extern&lt;/code&gt; is that seam, and nothing more. It is a declaration form rather than a set of names the
compiler knows, which is why the whole of this page is about &lt;em&gt;declaring&lt;/em&gt; what is on the other side
and almost nothing about what is there.&lt;/p&gt;
&lt;h2 id=&quot;extern-a-declaration-with-no-body&quot;&gt;&lt;code&gt;extern&lt;/code&gt; — a declaration with no body&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;memcpy&lt;/span&gt;(dst: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, src: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a function header, and &lt;strong&gt;the absence of a body is the whole difference&lt;/strong&gt;. Everything
downstream is the ordinary path: a call is checked against the declared signature, its arity is
checked, and it lowers to an ordinary call. The result type is optional and absent means &lt;code&gt;unit&lt;/code&gt;,
exactly as for a function.&lt;/p&gt;
&lt;p&gt;Four rules follow from having no body:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Externs live in the one function namespace&lt;/strong&gt;, so an extern and a function cannot share a name.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An extern is never generic.&lt;/strong&gt; There is no body to monomorphize.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The escape analysis assumes the worst of it&lt;/strong&gt; — every argument may be kept, and the result may
view any of them — because nothing can tell whether the foreign side held on to what it was
handed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A declaration nothing calls is not emitted at all&lt;/strong&gt;, so declaring more of a C library than a
program uses costs nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The namespace rule is the one that surprises, because the name a program uses is ordinarily the
symbol:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = n&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;abs&apos; is already declared as an &apos;extern&apos;, which this would overload — what tells overloads of an &apos;extern&apos; apart is the symbol each names, and a sysl function declares no symbol
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where a program wants that name for itself, the link name below is what separates the two.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;extern f() -&amp;gt; never&lt;/code&gt; is how a program says the callee does not come back, which is what makes the
exit path of a panic ordinary sysl rather than a compiler intrinsic.&lt;/p&gt;
&lt;h3 id=&quot;an-extern-also-declares-a-variable&quot;&gt;An &lt;code&gt;extern&lt;/code&gt; also declares a variable&lt;/h3&gt;
&lt;p&gt;Written &lt;code&gt;name: type&lt;/code&gt;. What follows the name is what says which of the two a declaration is — a
parameter list makes it a function, a type makes it storage:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; optind: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; environ: *&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(optind)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is here because a C library’s interface is not only its calls.&lt;/strong&gt; &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;stderr&lt;/code&gt; and &lt;code&gt;stdin&lt;/code&gt;
are variables, and half of &lt;code&gt;stdio.h&lt;/code&gt; is reached through them; so are &lt;code&gt;environ&lt;/code&gt;, &lt;code&gt;optarg&lt;/code&gt;, &lt;code&gt;optind&lt;/code&gt;,
&lt;code&gt;tzname&lt;/code&gt; and &lt;code&gt;sys_errlist&lt;/code&gt;. Where C also offers a getter there is a way round — &lt;code&gt;errno&lt;/code&gt; is
&lt;code&gt;__error()&lt;/code&gt; on Darwin, and an ordinary &lt;code&gt;extern&lt;/code&gt; reaches that — but &lt;code&gt;stdout&lt;/code&gt; has none that is the
&lt;em&gt;same object&lt;/em&gt;, since &lt;code&gt;fdopen(1, &amp;quot;w&amp;quot;)&lt;/code&gt; is a different &lt;code&gt;FILE&lt;/code&gt; with its own buffer and interleaves
wrongly with anything already writing to the real one. &lt;code&gt;environ&lt;/code&gt; has no way round at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The type is written and never inferred.&lt;/strong&gt; There is no initializer to infer it from, and what the
other side laid down is not something this compiler can see. Writing the wrong one is the same kind
of promise a wrong parameter list is. The one type refused is one that occupies nothing, because a
symbol is an address and a value with no representation has nothing to put one at:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; nothing: &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;nothing&apos; cannot be an &apos;extern&apos; variable: a unit value occupies nothing, so there is no storage for the linker to resolve the name to
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is a place, and a writable one&lt;/strong&gt; — the one respect in which it is unlike every other global the
language has. A &lt;a href=&quot;/reference/modules/&quot;&gt;module-level &lt;code&gt;val&lt;/code&gt;&lt;/a&gt; is read-only at every depth and counts
nothing, because it owns what it names for the whole run and promises never to change it. An
&lt;code&gt;extern&lt;/code&gt; variable owns nothing and promises nothing: the storage is C’s, C writes it, and
&lt;code&gt;optind = 1&lt;/code&gt; before a &lt;code&gt;getopt&lt;/code&gt; loop is ordinary use of the interface being reached. The type rule
does not carry over either — a &lt;code&gt;val&lt;/code&gt; is refused a &lt;code&gt;&amp;amp;T&lt;/code&gt; because nothing would ever release it, and an
&lt;code&gt;extern&lt;/code&gt; variable may name whatever the other side laid down, because releasing it was never this
program’s job.&lt;/p&gt;
&lt;h3 id=&quot;naming-the-symbol-separately&quot;&gt;Naming the symbol separately&lt;/h3&gt;
&lt;p&gt;A string before the name is what the linker resolves; the identifier after it is what the program
calls it by:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;magnitude&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;absolute&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;magnitude&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;absolute&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without one the two are the same, which is the common case and stays the default. The separation
exists because &lt;strong&gt;a symbol’s spelling belongs to whoever exported it&lt;/strong&gt;: it may be shaped nothing like
sysl, it may be a name the program wants for something of its own, and — the case that forced it —
a declaration in the &lt;em&gt;library&lt;/em&gt; would otherwise spend that name out of every program’s namespace. The
standard library renders integers and floats through &lt;code&gt;snprintf&lt;/code&gt;, and a program that declares
&lt;code&gt;snprintf&lt;/code&gt; itself must not collide with it.&lt;/p&gt;
&lt;p&gt;The case where nothing else would do at all is a header macro. What C calls &lt;code&gt;stdout&lt;/code&gt; is a &lt;code&gt;#define&lt;/code&gt;,
and the symbol behind it is &lt;code&gt;__stdoutp&lt;/code&gt; on Darwin and &lt;code&gt;stdout&lt;/code&gt; elsewhere — so &lt;code&gt;extern &amp;quot;__stdoutp&amp;quot; stdout: *u8&lt;/code&gt; is the only declaration that reaches it, and a transcription of the header’s spelling
would reach nothing.&lt;/p&gt;
&lt;p&gt;The symbol must be one a linker could resolve — letters, digits, &lt;code&gt;_&lt;/code&gt;, &lt;code&gt;$&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;not a symbol!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;weird&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;weird&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;not a symbol!&apos; is not a symbol a linker can resolve
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two declarations may share one symbol under different sysl names, as above; a module declares each
symbol once. &lt;strong&gt;A link name is an &lt;code&gt;extern&lt;/code&gt;‘s alone&lt;/strong&gt; — a sysl function is &lt;em&gt;defined&lt;/em&gt; here, and what it
is called is its name.&lt;/p&gt;
&lt;p&gt;Note what this does &lt;em&gt;not&lt;/em&gt; do: nothing here changes what a sysl function’s own symbol is. It is the
name, unmangled, so a program that defines &lt;code&gt;abs&lt;/code&gt; collides with libc’s whatever else it declares.&lt;/p&gt;
&lt;h3 id=&quot;a-link-name-in-the-llvm-namespace-names-an-instruction&quot;&gt;A link name in the &lt;code&gt;llvm.&lt;/code&gt; namespace names an instruction&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llvm.sqrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;root&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llvm.sqrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;rootf&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;root&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9.0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;rootf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two kinds of &lt;code&gt;extern&lt;/code&gt; differ only in &lt;strong&gt;who resolves them&lt;/strong&gt; — the linker, or the back end — and
that needs no keyword to say which, because LLVM owns that namespace: a module defining a symbol
beginning &lt;code&gt;llvm.&lt;/code&gt; is invalid IR, so no library can export one and a link name there cannot mean
anything else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The width is derived, not written.&lt;/strong&gt; LLVM overloads an intrinsic on its operand type and spells
the choice in the name — &lt;code&gt;llvm.sqrt.f64&lt;/code&gt;, &lt;code&gt;llvm.sqrt.f32&lt;/code&gt; — so a declaration stating the whole thing
would say the width twice and let the two disagree. What is written is the base; the suffix comes
from the signature, which is why the pair above is one name at two widths.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The set is closed&lt;/strong&gt;, and the reason is not caution about the feature. An intrinsic’s signature
belongs to LLVM and moves between releases, and a declaration that disagrees is not a link error —
it is a verifier failure at best and a miscompile at worst, reported against generated IR rather
than against a line someone wrote. So the compiler holds the list it supports and checks each
declaration against it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llvm.nosuchthing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;bogus&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;bogus&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;llvm.nosuchthing&apos; is not an intrinsic sysl supports — it has llvm.ceil, llvm.copysign, llvm.fabs, llvm.floor, llvm.round, llvm.sqrt, llvm.trunc
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What it is for is not only speed.&lt;/strong&gt; An intrinsic that lowers to an instruction leaves no symbol
behind, so the operation needs no library at the link — which is what lets the standard module’s
roots, magnitudes, sign transfers and roundings work on a &lt;strong&gt;freestanding&lt;/strong&gt; target, where there is no
libm to ask. Where the machine has no instruction there is nothing to gain: &lt;code&gt;llvm.sin&lt;/code&gt; exists and
lowers to a call to the same &lt;code&gt;sin&lt;/code&gt; an ordinary &lt;code&gt;extern&lt;/code&gt; names, so the transcendentals stay linked.&lt;/p&gt;
&lt;h3 id=&quot;what-crosses-the-boundary&quot;&gt;What crosses the boundary&lt;/h3&gt;
&lt;p&gt;A scalar or a &lt;code&gt;*T&lt;/code&gt; matches C directly. A &lt;code&gt;string&lt;/code&gt; or a &lt;code&gt;&amp;amp;T&lt;/code&gt; is a sysl layout C has no notion of, and
handing one over is the same kind of promise &lt;code&gt;*T&lt;/code&gt; already is — &lt;strong&gt;what crosses is the programmer’s
business.&lt;/strong&gt; The usual move is to convert:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cs = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;strlen&lt;/span&gt;(cs.ptr))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;cstring&lt;/code&gt; copies the text into the NUL-terminated shape C reads and &lt;em&gt;owns&lt;/em&gt; that copy, which is how a
language with no manual free says who frees it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What crosses by value is not the programmer’s business.&lt;/strong&gt; A struct, a tuple, a view, an enum —
every aggregate — is handed over in whichever registers the machine’s C convention names, which is
not the same as the registers a sysl-to-sysl call would use and is not what LLVM does with an
aggregate left to itself. So a foreign declaration is emitted in the &lt;strong&gt;coerced&lt;/strong&gt; types that
convention asks for, and the call converts each value into and out of them. The shape a program
wrote is unchanged, nothing about it is visible in a program, and nothing about it applies to a
struct handed over behind a &lt;code&gt;*T&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;a href=&quot;/reference/vectors/&quot;&gt;vector&lt;/a&gt; is the one shape that does not cross, in either direction.&lt;/strong&gt; Which
register a &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; arrives in differs by target &lt;em&gt;and&lt;/em&gt; by which instruction-set extensions the other
side was compiled with — the same C source built with and without &lt;code&gt;-mavx2&lt;/code&gt; does not agree — so there
is no convention to emit against and sysl declines to guess at one. Guessing would not fail to link:
it would produce a call that resolves and corrupts its arguments, which is the failure a boundary
check exists to prevent.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;process_lanes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;process&lt;/span&gt;(v: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;how a vector reaches a C function differs by target
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pass the lanes through memory instead — a &lt;code&gt;*f32&lt;/code&gt; and a count, which is what C’s own SIMD-taking
functions take and what has one meaning on both sides.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A scalar narrower than a register is not quite free either.&lt;/strong&gt; A &lt;code&gt;u8&lt;/code&gt; is a byte to both languages, so
there is nothing to coerce — but it travels in a register a whole word wide, and most conventions
require whoever hands it over to widen it to fill one first. Sysl writes that widening where the
convention asks for it: on an argument at the call, and on the result of every function it defines,
so that a &lt;code&gt;bool&lt;/code&gt; answered to a C caller is a &lt;code&gt;bool&lt;/code&gt; rather than one bit beside thirty-one undefined
ones. Which values are widened, and whether by sign or by zero, is the &lt;em&gt;target’s&lt;/em&gt; answer rather than
the language’s — AArch64 outside Darwin widens nothing at all, Windows widens only &lt;code&gt;bool&lt;/code&gt;, and
RISC-V 64 widens a 32-bit value even when it is unsigned. As with the coercion above, none of it is
visible in a program; it is worth stating because it is the part of the boundary a reader is likeliest
to assume away.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;extern&lt;/code&gt; implies C’s convention and says nothing about any other.&lt;/strong&gt; The one case that needs
something else is a function the &lt;em&gt;processor&lt;/em&gt; enters rather than a caller, and that is a property of
a definition rather than of a foreign declaration — see &lt;code&gt;interrupt&lt;/code&gt;
below.&lt;/p&gt;
&lt;h3 id=&quot;several-externs-may-share-a-name&quot;&gt;Several &lt;code&gt;extern&lt;/code&gt;s may share a name&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Two &lt;code&gt;extern&lt;/code&gt;s of one name are two functions exactly when they name two symbols.&lt;/strong&gt; A C library’s
naming is not sysl’s, and a family C spells &lt;code&gt;_solid&lt;/code&gt;/&lt;code&gt;_shaded&lt;/code&gt;/&lt;code&gt;_blended&lt;/code&gt; is one operation with an
option — which a binding may say directly, rather than inventing a sysl name per C symbol:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strnlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, cap: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which one a call means is decided by its arguments, exactly as for any other
&lt;a href=&quot;/reference/declarations/#overloading&quot;&gt;overloaded name&lt;/a&gt;. Two declarations naming the &lt;strong&gt;same&lt;/strong&gt; symbol
are refused: that is one C function claimed at two signatures, and the symbol is what gets emitted,
so both calls would reach the same code with different arguments. Where that is genuinely wanted — a
&lt;code&gt;void *&lt;/code&gt; interface used at several types — it is written where a reader can see it, by taking the
address and casting it.&lt;/p&gt;
&lt;p&gt;An &lt;code&gt;extern&lt;/code&gt; and a sysl function do not overload each other, in either order: what tells overloads of
an &lt;code&gt;extern&lt;/code&gt; apart is the symbol each names, and a sysl function declares none.&lt;/p&gt;
&lt;h2 id=&quot;export-a-definition-c-can-call&quot;&gt;&lt;code&gt;@export&lt;/code&gt; — a definition C can call&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@export&lt;/code&gt; is &lt;code&gt;extern&lt;/code&gt; read the other way. An &lt;code&gt;extern&lt;/code&gt; names a symbol the linker has and states the
signature the other side published; an &lt;code&gt;@export&lt;/code&gt; publishes a symbol and states the signature C may
call it at. They are spelled alike because they are one mechanism pointing in two directions:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(code: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;never&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A sysl definition ordinarily carries its module path into its symbol, so two modules may each declare
an &lt;code&gt;init&lt;/code&gt; without colliding. &lt;code&gt;@export&lt;/code&gt; publishes a bare, unmangled name beside it — one a C
declaration can spell and a C linker can resolve.&lt;/p&gt;
&lt;h3 id=&quot;naming-the-symbol&quot;&gt;Naming the symbol&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@export(&amp;quot;mylib_add&amp;quot;)&lt;/code&gt; publishes it under that name instead, which is the same rename &lt;code&gt;extern&lt;/code&gt; offers
on the importing side:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mylib_add&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = a + b&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This is the form a real C API wants rather than a convenience.&lt;/strong&gt; A C library’s symbols share a
prefix so that linking two of them is not a coin toss, and the sysl side has a module path doing that
job already. &lt;code&gt;add&lt;/code&gt; is the name to write inside sysl and &lt;code&gt;mylib_add&lt;/code&gt; is the name to publish; requiring
the function to be &lt;em&gt;called&lt;/em&gt; &lt;code&gt;mylib_add&lt;/code&gt; everywhere inside would be spelling the module path twice.
&lt;strong&gt;A sysl caller is unaffected&lt;/strong&gt; — it goes on naming &lt;code&gt;mylib.add&lt;/code&gt;, and reaches the definition rather
than the published symbol.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@export&lt;/code&gt; implies C’s convention and says nothing about any other, which is &lt;code&gt;extern&lt;/code&gt;‘s rule read the
other way.&lt;/p&gt;
&lt;h3 id=&quot;the-published-symbol-is-an-entry-not-a-renamed-definition&quot;&gt;The published symbol is an entry, not a renamed definition&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A rename is not a convention&lt;/strong&gt;, and the difference is the whole of what &lt;code&gt;@export&lt;/code&gt; is for. The
exported symbol is a function of its own: its signature is what the machine’s C convention says, and
it reassembles each argument into the shape sysl’s own lowering expects before calling the
definition. The definition keeps its mangled name and its own lowering.&lt;/p&gt;
&lt;p&gt;None of that is anything to write, and it is worth knowing for three reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;an aggregate may cross&lt;/strong&gt;, which is the type rule below;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;f&lt;/code&gt; on an exported function is that entry’s address&lt;/strong&gt;, so a C library may be handed the callback
it asks for — which is what &lt;em&gt;A function’s address&lt;/em&gt; below turns on;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a sysl caller pays nothing for it&lt;/strong&gt;, since the conversion is only on the path C takes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is the foreign &lt;em&gt;call&lt;/em&gt; path read backwards: a call out to C classifies each argument by the
convention and puts it in the registers named, and an entry in classifies the same way and reads it
back. One classifier answers both directions, so what a binding calls and what it exports cannot
disagree about the same struct.&lt;/p&gt;
&lt;h3 id=&quot;what-an-exported-function-may-be&quot;&gt;What an exported function may be&lt;/h3&gt;
&lt;p&gt;The boundary is a &lt;strong&gt;facade&lt;/strong&gt;: one file whose job is the export surface, where the signatures are
written to be C-shaped on purpose. That is what makes the list below cost so little — every refusal
fires inside a file somebody wrote for this, where the restriction is the point rather than a
surprise.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;refused&lt;/th&gt;&lt;th&gt;because&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;generic&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;an exported symbol is one function at one signature, so there is no way to say which instantiation the linker holds&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;member&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;C has no receiver to hand it. The grammar refuses this before any rule here is reached, and says so in as many words: a member takes no annotation at all (&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt;), so &lt;code&gt;@test&lt;/code&gt; and &lt;code&gt;@pure&lt;/code&gt; are as unavailable on a method&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;&lt;code&gt;private&lt;/code&gt;&lt;/strong&gt; definition&lt;/td&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt; gives the symbol internal linkage, which promises every caller is inside the module; an export promises the opposite&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;&lt;code&gt;@ghost&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;it is erased before there is a symbol at all&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;&lt;code&gt;@test&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;only &lt;code&gt;sysl test&lt;/code&gt; builds one, and an export has to be in the artifact a C project links&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;variadic&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;what a C caller promotes into the tail is decided by the prototype it compiled against, not by this declaration. Take a &lt;code&gt;va_list&lt;/code&gt; parameter, which says the same thing and is what C’s own &lt;code&gt;v&lt;/code&gt; variants do&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a symbol that is not a &lt;strong&gt;C identifier&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;there would be nothing a C declaration could spell&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The types are the interesting rule, and it asks what C can &lt;em&gt;declare&lt;/em&gt;.&lt;/strong&gt; A scalar, a &lt;code&gt;*T&lt;/code&gt; and a
function pointer cross as themselves. So does a &lt;strong&gt;struct&lt;/strong&gt; built out of those, and a &lt;strong&gt;simple enum&lt;/strong&gt;,
which is its underlying integer and nothing else — the exported symbol is an entry lowered under the
machine’s C convention, so an aggregate is handed over where C looks for it.&lt;/p&gt;
&lt;p&gt;What is refused is what C has no declaration for whatever convention is applied: a slice or a
&lt;code&gt;string&lt;/code&gt;, which is two words with a length in the second; a &lt;code&gt;&amp;amp;T&lt;/code&gt; or a &lt;code&gt;weak&lt;/code&gt;, which is a counted box
whose header C would have to know the layout of; a trait object, which is a value and a method table
together; a data enum, which is a tag beside a union sysl laid out rather than the shape a C union
has; and a bare array as a parameter or result, which C decays to a pointer and has no by-value
prototype for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(xs: []&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;xs&apos; of the exported &apos;mylib.sum&apos; is []int, which C has no way to spell — an exported function takes an integer, a float, a &apos;bool&apos;, a &apos;char&apos;, a pointer, a function pointer, a simple enum, or a struct built out of those. A slice is an address and a length, so C takes them as two parameters — a pointer and a &apos;usize&apos; — which is the shape its own string and buffer functions already have
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An aggregate is asked about its fields&lt;/strong&gt;, which is what keeps those two lists apart: a struct of
scalars is a struct C declares, and a struct with a &lt;code&gt;&amp;amp;T&lt;/code&gt; in it is a counted box with a coat on. The
refusal names the &lt;em&gt;field&lt;/em&gt;, since the declaration being read does not mention it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    n: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = p.x&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;n&apos; of mylib.P is &amp;amp;mylib.Node, which is what C has no declaration for — the aggregate around it is fine
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recurring is also why nothing here says who owns what: every type reaching the boundary is plain
data, so no count crosses it in either direction.&lt;/p&gt;
&lt;p&gt;Every refusal names the shape to write instead, because there always is one — a slice becomes the
pointer and length C’s own buffer functions already take, an array becomes a struct holding it. That
is what makes the boundary writable rather than merely restricted.&lt;/p&gt;
&lt;h3 id=&quot;module-storage-a-c-caller-cannot-fill&quot;&gt;Module storage a C caller cannot fill&lt;/h3&gt;
&lt;p&gt;Module storage is filled before a program’s own statements run, and &lt;strong&gt;a C project supplies its own
&lt;code&gt;main&lt;/code&gt;&lt;/strong&gt; — so nothing sysl emitted runs before the C side calls in. An exported function that reached
storage a computed initializer would have written would read whatever the loader left, so it is
refused, and the walk is transitive:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; start: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;begin&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = start&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;mylib.begin&apos; is exported and reaches &apos;mylib.start&apos;, which is module storage an initializer fills before the program&apos;s own statements run. A C project linking this supplies its own &apos;main&apos;, so nothing fills it and the function would read whatever the loader left. A module &apos;val&apos; whose initializer is constant data is laid straight into the object file and is fine here — it is a computed one that has nowhere to be computed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;val&lt;/code&gt; whose initializer is constant data is fine&lt;/strong&gt;, because nothing runs to fill it — the
constant is written straight into the object file. That is the rule C already has for a
static-storage initializer, which is why this bites so rarely:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; start: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;begin&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;const&lt;/code&gt; has no storage at all and never arises.&lt;/p&gt;
&lt;h3 id=&quot;what-the-compiler-hands-the-c-project&quot;&gt;What the compiler hands the C project&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sysl build-c&lt;/code&gt; writes a &lt;strong&gt;static archive&lt;/strong&gt; and a &lt;strong&gt;C header&lt;/strong&gt; beside it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;$ sysl build-c mylib -o libmylib.a
wrote libmylib.a
wrote libmylib.a.h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The header is a translation of the exported signatures and holds no decisions of its own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;stdbool.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;stddef.h&amp;gt;

#ifdef __cplusplus
extern &amp;quot;C&amp;quot; {
#endif

int32_t mylib_add(int32_t a, int32_t b);

#ifdef __cplusplus
}
#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It uses &lt;code&gt;&amp;lt;stdint.h&amp;gt;&lt;/code&gt;‘s fixed-width names because sysl’s integers say what they &lt;em&gt;are&lt;/em&gt; where C’s say
what they are &lt;em&gt;at least&lt;/em&gt;: an &lt;code&gt;i32&lt;/code&gt; is &lt;code&gt;int32_t&lt;/code&gt;, and writing it &lt;code&gt;int&lt;/code&gt; would be right on every machine
anyone is likely to use and wrong as a claim. A &lt;code&gt;char&lt;/code&gt; is a Unicode scalar value and becomes
&lt;code&gt;uint32_t&lt;/code&gt;, never C’s &lt;code&gt;char&lt;/code&gt;, which would be wrong by a factor of four. The header assumes &lt;strong&gt;C99, or
any C++&lt;/strong&gt;, which is what those three includes already needed.&lt;/p&gt;
&lt;p&gt;The one fact a type name cannot carry across is divergence, since &lt;code&gt;never&lt;/code&gt; and &lt;code&gt;unit&lt;/code&gt; both spell as
&lt;code&gt;void&lt;/code&gt;. A function returning &lt;code&gt;never&lt;/code&gt; is therefore annotated:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#ifndef SYSL_NORETURN
#if defined(__cplusplus) &amp;amp;&amp;amp; __cplusplus &amp;gt;= 201103L
#define SYSL_NORETURN [[noreturn]]
#elif defined(__STDC_VERSION__) &amp;amp;&amp;amp; __STDC_VERSION__ &amp;gt;= 201112L
#define SYSL_NORETURN _Noreturn
#else
#define SYSL_NORETURN
#endif
#endif

SYSL_NORETURN void mylib_spin(void);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A macro rather than the keyword, because the header serves both languages and &lt;code&gt;_Noreturn&lt;/code&gt; is not
valid C++; an older compiler gets the empty definition, which is a weaker declaration rather than one
it refuses. The block appears only in a header that has something diverging in it. What it buys the
caller is real: code after the call is dead, and a path ending in it needs no return value.&lt;/p&gt;
&lt;h3 id=&quot;naming-a-struct-in-the-header&quot;&gt;Naming a struct in the header&lt;/h3&gt;
&lt;p&gt;A struct an exported signature reaches is &lt;strong&gt;defined&lt;/strong&gt; in the header as well as named, since a
prototype mentioning an &lt;code&gt;Id&lt;/code&gt; is useless to a consumer that has not been told what one is. Left alone
its name is derived from the module path — &lt;code&gt;mylib_Id&lt;/code&gt; here, and &lt;code&gt;sh_sysl_box2d_c_Id&lt;/code&gt; in a package —
which makes it the one name in the file nobody chose. &lt;code&gt;@export&lt;/code&gt; above the struct chooses it, exactly
as it names a function’s symbol:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mylib_vec2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mylib_add_vec&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(a.x + b.x, a.y + b.y)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.x, v.y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11 22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A sysl caller is unaffected by either name, exactly as it is by a function’s symbol — it goes on
writing &lt;code&gt;Vec2&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt;. What the two attributes decide is what the header says:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;typedef struct {
    int32_t x;
    int32_t y;
} mylib_vec2;

mylib_vec2 mylib_add_vec(mylib_vec2 a, mylib_vec2 b);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written bare, &lt;code&gt;@export&lt;/code&gt; gives the &lt;code&gt;typedef&lt;/code&gt; the &lt;strong&gt;declared&lt;/strong&gt; name — &lt;code&gt;Vec2&lt;/code&gt; — which is the reading it
already has on a function. It composes with &lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;@packed&lt;/code&gt; and &lt;code&gt;@align(n)&lt;/code&gt;&lt;/a&gt;,
which are three facts about one struct, and it is what a binding mirroring a C library wants: that
library’s own type names rather than tidier derived ones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The derived name was buying uniqueness and a chosen one is a claim&lt;/strong&gt;, so the claim is checked. Two
things in one header answering to one name are refused — and &lt;strong&gt;a function’s symbol counts&lt;/strong&gt;, because
at file scope C puts a &lt;code&gt;typedef&lt;/code&gt; name and a function name in one namespace where sysl has two:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;H&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;handle&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;make&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;H&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;H&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;handle&apos; is the C name of the function &apos;mylib.make&apos; and the type &apos;mylib.H&apos; — a header declares both in one namespace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;generic&lt;/strong&gt; struct is refused for the reason a generic function is, one step shorter: every
instantiation is a struct of its own, so one written name would be claimed by all of them at once.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Box&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a header names one type at one shape, so &apos;mylib.Box&apos; cannot be generic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;&lt;code&gt;private&lt;/code&gt;&lt;/strong&gt; struct is refused too, and not for the reason a private &lt;em&gt;definition&lt;/em&gt; is — a &lt;code&gt;typedef&lt;/code&gt;
has no linkage to contradict. The visibility rule gets there first: a public declaration may not name
a type less visible than itself and an export is public, so a private struct appears in no signature
a header carries and there is no name in one for it to take.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;mylib&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;mylib_id&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Id&lt;/span&gt;
    index1: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;mylib.Id&apos; is private, so no exported function may name it — an export is public
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The chosen name reaches the header and nothing else.&lt;/strong&gt; The emitted aggregate keeps its mangled
name, and C links nothing on a type name — which is what makes this a spelling an author may decide
rather than a fact anything else depends on.&lt;/p&gt;
&lt;p&gt;From there it is an ordinary C build:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;$ clang main.c libmylib.a -o app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The archive is self-contained.&lt;/strong&gt; Whatever of the standard library the module reaches is compiled
into it, because a &lt;code&gt;.syslib&lt;/code&gt; is not something a C link line can be handed — an archive referring to
one would fail at that link naming a &lt;code&gt;sysl$&lt;/code&gt; symbol its author has no way to place. So &lt;code&gt;--std-lib&lt;/code&gt; is
refused here and &lt;code&gt;--no-std-lib&lt;/code&gt; asks for what already happens. The cost, which is accepted: two
&lt;code&gt;build-c&lt;/code&gt; archives linked into one program each carry the part of the library they reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What the archive does not hold is what the sysl side’s own libraries supply&lt;/strong&gt; — &lt;code&gt;libm&lt;/code&gt;, and
whatever &lt;code&gt;@link&lt;/code&gt; named — and &lt;code&gt;build-c&lt;/code&gt; says which those are rather than leaving them to be found at
that link. Those are libraries the author chose and can hand to a linker, which is exactly the
distinction the standard module fails.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sysl emit-header&lt;/code&gt; prints the same declarations without building anything, for a project that
generates its headers as a build step.&lt;/p&gt;
&lt;h3 id=&quot;what-a-dependency-s-module-contributes&quot;&gt;What a dependency’s module contributes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A module a dependency supplied contributes to your build only where your program reaches that
module.&lt;/strong&gt; In your own tree the four attributes below mean what they say and nothing qualifies them:
each is a root of the reachability walk, which is what lets a &lt;code&gt;build-c&lt;/code&gt; compilation — with no entry
point at all — keep anything.&lt;/p&gt;
&lt;p&gt;A dependency is different because a package’s source root is compiled &lt;strong&gt;whole&lt;/strong&gt; rather than by what
you import, so every module of every &lt;code&gt;--lib&lt;/code&gt; root and every fetched package is in the compilation
whether or not you named it. For an ordinary declaration that costs nothing, since pruning drops what
no body reaches. &lt;strong&gt;These four are the declarations no body reaches&lt;/strong&gt;, so without this rule an
unimported module’s contribution landed in your build anyway:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;in a module you never reach&lt;/th&gt;&lt;th&gt;what it used to cost you&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;an &lt;code&gt;@export&lt;/code&gt;&lt;/td&gt;&lt;td&gt;its symbol in your archive&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an &lt;code&gt;interrupt&lt;/code&gt; handler&lt;/td&gt;&lt;td&gt;a handler in your vector table&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;@section&lt;/code&gt;&lt;/a&gt; definition&lt;/td&gt;&lt;td&gt;bytes in your image, marked so that nothing removes them&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt;&lt;/td&gt;&lt;td&gt;a function nothing can call&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The rule is about where the declaration came from rather than about which attribute it carries&lt;/strong&gt;,
and that is what makes it hold. A kind left unconditional would keep whatever &lt;em&gt;else&lt;/em&gt; the same
function carries — an export that is also placed, or that is also a handler, would survive for the
second reason and land its symbol anyway.&lt;/p&gt;
&lt;p&gt;What that cost was a package &lt;strong&gt;carrying its own program&lt;/strong&gt;. A binding whose tests have to run on real
hardware writes them as an application with an &lt;code&gt;@export(&amp;quot;main&amp;quot;)&lt;/code&gt;, and inside the package that handed
every consumer a second &lt;code&gt;main&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;$ nm -g probe.a
0000000000000008 T _main              &amp;lt;- yours
0000000000000000 T _main              &amp;lt;- the package&apos;s test application
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reaching is asked of the module graph, so an &lt;code&gt;import&lt;/code&gt; counts as readily as a call, and it follows the
graph out — a package you reach through another package is reached. It is deliberately coarser than
the walk over function bodies: a module holding nothing but an exported C entry point has no function
anything calls, and a rule asking whether you &lt;em&gt;called&lt;/em&gt; something there would drop exactly the case an
export exists for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If a package wants a symbol, a handler or a placed definition published regardless, it puts it in a
module its consumers import.&lt;/strong&gt; Each is a claim about what &lt;em&gt;your&lt;/em&gt; image contains, and an image that
never reaches the module has not asked for it. That reading is at its strongest where the attributes
matter most: a vector table slot and a RAM-resident &lt;code&gt;.ramfunc&lt;/code&gt; region are the scarcest things on the
parts they exist for, so gaining every unimported module’s silently is the worse way to be wrong.&lt;/p&gt;
&lt;h2 id=&quot;link-which-library-resolves-the-externs&quot;&gt;&lt;code&gt;@link&lt;/code&gt; — which library resolves the externs&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@link(&amp;quot;z&amp;quot;)&lt;/code&gt; in a file’s header names a library the linker must be given, and it sits beside the
&lt;code&gt;extern&lt;/code&gt;s it supports because that is the only place that knows. An &lt;code&gt;extern&lt;/code&gt; states the symbol it
wants and never where the symbol lives; a binding to &lt;code&gt;libpng&lt;/code&gt; is written by whoever writes the
module, and the driver cannot carry a list of libraries it has never heard of.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;image&lt;/span&gt;.png
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;png&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;link&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;z&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;png_create_read_struct&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;create&lt;/span&gt;(ver: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, err: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, fn: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A directive names a library, and never a flag.&lt;/strong&gt; That is the whole of the design. Where a library
&lt;em&gt;lives&lt;/em&gt; is a property of the machine being built for: the mathematics is a file of its own on ELF,
part of &lt;code&gt;libSystem&lt;/code&gt; on Darwin, inside the CRT on Windows, and absent from a freestanding target that
has no libc for it to be in. A directive spelling &lt;code&gt;-lm&lt;/code&gt; would be right on one of those and wrong on
the other three — and the author could not be told so by any compiler running on the machine that
wrote it, because the link that fails is somewhere else. So the file names &lt;code&gt;m&lt;/code&gt;, and the driver
decides what that becomes:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;the target&lt;/th&gt;&lt;th&gt;what a name becomes&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;has the library separately&lt;/td&gt;&lt;td&gt;&lt;code&gt;-lname&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the ordinary case, and what every unrecognized name gets&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;already links what holds it&lt;/td&gt;&lt;td&gt;nothing&lt;/td&gt;&lt;td&gt;Darwin’s &lt;code&gt;libSystem&lt;/code&gt;, Windows’ CRT — the driver passes those unasked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;does not have it at all&lt;/td&gt;&lt;td&gt;nothing&lt;/td&gt;&lt;td&gt;a freestanding build has no libc, so nothing can be passed for one&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last two both put nothing on the command line and are still written apart, because they are
different facts and a target added to the registry has to answer them separately. A freestanding
program that then calls &lt;code&gt;sqrt&lt;/code&gt; fails at the link naming &lt;code&gt;sqrt&lt;/code&gt;, which is the honest report: what is
missing is the function, and no &lt;code&gt;-l&lt;/code&gt; would have supplied it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The set the compiler knows is deliberately small&lt;/strong&gt; — the C runtime and the mathematics, the two
whose placement actually differs. An unrecognized name is passed straight through rather than
guessed about. Being wrong in that direction produces a link error naming the &lt;em&gt;library&lt;/em&gt;; being wrong
in the other produces one naming a &lt;em&gt;function&lt;/em&gt;, on a platform the author does not have.&lt;/p&gt;
&lt;p&gt;Four more rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The requirement travels in the artifact.&lt;/strong&gt; The clauses are part of the tree a &lt;code&gt;.syslib&lt;/code&gt; carries,
so a program depending on a prebuilt library learns to pass &lt;code&gt;-lz&lt;/code&gt; without reading that library’s
source. Leaving them out would mean a binding that works from source and stops working the moment
it ships — the worst available shape, since the build that breaks is one its author never ran.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A module’s requirement is the union of its files’, and its files are not held to agreeing.&lt;/strong&gt;
This is where the directive differs from a &lt;a href=&quot;/reference/modules/&quot;&gt;capability clause&lt;/a&gt;, which it is
otherwise shaped like: a capability describes what the whole module may do, so files that
disagreed would be describing different modules, where a link requirement describes what &lt;em&gt;one
file’s&lt;/em&gt; externs need.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Order is kept rather than sorted.&lt;/strong&gt; A static archive is scanned once, left to right, and a
member is pulled in only to resolve a symbol already undefined — so a library that calls into
another has to come first: &lt;code&gt;-lpng -lz&lt;/code&gt;, never the reverse. Sorting would decide it by spelling,
which is right by accident for those two and wrong for the next pair.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;@link&lt;/code&gt; is an annotation, not grammar&lt;/strong&gt; — so &lt;code&gt;link&lt;/code&gt; is an ordinary identifier and a program may
still declare a function or a field called it. That is the general rule for everything the file
header carries: an annotation’s name is read as an identifier, which is what keeps &lt;code&gt;alloc&lt;/code&gt;, &lt;code&gt;no&lt;/code&gt;,
&lt;code&gt;requires&lt;/code&gt; and &lt;code&gt;link&lt;/code&gt; out of the reserved list. See &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;where-the-library-is-where-its-headers-are-and-what-they-are-configured-with&quot;&gt;Where the library is, where its headers are, and what they are configured with&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@link&lt;/code&gt; says &lt;em&gt;which&lt;/em&gt; library. Where it lives on a particular machine is not the module’s to know, and
neither is what the surrounding project builds its headers with, so those are three flags on the
command line rather than three more directives:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-path &amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;where to look for a header the C beside a module includes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-path &amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same, and it answers the header requirement a package declared under that name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-D NAME&lt;/code&gt; or &lt;code&gt;-D NAME=value&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a macro that C is compiled with&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--link-path &amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;where to look for the library &lt;code&gt;@link&lt;/code&gt; named&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;They fail in that order, and the first two fail &lt;em&gt;before&lt;/em&gt; anything reaches a linker. A binding to a
library a package manager put outside the toolchain’s prefix needs the paths; a module joining an
existing C project — an SDK, a firmware build — needs the macros as well, because a header found is
not a header that compiles. pico-sdk’s &lt;code&gt;pico/cyw43_arch.h&lt;/code&gt; &lt;code&gt;#error&lt;/code&gt;s on a build that has not said
which architecture variant it means, which is the shape to expect rather than a curiosity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing is guessed at.&lt;/strong&gt; sysl does not add &lt;code&gt;/opt/homebrew/lib&lt;/code&gt; and does not invent a macro: a
compiler ruling on where a platform keeps its libraries, or on how a project configures its headers,
would be wrong on a machine its author cannot reach, and the cost of being wrong is a build that
fails somewhere else. A build system that already knows these has them — from CMake, the target’s
&lt;code&gt;INCLUDE_DIRECTORIES&lt;/code&gt; and &lt;code&gt;COMPILE_DEFINITIONS&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A package may say which headers it needs, though never where they are.&lt;/strong&gt; A &lt;code&gt;--include-path&lt;/code&gt; written
as &lt;code&gt;&amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt; answers a requirement the package declared under that name, so a build missing one
stops before clang runs and names the package rather than a header the reader has never heard of. The
declaration goes in &lt;code&gt;package.hocon&lt;/code&gt; — see
&lt;a href=&quot;/reference/packages/#headers-a-package-needs-and-does-not-carry&quot;&gt;packages&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;a-function-s-address-extern-a-b-r&quot;&gt;A function’s address — &lt;code&gt;*extern(A, B) -&amp;gt; R&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/reference/expressions/&quot;&gt;&lt;code&gt;Fn&lt;/code&gt;&lt;/a&gt; is sysl’s answer to “what is the type of a callable”, and it is the
right one for sysl: a bound where the callable is passed down, a boxed object where it is kept, and
in both cases something with an environment beside it. &lt;strong&gt;C has no notion of an environment.&lt;/strong&gt; What a
C interface means by a function pointer is one word holding the address of code.&lt;/p&gt;
&lt;p&gt;That matters for more than a corner: &lt;code&gt;qsort&lt;/code&gt; and &lt;code&gt;bsearch&lt;/code&gt; take a comparison, &lt;code&gt;signal&lt;/code&gt; and
&lt;code&gt;sigaction&lt;/code&gt; take a handler, &lt;code&gt;atexit&lt;/code&gt; takes a hook, &lt;code&gt;pthread_create&lt;/code&gt; takes a thread body, &lt;code&gt;scandir&lt;/code&gt;
takes a filter, and every library with a &lt;code&gt;_set_callback&lt;/code&gt; in it takes one of these.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(base: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, size: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, cmp: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;compare&lt;/span&gt;(a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pa: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(a)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pb: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(b)

    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;pa - &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;pb

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]), &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;compare)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 20 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;f&lt;/code&gt; is the address&lt;/strong&gt;, and the &lt;code&gt;&amp;amp;&lt;/code&gt; is the same one the &lt;a href=&quot;/reference/memory/&quot;&gt;memory model&lt;/a&gt; gives
every other address. A bare &lt;code&gt;f&lt;/code&gt; keeps its ordinary meaning — the capture-free closure — because a
spelling that meant a sysl callable in one slot and a C address in another would be choosing
silently between two representations that share nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The function may be named through its module&lt;/strong&gt;, and &lt;code&gt;&amp;amp;f[T]&lt;/code&gt; may be qualified too. Under
&lt;code&gt;import shapes&lt;/code&gt;, &lt;code&gt;&amp;amp;shapes.less&lt;/code&gt; is the same address &lt;code&gt;&amp;amp;less&lt;/code&gt; gives under &lt;code&gt;import shapes.less&lt;/code&gt; — a name
means the &lt;em&gt;declaration&lt;/em&gt; rather than a spelling of it, which is the rule a
&lt;a href=&quot;/reference/declarations/&quot;&gt;constant&lt;/a&gt; follows as well. A &lt;strong&gt;local binding shadows a module name&lt;/strong&gt;, so
where the head of the path is bound to a value the chain is an ordinary field read and the &lt;code&gt;&amp;amp;&lt;/code&gt;
addresses that field.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is its own type rather than a mode over the call trait.&lt;/strong&gt; &lt;code&gt;*Fn(A) -&amp;gt; R&lt;/code&gt; was already taken, and
by the right thing: an unowned trait object over a callable, two words, a method table beside the
value. Spelling both the same would put a fat pointer where C reads one word, and the mistake would
be invisible. So the three are three:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;th&gt;width&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;A -&amp;gt; R&lt;/code&gt; at a parameter&lt;/td&gt;&lt;td&gt;a bound over &lt;code&gt;Fn&lt;/code&gt;, monomorphized and inlined&lt;/td&gt;&lt;td&gt;nothing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;Fn(A) -&amp;gt; R&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a heap-boxed callable, counted&lt;/td&gt;&lt;td&gt;two words&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*extern(A) -&amp;gt; R&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the address of code compiled to C’s convention&lt;/td&gt;&lt;td&gt;one word&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It is also &lt;strong&gt;not &lt;code&gt;*T&lt;/code&gt; of anything&lt;/strong&gt;. A raw pointer addresses a &lt;em&gt;value&lt;/em&gt; — one that can be read
through, written through, and measured — and there is no value at the end of this one, so every
operation &lt;code&gt;*T&lt;/code&gt; carries would have needed an exception. What an address of code can do is the one
thing it is for: be called, and be handed to whoever asked for it.&lt;/p&gt;
&lt;p&gt;Three consequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A call through one goes out under C’s convention&lt;/strong&gt;, because that is what the type said was at
the other end. Nothing checks that the signature is the one the code at that address was compiled
with; that is the promise the &lt;code&gt;*&lt;/code&gt; announces, and it is the same promise every raw pointer makes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ptr_cast&lt;/code&gt; reaches between an address of code and an address of bytes&lt;/strong&gt;, which is how a &lt;code&gt;*u8&lt;/code&gt;
from &lt;code&gt;dlsym&lt;/code&gt; becomes callable and how one goes back to a C interface that stores callbacks as
&lt;code&gt;void *&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;null&lt;/code&gt; is a &lt;code&gt;*extern&lt;/code&gt;&lt;/strong&gt;, since “there is no callback, use the default” is a state several C
interfaces have, and two compare by address so a program can ask whether one is installed:&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;compare&lt;/span&gt;(a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; installed: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(installed == &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;compare == &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-generic-function-s-address-the-instantiation-is-read-off-the-type&quot;&gt;A generic function’s address — the instantiation is read off the type&lt;/h3&gt;
&lt;p&gt;A generic function is a body per set of type arguments, so an address needs them settled. &lt;strong&gt;The
expected type settles them&lt;/strong&gt;, by the same unification a call site uses on its arguments:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(base: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, size: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, cmp: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;ascending&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pa: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(a)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; pb: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(b)
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;pa - &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;pb

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]), &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;ascending)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 20 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A comparison written once over &lt;code&gt;*T&lt;/code&gt; is now usable at every element type, where before a program
needed a concrete copy of it per type.&lt;/p&gt;
&lt;h3 id=&quot;the-void-userdata-pattern-the-arguments-are-written&quot;&gt;The &lt;code&gt;void *userdata&lt;/code&gt; pattern — the arguments are written&lt;/h3&gt;
&lt;p&gt;A C interface that calls back pairs the pointer with an untyped &lt;code&gt;void *&lt;/code&gt;, so a trampoline for one has
the signature C fixed — &lt;code&gt;(*u8, Event) -&amp;gt; bool&lt;/code&gt;. The state type appears nowhere in it, so nothing in
the expected type can settle it, and no annotation written anywhere else could supply it either. The
arguments are written where the address is taken, and &lt;strong&gt;this is the one position in the language that
takes them&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(base: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, size: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, cmp: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;compare&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt;](a: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, b: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(a)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; y: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(b)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;x &amp;lt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;y &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;y &amp;lt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;x &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;qsort&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]), &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;compare[&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 20 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recovering the state is still a &lt;code&gt;ptr_cast&lt;/code&gt; from &lt;code&gt;*u8&lt;/code&gt;, which is a promise rather than a deduction —
that is C’s shape and nothing here changes it. What is no longer needed is the shape the &lt;em&gt;language&lt;/em&gt;
was forcing: a trampoline written over &lt;code&gt;*T&lt;/code&gt; because it could not be written over &lt;code&gt;*u8&lt;/code&gt;, a second
&lt;code&gt;ptr_cast&lt;/code&gt; of the function pointer, and a &lt;code&gt;val&lt;/code&gt; whose only job was to be somewhere to put the type.
&lt;a href=&quot;/guides/qsort/&quot;&gt;qsort&lt;/a&gt; is written the new way.&lt;/p&gt;
&lt;p&gt;More than one argument is written the same way, &lt;code&gt;&amp;amp;f[A, B]&lt;/code&gt;, and a value parameter takes its place in
the list like any other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;amp;f[T]&lt;/code&gt; and &lt;code&gt;&amp;amp;xs[i]&lt;/code&gt; are the same shape, and the analyzer is what separates them&lt;/strong&gt;: the name has to
resolve to a function declaration with no local shadowing it. A local shadowing the name keeps the
ordinary indexed reading, so a subscript is never re-read as a feature its author did not reach for.&lt;/p&gt;
&lt;p&gt;What the brackets can hold is the &lt;em&gt;expression&lt;/em&gt; grammar’s reading of a type — a name, a qualified
name, a name applied to arguments, &lt;code&gt;*T&lt;/code&gt;, &lt;code&gt;&amp;amp;T&lt;/code&gt;, a tuple, and an integer for a value parameter. A
slice, a &lt;code&gt;weak&lt;/code&gt;, a &lt;code&gt;volatile&lt;/code&gt; and a callable have no spelling there; the annotated &lt;code&gt;val&lt;/code&gt; reaches
every one of them, and the diagnostic says so.&lt;/p&gt;
&lt;h3 id=&quot;what-has-no-address-and-why&quot;&gt;What has no address, and why&lt;/h3&gt;
&lt;p&gt;Each of these is refused because the address would not be an address of what its type says, and
nothing downstream could notice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A generic function with nothing to say which copy&lt;/strong&gt; — the arguments have to come from somewhere,
and a bare &lt;code&gt;var&lt;/code&gt; says nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;id&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = x

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;id

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;nothing here says what they are
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A type parameter the signature never mentions, left to be inferred&lt;/strong&gt; — nothing in the expected type
can settle it, and the message names the form that can:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;tagged&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](n: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = n

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; f: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;tagged

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;does not say what &apos;T&apos; should be
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written out, &lt;code&gt;&amp;amp;tagged[i32]&lt;/code&gt;, it is an ordinary address — that is the case the written form exists
for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A variadic function&lt;/strong&gt; — C reads a tail relative to the last named argument, and a &lt;code&gt;*extern&lt;/code&gt; states
the arguments a call passes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;varia&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;varia

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;varia&apos; is variadic, and a &apos;*extern&apos; fixes the arguments a call passes — a tail has no width a signature could state, so a variadic function is reached by calling it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A nested function&lt;/strong&gt; — its environment is the frame it was declared in, and what would have to
travel beside the address is that frame. &lt;strong&gt;A closure&lt;/strong&gt; is the same reason with the name taken off. A
&lt;strong&gt;&lt;code&gt;@test&lt;/code&gt; function&lt;/strong&gt; is dropped by every build but &lt;code&gt;sysl test&lt;/code&gt;, so its address would be of a
definition the program does not have:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;outer&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;inner&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = x + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;inner

    &lt;span class=&quot;hl-function&quot;&gt;inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;outer&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;inner&apos; is a nested function, so it has no address to take — what would have to travel beside the address is the frame it reads, and a &apos;*extern&apos; is one word. A top-level function is what has an address
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An intrinsic&lt;/strong&gt; — there is no body for an address to name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;llvm.sqrt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;root&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;root

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;root&apos; is an intrinsic, which the back end lowers to an instruction rather than a function anything calls — there is no body for an address to name. A sysl function that calls it is what has one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A plain sysl function whose signature carries an aggregate&lt;/strong&gt; — a struct, a tuple, a data enum, a
view, a &lt;code&gt;string&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;agg&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = p.a

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;agg

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the 1st parameter of &apos;agg&apos; is Pair, an aggregate, and an aggregate crosses to C in whichever registers that machine&apos;s convention names rather than the ones a sysl call uses
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The test is made by &lt;strong&gt;shape&lt;/strong&gt; rather than by asking the target’s classification, so a program
accepted for one machine is accepted for every machine.&lt;/p&gt;
&lt;h3 id=&quot;two-kinds-of-function-are-past-the-aggregate-question&quot;&gt;Two kinds of function are past the aggregate question&lt;/h3&gt;
&lt;p&gt;They were once refused by it, and that cost a binding every callback a C library asks it to register
— those signatures are written in aggregates almost without exception.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;extern&lt;/code&gt; is C.&lt;/strong&gt; sysl neither compiled it nor chose its convention, and its type is what the
declaration transcribed from the header, so there is no lowering here to be wrong about:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;c_sum&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_sum&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;c_take&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_take&lt;/span&gt;(f: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;c_take&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;c_sum))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A function carrying &lt;code&gt;@export&lt;/code&gt; has a C-convention entry&lt;/strong&gt;, and its address is that entry’s. So the
answer to the refusal above is to mark the function rather than to hand-write a wrapper around it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;export&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;c_sum&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = p.a + p.b

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;c_take&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_take&lt;/span&gt;(f: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;c_take&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sum))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A plain sysl function is what is left, and there the refusal stands: it has no C-convention entry to
point at, and an address that is quietly wrong is worse than no address.&lt;/p&gt;
&lt;h3 id=&quot;what-it-costs-today&quot;&gt;What it costs today&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A signature cannot be named once.&lt;/strong&gt; Every declaration mentioning a callback spells the whole of
it, and a real binding mentions one several times — &lt;code&gt;signal&lt;/code&gt; takes a handler and returns the
previous one, so its declaration says the same eight tokens twice. This is not the foreign
interface’s restriction: &lt;code&gt;type&lt;/code&gt; declares a
&lt;a href=&quot;/reference/errors/&quot;&gt;constrained subtype&lt;/a&gt;, whose base must be a scalar, so a name
for a pointer type is refused in the same words:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a constrained subtype&apos;s base must be an integer, a float, or &apos;char&apos;, not *byte
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What would fix it is an alias that is not a subtype.&lt;/p&gt;
&lt;h2 id=&quot;variadic-functions&quot;&gt;Variadic functions&lt;/h2&gt;
&lt;p&gt;C’s ellipsis is the one arity in the language a declaration does not fix, and it exists for one
reason: &lt;code&gt;printf&lt;/code&gt;, &lt;code&gt;snprintf&lt;/code&gt;, &lt;code&gt;execl&lt;/code&gt;, &lt;code&gt;open&lt;/code&gt; — the calls every C library reserves for a variable
tail — cannot be declared at all without it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;printf&lt;/span&gt;(fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;snprintf&lt;/span&gt;(buf: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A sysl function may have one too&lt;/strong&gt;, and the rules for what may go in the tail are shared, so a
caller need not know whether the callee it is reaching is foreign:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;va_start&lt;/span&gt;(ap)

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += &lt;span class=&quot;hl-function&quot;&gt;va_arg&lt;/span&gt;(ap)

    &lt;span class=&quot;hl-function&quot;&gt;va_end&lt;/span&gt;(ap)

    total

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;60
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why it is here at all.&lt;/strong&gt; C can do this, so sysl must: a capability C has and sysl lacks is a place
sysl cannot be used, and sysl exists to be used where C is. The concrete cases are the ones every C
codebase has — a logging or formatting function whose arity is the caller’s business, and a function
that must be &lt;em&gt;callable from&lt;/em&gt; C at a variadic signature, or hand a tail onward to one.&lt;/p&gt;
&lt;h3 id=&quot;the-calling-side&quot;&gt;The calling side&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The ellipsis follows the named parameters, and there must be at least one&lt;/strong&gt;, because C reads a
variadic call’s tail relative to the last named argument. &lt;code&gt;f(...)&lt;/code&gt; is not a callable declaration in
any C either:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;nothing&lt;/span&gt;(...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;nothing&apos; needs at least one named parameter before &apos;...&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A call is checked against the declared parameters exactly as any other call is — the ellipsis
excuses nothing that comes before it, arity included, and the escape analysis still assumes the
callee keeps every argument. What the ellipsis governs is only what follows:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only what C varargs can carry may go in the tail&lt;/strong&gt; — an integer, a float, a &lt;code&gt;char&lt;/code&gt;, or a raw
pointer. What is refused there and not at a declared parameter is a &lt;code&gt;bool&lt;/code&gt;: C would promote it to
&lt;code&gt;int&lt;/code&gt;, and sysl has no conversion that says so, so there is nothing to promote it &lt;em&gt;with&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;printf&lt;/span&gt;(fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;printf&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a bool cannot be passed to &apos;...&apos; — a variadic argument must be an integer, a float, a char, or a raw pointer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A tail argument is passed already widened&lt;/strong&gt;, by C’s default argument promotions: an integer
narrower than 32 bits becomes &lt;code&gt;i32&lt;/code&gt; or &lt;code&gt;u32&lt;/code&gt; following its own signedness, and an &lt;code&gt;f16&lt;/code&gt; or &lt;code&gt;f32&lt;/code&gt;
becomes &lt;code&gt;f64&lt;/code&gt;. This is not something the ABI can be left to do — LLVM promotes nothing on its own,
and a narrow value handed over as written is read back out of the wrong number of bytes. The
widening is part of the call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An aggregate is the one place a sysl tail is narrower than a foreign one.&lt;/strong&gt; A struct, an enum, a
tuple or a view crosses to a &lt;em&gt;foreign&lt;/em&gt; callee under exactly the classification a declared parameter
of that type gets, which is what C does with one as well. It does not cross to a &lt;em&gt;sysl&lt;/em&gt; one, because
there it is the callee’s own walk that reads the tail back, and the walk reads one register at a
time:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a Pair cannot be passed to a sysl function&apos;s &apos;...&apos; — a walk over the tail reads back one register at a time and an aggregate is not one, where a foreign callee takes it because C says which registers it arrives in
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The refusal says which callee it is about rather than calling the argument unsuitable, since the
same argument is fine one call away.&lt;/p&gt;
&lt;h3 id=&quot;the-receiving-side-c-s-spelled-sysl-s-way&quot;&gt;The receiving side — C’s, spelled sysl’s way&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_list&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;predeclared type&lt;/strong&gt;, like &lt;code&gt;int&lt;/code&gt; and &lt;code&gt;never&lt;/code&gt; — not a struct a program could have written, because its layout is the target ABI’s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_start(ap)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;readies it. C also names the last fixed parameter here; sysl does not, because the function already knows which parameter that is and repeating it is a chance to get it wrong&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_arg(ap)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;takes the next argument and advances&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_end(ap)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;finishes with it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;va_copy(dst, src)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;starts &lt;code&gt;dst&lt;/code&gt; where &lt;code&gt;src&lt;/code&gt; has reached, so a tail can be walked twice&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These five are &lt;strong&gt;language forms, not library functions&lt;/strong&gt;, in the same category as &lt;code&gt;sizeof&lt;/code&gt;: each is
an ABI primitive that no sysl body could implement, so there is nothing to put in the library. That
is the line the “no functions built into the compiler” rule actually draws — no program could write
&lt;code&gt;va_arg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;va_arg&lt;/code&gt; reads its type from context, or from the brackets.&lt;/strong&gt; C writes the type as a second
argument, which is not a thing a sysl expression can hold; here it comes from the place the value is
read into — &lt;code&gt;var v: int = va_arg(ap)&lt;/code&gt;, &lt;code&gt;total += va_arg(ap)&lt;/code&gt;, &lt;code&gt;take(va_arg(ap))&lt;/code&gt; — the same place
&lt;code&gt;None&lt;/code&gt; and &lt;code&gt;Ok(5)&lt;/code&gt; get theirs. Where a reader would rather say it at the form, &lt;code&gt;va_arg[int](ap)&lt;/code&gt; is
&lt;a href=&quot;/reference/generics/&quot;&gt;the written type-argument list&lt;/a&gt; at a special form, and it is what a bare
&lt;code&gt;print(va_arg[int](ap))&lt;/code&gt; needs. Where neither says, the form is refused rather than guessed at:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;walk&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;va_start&lt;/span&gt;(ap)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;va_arg&lt;/span&gt;(ap))

    &lt;span class=&quot;hl-function&quot;&gt;va_end&lt;/span&gt;(ap)

    n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;walk&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;va_arg&apos; reads the next argument as some type, and nothing here says which — annotate the variable it is read into
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;handing-a-walk-on&quot;&gt;Handing a walk on&lt;/h3&gt;
&lt;p&gt;C’s other half of this is &lt;code&gt;vprintf&lt;/code&gt;: a function receives the tail, does not read it itself, and
passes it to somebody who does. The parameter type is &lt;strong&gt;&lt;code&gt;*va_list&lt;/code&gt;&lt;/strong&gt;, and the call writes &lt;code&gt;&amp;amp;ap&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;report&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ap: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += &lt;span class=&quot;hl-function&quot;&gt;va_arg&lt;/span&gt;(ap)

    total

&lt;span class=&quot;hl-function&quot;&gt;relay&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;va_start&lt;/span&gt;(ap)

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-function&quot;&gt;report&lt;/span&gt;(n, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;ap)

    &lt;span class=&quot;hl-function&quot;&gt;va_end&lt;/span&gt;(ap)

    t

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;relay&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A bare &lt;code&gt;va_list&lt;/code&gt; parameter is refused&lt;/strong&gt;, and the by-value parameter rule is why — a copy of a walk
is not a walk:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;borrow&lt;/span&gt;(ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;borrow&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a va_list is a parameter as &apos;*va_list&apos;, not as &apos;va_list&apos; — a parameter is a by-value binding, and a copy of a walk advances nothing &apos;borrow&apos;&apos;s caller can see, so the walk is handed over by address and the call writes &apos;&amp;amp;ap&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things follow, and both are the point. The borrower &lt;strong&gt;advances the lender’s own list&lt;/strong&gt;, so what
it consumed is gone when the lender reads on — which is what &lt;code&gt;va_copy&lt;/code&gt; is for, exactly as in C. And
&lt;code&gt;va_start&lt;/code&gt; still asks for a tail of the function’s own while &lt;code&gt;va_arg&lt;/code&gt; asks only for a walk, so a
borrower reads a tail without having one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Returning a &lt;code&gt;va_list&lt;/code&gt; is refused outright&lt;/strong&gt;, foreign or not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;give&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;

    ap

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a va_list cannot be returned from &apos;give&apos; — the type names the storage a walk lives in, and there is no value of it to hand back
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;*va_list&lt;/code&gt; is an ordinary raw pointer and is refused nowhere — it may be returned, held in a
field, or carried in a struct, under the memory model’s rules and nobody else’s.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;extern&lt;/code&gt; is written in C’s spellings and takes either.&lt;/strong&gt; A foreign declaration transcribes a C
header, so it says what the header says: &lt;code&gt;va_list&lt;/code&gt; is C’s by-value parameter, the one &lt;code&gt;vprintf&lt;/code&gt;
takes, and &lt;code&gt;*va_list&lt;/code&gt; is C’s &lt;code&gt;va_list *&lt;/code&gt;. The refusal above is about a &lt;em&gt;sysl&lt;/em&gt; body, which could do
nothing with a copy of a walk; a foreign body is C’s, and C’s &lt;code&gt;vprintf&lt;/code&gt; is precisely a body that
reads one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;vprintf&lt;/span&gt;(fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(fmt: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, ...) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ap: &lt;span class=&quot;hl-type&quot;&gt;va_list&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;va_start&lt;/span&gt;(ap)

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-function&quot;&gt;vprintf&lt;/span&gt;(fmt, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;ap)

    &lt;span class=&quot;hl-function&quot;&gt;va_end&lt;/span&gt;(ap)

    n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The call writes &lt;code&gt;&amp;amp;ap&lt;/code&gt; for either spelling&lt;/strong&gt;, because the address is the only thing sysl has and it
is what both are formed from. What actually crosses for the by-value one is a &lt;em&gt;target&lt;/em&gt; question:
C’s &lt;code&gt;va_list&lt;/code&gt; is a different type on every machine and is passed three different ways — the value in
the storage on Darwin arm64, the storage’s own address on x86-64 System V, the address of a fresh
copy on AAPCS64. All three pass one pointer, so the difference cannot be recovered from the emitted
types; the compiler reads it off the target it was told to build for.&lt;/p&gt;
&lt;h3 id=&quot;where-an-ellipsis-may-go&quot;&gt;Where an ellipsis may go&lt;/h3&gt;
&lt;p&gt;A member is a function with a receiver in front, so a &lt;code&gt;...&lt;/code&gt; reaches one under exactly these rules.
The receiver is a parameter once the member is lowered, and it is therefore what a tail anchors on —
so &lt;code&gt;only(self, ...)&lt;/code&gt; is a complete declaration, while a receiverless &lt;code&gt;make(...)&lt;/code&gt; has nothing named
before its ellipsis and is refused exactly as &lt;code&gt;f(...)&lt;/code&gt; is. The same holds for an associated function,
a member of a generic type, a member with type parameters of its own, and a &lt;strong&gt;nested function&lt;/strong&gt;,
whose environment holds the first parameter slot the way a receiver does.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;trait&lt;/strong&gt; may declare one, and an implementation must agree about it: a &lt;code&gt;...&lt;/code&gt; is part of what a
caller may write, so having one where the trait has none is a different promise rather than a wider
one. What such a trait cannot be is a &lt;a href=&quot;/reference/traits/&quot;&gt;&lt;strong&gt;trait object&lt;/strong&gt;&lt;/a&gt;. A call to a variadic
names the callee’s whole function type — that is how it says where the declared parameters stop —
and a slot in a method table is a word that names none. A bound still reaches the method, because
that call knows which function it is reaching.&lt;/p&gt;
&lt;h3 id=&quot;it-is-as-unsafe-as-c-s&quot;&gt;It is as unsafe as C’s&lt;/h3&gt;
&lt;p&gt;Nothing checks that the callee asks for the types the caller passed, or that it stops at the right
count; &lt;code&gt;va_arg&lt;/code&gt; past the end reads whatever is there. The tail carries no type information, so there
is nothing to check against. &lt;strong&gt;This is the one place in sysl where getting it wrong is
undiagnosed&lt;/strong&gt; — which is why a &lt;em&gt;safe&lt;/em&gt; variadic (a homogeneous &lt;code&gt;...T&lt;/code&gt; collected into a slice, or a
heterogeneous &lt;code&gt;...&amp;amp;Show&lt;/code&gt; over trait objects) is worth adding beside it later, never instead of it.&lt;/p&gt;
&lt;h2 id=&quot;opaque-withholding-a-layout&quot;&gt;&lt;code&gt;opaque&lt;/code&gt; — withholding a layout&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;opaque struct Name&lt;/code&gt; is known by shape only inside the module that declares it. Everywhere else the
type is &lt;strong&gt;incomplete&lt;/strong&gt; — exactly what C’s &lt;code&gt;struct foo;&lt;/code&gt; is — and the only thing that may be said
about it is &lt;code&gt;*Name&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;net&lt;/span&gt;

opaque &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;
    fd: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    live: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;open&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(c: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Conn&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One rule, because two different wants meet in it.&lt;/strong&gt; A library stabilizing its surface wants to add
and reorder fields with nothing downstream recompiled. A binding wants &lt;code&gt;*sqlite3&lt;/code&gt; to be a type a
&lt;code&gt;*u8&lt;/code&gt; cannot be mistaken for, where nobody in sysl knows the layout at all. Both are “the shape is
not yours to know”.&lt;/p&gt;
&lt;p&gt;So an opaque struct may declare &lt;strong&gt;no body at all&lt;/strong&gt;, which is the C-handle case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

opaque &lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Dir&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;opendir&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_opendir&lt;/span&gt;(path: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Dir&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;closedir&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_closedir&lt;/span&gt;(d: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Dir&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-function&quot;&gt;c_opendir&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/tmp&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).ptr)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;c_closedir&lt;/span&gt;(d))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in sysl lays a &lt;code&gt;Dir&lt;/code&gt; out; the storage is libc’s. An &lt;em&gt;ordinary&lt;/em&gt; struct with no body stays an
error, and says which word to add.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What is refused outside the declaring module is one list&lt;/strong&gt;: a binding, a field of another type, an
element, an array, a slice, a &lt;code&gt;&amp;amp;&lt;/code&gt;, a type argument, a by-value parameter or result, construction,
reading or writing a field, a pattern naming the fields, a dereference, &lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt;,
&lt;code&gt;offsetof&lt;/code&gt;, and a by-value &lt;code&gt;self&lt;/code&gt; method. Every one of them needs a size or an offset, which is the
single fact being withheld, so they are one diagnostic rather than fifteen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The by-value &lt;code&gt;self&lt;/code&gt; method is the case worth stating outright&lt;/strong&gt;, because it looks like a call and
is not. The &lt;em&gt;function&lt;/em&gt; was compiled by the library; what crosses the boundary is the &lt;strong&gt;caller’s
copy&lt;/strong&gt;, laid out to the fields as they stood when that caller was built. Adding a field would then
break it silently — precisely the failure the modifier exists to prevent. &lt;code&gt;*self&lt;/code&gt; and &lt;code&gt;&amp;amp;self&lt;/code&gt; need no
shape and stay reachable, which is what makes them the forms an opaque type’s methods take.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The reach is the declaring module exactly&lt;/strong&gt;, not a subtree the way &lt;code&gt;private[M]&lt;/code&gt; widens. What
&lt;code&gt;opaque&lt;/code&gt; buys is that a field may move with nothing downstream recompiled, and the set of files that
must recompile together is the module — its files share one scope, so they are already one unit for
this, and a submodule is already not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is not a visibility, and the two are independent.&lt;/strong&gt; Visibility decides who may say the &lt;em&gt;name&lt;/em&gt;;
&lt;code&gt;opaque&lt;/code&gt; decides who may know the &lt;em&gt;shape&lt;/em&gt;. A public type may be opaque, which is the whole point of
one; a &lt;code&gt;private&lt;/code&gt; type may be opaque too, and simply has nobody left to be opaque to.&lt;/p&gt;
&lt;p&gt;Codegen needs nothing for it — pointers lower to &lt;code&gt;ptr&lt;/code&gt;, so a &lt;code&gt;*Opaque&lt;/code&gt; downstream never asks for the
aggregate, and the check is entirely a front-end rule.&lt;/p&gt;
&lt;h2 id=&quot;interrupt-a-definition-the-processor-enters&quot;&gt;&lt;code&gt;interrupt&lt;/code&gt; — a definition the processor enters&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;interrupt&lt;/code&gt; before a definition says the &lt;strong&gt;processor&lt;/strong&gt; enters it, not a caller. It is written where a
visibility modifier is, on the declaration rather than folded into &lt;code&gt;extern&lt;/code&gt;, because it is about a
&lt;em&gt;definition&lt;/em&gt; — the handler is code this program supplies.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;interrupt &lt;span class=&quot;hl-function&quot;&gt;timer&lt;/span&gt;()               &lt;span class=&quot;hl-comment&quot;&gt;// RISC-V: takes nothing&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;interrupt&lt;/span&gt;(supervisor) &lt;span class=&quot;hl-function&quot;&gt;trap&lt;/span&gt;()    &lt;span class=&quot;hl-comment&quot;&gt;// ...at a named privilege level&lt;/span&gt;

interrupt &lt;span class=&quot;hl-function&quot;&gt;fault&lt;/span&gt;(f: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Frame&lt;/span&gt;)      &lt;span class=&quot;hl-comment&quot;&gt;// x86-64: the ABI requires the frame&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One concept, three answers&lt;/strong&gt;, every one of them read off clang rather than out of a document:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;processor&lt;/th&gt;&lt;th&gt;what &lt;code&gt;interrupt&lt;/code&gt; is&lt;/th&gt;&lt;th&gt;the signature it demands&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;x86-64&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;an LLVM calling convention, &lt;code&gt;x86_intrcc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a pointer to the frame the hardware pushed, optionally then an integer error code&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;RISC-V&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;a function &lt;em&gt;attribute&lt;/em&gt;, &lt;code&gt;&amp;quot;interrupt&amp;quot;=&amp;quot;machine&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;nothing at all&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;AArch64&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;it does not exist — a handler is assembly&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Arm M-profile&lt;/strong&gt; (&lt;code&gt;thumb&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;it does not exist — a handler is an ordinary function&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CRAFT&lt;/strong&gt; (&lt;code&gt;craft&lt;/code&gt;)&lt;/td&gt;&lt;td&gt;it does not exist — one vector, and the kernel decodes &lt;code&gt;cause&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;So the annotation names the &lt;strong&gt;concept&lt;/strong&gt; and the back end decides what that becomes. A directive
spelling &lt;code&gt;x86_intrcc&lt;/code&gt; would put one machine’s answer in a source file and be wrong on the other
two — the same shape as &lt;code&gt;@link&lt;/code&gt; naming a library rather than a flag, and the same reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a processor without it, the annotation is refused rather than ignored:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;interrupt &lt;span class=&quot;hl-function&quot;&gt;timer&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;tick&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;interrupt&apos; is not something aarch64 has: its exception entry goes through a vector table of fixed-size instruction slots, so a handler is assembly and there is nothing here for a convention to describe
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Clang answers &lt;code&gt;__attribute__((interrupt))&lt;/code&gt; on AArch64 with “unknown attribute ignored” and compiles
an ordinary function. That is defensible for C, where an attribute is advisory by tradition. It is
not defensible here: the handler would then return with &lt;code&gt;ret&lt;/code&gt; where the machine needs &lt;code&gt;eret&lt;/code&gt;, having
saved none of the registers an asynchronous entry clobbers, so the failure is silent and arrives as
corruption in whatever was interrupted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AArch64’s absence is not an oversight to fill in later.&lt;/strong&gt; Its exception entry goes through a vector
table the processor indexes by cause, where each entry is a fixed-size slot of instructions — so the
entry point is assembly by construction, and there is nothing for a convention on a sysl function to
describe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;M-profile’s absence is a different absence, and the refusal says which one it is.&lt;/strong&gt; Every &lt;code&gt;thumb&lt;/code&gt;
target is Armv6-M, Armv7-M or Armv8-M, and there an exception is entered with &lt;code&gt;xPSR&lt;/code&gt;, &lt;code&gt;PC&lt;/code&gt;, &lt;code&gt;LR&lt;/code&gt;,
&lt;code&gt;R12&lt;/code&gt; and &lt;code&gt;R3&lt;/code&gt;–&lt;code&gt;R0&lt;/code&gt; already stacked by the hardware and &lt;code&gt;EXC_RETURN&lt;/code&gt; in the link register — so a
plain function returning normally &lt;em&gt;is&lt;/em&gt; a correct handler, and the vector table holds its address
rather than its code. Nothing is needed, which is why nothing is accepted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;interrupt &lt;span class=&quot;hl-function&quot;&gt;systick&lt;/span&gt;()
    ()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;interrupt&apos; is not something thumb has: a Cortex-M exception is entered with the caller-saved registers already stacked by the processor and &apos;EXC_RETURN&apos; in the link register, so an ordinary function is already a correct handler and there is no prologue for a convention to arrange — write one, and give it the name the vector table holds with &apos;@export(&amp;quot;SysTick_Handler&amp;quot;)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So &lt;strong&gt;a Cortex-M handler is an ordinary function named for the vector table with &lt;code&gt;@export&lt;/code&gt;&lt;/strong&gt;, which is
already a reachability root — the symbol survives pruning and carries the name the table was built
against, which is the whole of what a handler needs there.&lt;/p&gt;
&lt;p&gt;Three more rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A handler is an entry point, so it is a root of the reachability walk&lt;/strong&gt;, and calling one is
refused outright: it leaves through a return-from-interrupt that would unwind a frame the call
never pushed. A walk starting from what the program &lt;em&gt;runs&lt;/em&gt; therefore cannot reach it, and dropping
it would leave the vector table pointing at nothing. Its address is still worth taking, which is
what fills that table.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The rules are about the signature, so they are checked on the declaration&lt;/strong&gt; rather than while a
body is walked. A generic handler nothing instantiates has no body analyzed at all, and it is
exactly as wrong as one that does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;interrupt&lt;/code&gt; is a soft keyword&lt;/strong&gt;, and what keeps it one is that a name must follow it. Three
things start with that word and only the first is a convention: &lt;code&gt;interrupt timer()&lt;/code&gt; declares a
handler, &lt;code&gt;interrupt(n: int) -&amp;gt; int&lt;/code&gt; declares a function &lt;em&gt;called&lt;/em&gt; &lt;code&gt;interrupt&lt;/code&gt;, and &lt;code&gt;interrupt(4)&lt;/code&gt;
calls one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Nothing about this is portable, and the design does not pretend otherwise.&lt;/strong&gt; An interrupt handler
is the least portable code there is — it is entered by a mechanism the processor defines, and even
the number of arguments differs. What the compiler owes is that the source says which machine it is
for, and that building it for another fails loudly.&lt;/p&gt;
&lt;h2 id=&quot;a-library-may-carry-c&quot;&gt;A library may carry C&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;.c&lt;/code&gt; file dropped in any module of a library’s tree is compiled with it and archived beside it.&lt;/strong&gt;
Nothing declares it and nothing lists it: the build already walks every directory, and a C file found
in one that holds source is compiled for the same target and becomes one more member of the
&lt;code&gt;.syslib&lt;/code&gt;. The sysl side reaches it through the &lt;code&gt;extern&lt;/code&gt; that was already the way to name a symbol
the linker has — so the &lt;em&gt;language&lt;/em&gt; gains nothing, and the whole of the feature is in the build.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A module, and not merely a directory.&lt;/strong&gt; A project is not the only thing that writes into its own
tree: &lt;code&gt;cmake -B build&lt;/code&gt; puts a build directory &lt;em&gt;inside&lt;/em&gt; it and fills that with generated C meant for
another compiler. A directory holding no sysl was never a module, so its C was never the tree’s and
the build passes it by — while still descending through it, because a module may sit any depth below
a directory holding nothing itself. &lt;strong&gt;The tree’s own root is the exception&lt;/strong&gt;, since the root is the
tree rather than a directory in it: a package namespaced by reverse DNS has its modules at
&lt;code&gt;sh/sysl/foo/&lt;/code&gt; and nothing at the top, so C belonging to no single module goes there.&lt;/p&gt;
&lt;p&gt;What this costs is a vendored C library laid out in sub-directories of its own: the ones holding no
sysl are skipped, and a link error naming the symbols is what says so. Put the &lt;code&gt;.sysl&lt;/code&gt; that declares
those &lt;code&gt;extern&lt;/code&gt;s in the directory and it is a module — which is where every binding written so far has
put it anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A shim can be per-operating-system, and that is a directory rather than a condition.&lt;/strong&gt; A &lt;code&gt;.c&lt;/code&gt;
cannot carry a sysl attribute, so &lt;code&gt;#if&lt;/code&gt; is no help to it; what selects it is where it sits. A
directory named &lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt; selects source for one operating system and names nothing
(&lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;), so the file belongs to the module holding the folder and is absent
everywhere else:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl/fs/path.sysl              module sysl.fs, on every target
sysl/fs/__macos__/dirent.c     compiled on macOS
sysl/fs/__linux__/dirent.c     compiled on Linux
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The standard library is the worked example.&lt;/strong&gt; &lt;code&gt;sysl.fs.entries&lt;/code&gt; lists a directory, which means
reading a &lt;code&gt;struct dirent&lt;/code&gt; — a shape whose name field sits at an offset the platforms disagree about,
and exactly the transcription the table below refuses. Four lines of C answer it. The folder is what
keeps that file off a freestanding target, where &lt;code&gt;&amp;lt;dirent.h&amp;gt;&lt;/code&gt; does not exist and &lt;code&gt;sysl.fs&lt;/code&gt; is still
compiled: &lt;strong&gt;the library is compiled whole for every target&lt;/strong&gt;, so a shim it could not compile
everywhere had nowhere to live until the folder existed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It exists because a binding to a real C library cannot be written without it.&lt;/strong&gt; Three things are
reachable from C and from nothing else, and each blocks an ordinary POSIX interface:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;what&lt;/th&gt;&lt;th&gt;why &lt;code&gt;extern&lt;/code&gt; cannot reach it&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a caller-allocated opaque type&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;regcomp&lt;/code&gt; wants a &lt;code&gt;regex_t&lt;/code&gt; the caller supplies, and its size is 32 bytes on Darwin and 64 under glibc. A program can only allocate storage whose size it knows&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a macro&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;REG_EXTENDED&lt;/code&gt;, &lt;code&gt;O_RDONLY&lt;/code&gt;, &lt;code&gt;SIGKILL&lt;/code&gt; are &lt;code&gt;#define&lt;/code&gt;s. They have no symbol, so there is nothing for a linker to resolve and nothing for &lt;code&gt;extern&lt;/code&gt; to name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a shape with no sysl spelling&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;an untagged union, an inline function, and a &lt;strong&gt;C bitfield struct&lt;/strong&gt; — sysl lays an &lt;code&gt;iN&lt;/code&gt; field out in exactly N bits inside &lt;code&gt;@packed&lt;/code&gt; (&lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt;), but C leaves &lt;em&gt;its&lt;/em&gt; allocation to the implementation, so the two need not agree on a size and a shim is what settles it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each becomes an ordinary function in three lines of C:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;size_t sysl_regex_t_size(void)  { return sizeof(regex_t); }
int    sysl_reg_extended(void)  { return REG_EXTENDED; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Better still, a shim that &lt;em&gt;allocates&lt;/em&gt; the opaque type hands back a pointer and the sysl side never
learns the size at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The alternative is transcription, and transcription is silently wrong.&lt;/strong&gt; A hand-written
&lt;code&gt;struct regex_t&lt;/code&gt; carrying one platform’s header fields compiles everywhere and is correct on one
machine. Nothing checks it — sysl’s own &lt;code&gt;sizeof&lt;/code&gt; would report what sysl laid out, not what C did, so
even that comparison is a tautology. Getting it wrong writes past the end of the caller’s storage.
The number has to come from the headers, and C is what reads headers.&lt;/p&gt;
&lt;p&gt;Three build rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A member is named after the path it was found at&lt;/strong&gt;, directories included — &lt;code&gt;demo/util.c&lt;/code&gt; becomes
&lt;code&gt;demo.util.o&lt;/code&gt;. A basename alone would not do: &lt;code&gt;ar r&lt;/code&gt; replaces by name, so two modules each holding
a &lt;code&gt;util.c&lt;/code&gt; would have the second evict the first, and the library would ship missing whatever only
the first defined.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The C files are fingerprinted with the sysl ones.&lt;/strong&gt; A library’s shims are as much its source as
its modules are, and an artifact that did not change when one was edited is a stale artifact
nothing would notice was stale.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross-compiling a library that includes headers needs that target’s headers.&lt;/strong&gt; That is not a cost
the design imposes — it is the requirement being honest: a binding to POSIX regex cannot be built
for a platform whose &lt;code&gt;regex_t&lt;/code&gt; nobody can see. C that includes nothing cross-compiles like any
other object. &lt;strong&gt;A &lt;code&gt;__&amp;lt;os&amp;gt;__&lt;/code&gt; directory is how a library carries both&lt;/strong&gt;: the standard library does
include a header, in a folder no freestanding build ever looks in, so it goes on building for every
target the toolchain can lower for — and the file that would not compile there is not skipped by a
rule about headers, it is simply not part of that build.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;c-const-a-value-only-the-c-compiler-can-work-out&quot;&gt;&lt;code&gt;c const&lt;/code&gt; — a value only the C compiler can work out&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A shim answers for a function, and it does not answer for a value.&lt;/strong&gt; A constant reached through a
call is not a constant: it has no value until the program runs, so it cannot size an array, cannot
stand in a &lt;code&gt;match&lt;/code&gt; arm, cannot be folded into a bound and cannot be checked by &lt;code&gt;@assert&lt;/code&gt;. The macro
row above still holds for &lt;code&gt;REG_EXTENDED&lt;/code&gt; as an &lt;em&gt;argument&lt;/em&gt;, and stops holding the moment the number
has to be known while compiling — which is where a statically allocated FreeRTOS task lives, being a
&lt;code&gt;[sizeof(StaticTask_t)]u8&lt;/code&gt; the caller supplies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;c const&lt;/code&gt; block is a constant whose value the C compiler works out, for the target being built
for.&lt;/strong&gt; The right-hand sides are C, in quotes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;limits.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;BITS&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;CHAR_BIT&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;WIDEST&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sizeof(long long)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;BITS&lt;/span&gt;) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;WIDEST&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;@include&lt;/code&gt; is a header clause like &lt;code&gt;@link&lt;/code&gt;, written the way C writes it — &lt;code&gt;&amp;quot;&amp;lt;limits.h&amp;gt;&amp;quot;&lt;/code&gt; reaches a
system header and &lt;code&gt;&amp;quot;qcbor.h&amp;quot;&lt;/code&gt; one beside the module, which is the same choice a C file makes. Where
the headers are and what they are configured with is &lt;code&gt;--include-path&lt;/code&gt; and &lt;code&gt;--define&lt;/code&gt;‘s answer,
exactly as it is for a shim. &lt;strong&gt;No name from the header becomes visible in sysl&lt;/strong&gt;: a type still
arrives by &lt;code&gt;opaque struct&lt;/code&gt; and a function by &lt;code&gt;extern&lt;/code&gt;, and what the block buys is only that the
expressions compile.&lt;/p&gt;
&lt;p&gt;Which is what the motivating case looks like written out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;FreeRTOS.h&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;STATIC_TASK_SIZE&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sizeof(StaticTask_t)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;MAX_DELAY&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;          = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;portMAX_DELAY&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tcb: [&lt;span class=&quot;hl-type&quot;&gt;STATIC_TASK_SIZE&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-type&quot;&gt;STATIC_TASK_SIZE&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The value is measured from a probe translation unit that is compiled and never linked or run&lt;/strong&gt; —
the file’s headers, one global per constant, lowered to IR for the target, and the number read back
out of the IR. Nothing executes, so the answer is the &lt;em&gt;target’s&lt;/em&gt; rather than the host’s: a pointer
measures four bytes building for a Cortex-M and eight building for this machine, with no hardware
involved either way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;c&lt;/code&gt; is contextual and stays an ordinary name.&lt;/strong&gt; Nothing else in the language follows a name
with a keyword, so &lt;code&gt;c const&lt;/code&gt; cannot be anything but this, and a program counting characters keeps its
variable &lt;code&gt;c&lt;/code&gt;. The C needs no literal prefix for the same kind of reason: inside the block a string
can mean nothing else, so the header marks the language once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any C constant expression, and the C compiler is the judge of which those are&lt;/strong&gt; — which is what
makes that an honest claim rather than a subset somebody maintains. An expression it will not settle
comes back in its own words:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;atoi(&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the C compiler refused this file&apos;s &apos;c const&apos; block
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four more refusals go with it: a header that is not there, a value the declared type cannot hold
(naming the value and both ends of the range), a type that is not a number, and a block written
inside a body, which has no file’s headers to be compiled against.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;string&lt;/code&gt; from C is not written this way.&lt;/strong&gt; A number is a number in the compiler’s output and
reads straight off; a string constant is a block of storage and a different job, and it would have to
be written &lt;code&gt;&amp;quot;\&amp;quot;foo\&amp;quot;&amp;quot;&lt;/code&gt; — two quotings for one value, which is a form nobody would guess. The refusal
says so rather than leaving it to be found.&lt;/p&gt;
&lt;h3 id=&quot;a-float-is-measured-too-and-it-is-the-value-hand-copying-gets-wrong&quot;&gt;A float is measured too, and it is the value hand-copying gets wrong&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The declared type may be &lt;code&gt;f32&lt;/code&gt; or &lt;code&gt;f64&lt;/code&gt;.&lt;/strong&gt; That a float can be spelled by name is no answer here:
a name gives you the &lt;em&gt;width&lt;/em&gt;, and what nothing was checking is the &lt;strong&gt;value&lt;/strong&gt;. The case that makes it
worth a feature rather than a convenience is the macro written as an expression over other macros —
a graphics or physics header is full of them — because copying one of those means doing the arithmetic
by hand and writing the answer down.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;float.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    pi:      &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;3.14159265359f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    quarter: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;0.25f * 3.14159265359f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    eps:     &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;FLT_EPSILON&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; one: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(quarter * &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt; == pi, one + eps &amp;gt; one, one + eps / &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt; == one)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;FLT_EPSILON&lt;/code&gt; is the second reason: it is the definition of the width rather than a number about it,
and a transcription with one digit wrong still looks plausible while being the wrong tolerance for
every convergence loop that uses it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rounding is allowed and silent.&lt;/strong&gt; Asking for &lt;code&gt;f32&lt;/code&gt; is asking for the nearest &lt;code&gt;f32&lt;/code&gt;, which is what C
does for &lt;code&gt;float x = M_PI;&lt;/code&gt; — refusing it would leave the narrow width unable to read the
&lt;code&gt;double&lt;/code&gt;-typed macros that are most of them. What is refused is the value going &lt;em&gt;missing&lt;/em&gt;: a
measurement that is not finite, because the C overflowed while settling it or the macro names an
infinity or a NaN, and a finite one the declared width turns into an infinity or into a zero it was
not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    huge: &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;1e300&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;which &apos;f32&apos; cannot hold
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The widths are &lt;code&gt;f32&lt;/code&gt; and &lt;code&gt;f64&lt;/code&gt;, and &lt;code&gt;f16&lt;/code&gt; is refused by name.&lt;/strong&gt; C writes a constant expression as a
&lt;code&gt;float&lt;/code&gt;, a &lt;code&gt;double&lt;/code&gt; or a &lt;code&gt;long double&lt;/code&gt;, so those two are the widths a measurement reads back at
without anyone having to guess which was meant.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    h: f16 = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;f16&apos; is not a width a &apos;c const&apos; is measured at
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;c type&lt;/code&gt; below still refuses a float, and that is a different question.&lt;/strong&gt; A typedef is measured
because its &lt;em&gt;width&lt;/em&gt; is the configuration’s to decide, and &lt;code&gt;float&lt;/code&gt; and &lt;code&gt;double&lt;/code&gt; are IEEE binary32 and
binary64 on every machine sysl targets — so &lt;code&gt;f32&lt;/code&gt; and &lt;code&gt;f64&lt;/code&gt; by name really are the whole answer
there. It is the value that varies, never the width.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The declared type may be a transparent subtype of a number&lt;/strong&gt;, which is what makes this block and
&lt;code&gt;c type&lt;/code&gt; below a pair rather than two features. Without &lt;code&gt;new&lt;/code&gt; such a type &lt;em&gt;is&lt;/em&gt; its base, so a
constant declared at one is a constant declared at that base — and a measured type is exactly that
shape:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;uint32_t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    forever: &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;0xFFFFFFFFul&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;wait&lt;/span&gt;(ticks: &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt;
    ticks

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;wait&lt;/span&gt;(forever)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4294967295
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the case the two blocks exist for: a typedef whose width the configuration decides, and the
constants that have to be that width. Spelling the constant &lt;code&gt;usize&lt;/code&gt; beside a &lt;code&gt;Tick&lt;/code&gt; parameter is a
package that stops compiling on a port where the two disagree, which is the version of this mistake
that used to ship.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The name is followed against the file’s own declarations&lt;/strong&gt; — a &lt;code&gt;c type&lt;/code&gt; measured beside it, or a
&lt;code&gt;type&lt;/code&gt; whose base reaches an integer — and a name from anywhere else is refused. A block is one
question put to one file’s headers, and a type measured against another file’s is not an answer this
one can use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;within&lt;/code&gt; range is checked while compiling&lt;/strong&gt;, against the number that came back:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

c &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sizeof(long long) * 100&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;does not admit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which is the &lt;code&gt;@assert&lt;/code&gt; a program would otherwise write underneath. A &lt;strong&gt;&lt;code&gt;where&lt;/code&gt; predicate&lt;/strong&gt; is refused
rather than checked — a predicate is a function, checked where a value is &lt;em&gt;made&lt;/em&gt;, and a constant is
folded into its uses rather than made anywhere — and so is a &lt;strong&gt;&lt;code&gt;new&lt;/code&gt; type&lt;/strong&gt;, since reaching one from
its base is a written conversion and there is nowhere on the line to write it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The value does not travel through the C type.&lt;/strong&gt; C narrows, so &lt;code&gt;(uint8_t)800&lt;/code&gt; is &lt;code&gt;32&lt;/code&gt;; carrying it
that way would let a constant that should have been refused arrive looking like one that fits, and
the range check is the whole point of having written the type down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A library ships the measured number, not the expression.&lt;/strong&gt; The lowering happens before the artifact
is written, so a program linking a package needs neither the package’s headers nor a C compiler of
its own — and could not honestly be handed the expression anyway, since an artifact is built for one
target and re-measuring it elsewhere would answer a different question under the same name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A file that writes no block costs nothing&lt;/strong&gt; and never causes a C compiler to be looked for.&lt;/p&gt;
&lt;h3 id=&quot;a-file-that-says-what-it-needs-is-not-probed-where-it-could-not-be&quot;&gt;A file that says what it needs is not probed where it could not be&lt;/h3&gt;
&lt;p&gt;A probe is a C compilation, so a file carrying one &lt;strong&gt;asks for headers&lt;/strong&gt; — and a library is built for
every target it might be used on. Without a rule here a library could hold no block at all: one module
measuring &lt;code&gt;sizeof(regex_t)&lt;/code&gt; would fail every freestanding build of every program, including programs
that never name it, because there is no &lt;code&gt;&amp;lt;regex.h&amp;gt;&lt;/code&gt; for a bare Cortex-M and no reason there should be.&lt;/p&gt;
&lt;p&gt;So a file’s blocks are &lt;strong&gt;skipped&lt;/strong&gt; when the file declares
&lt;a href=&quot;/reference/modules/#capabilities-are-a-module-property&quot;&gt;&lt;code&gt;@requires&lt;/code&gt;&lt;/a&gt; on a capability the machine
cannot have:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;module sysl.posix.regex
@requires(posix)
@include(&amp;quot;regex.h&amp;quot;)

c const
    REGEX_SIZE: usize = &amp;quot;sizeof(regex_t)&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Built for a freestanding target, no C compiler is asked anything. The module’s &lt;strong&gt;header stays&lt;/strong&gt; and
its declarations go, so a program that &lt;em&gt;does&lt;/em&gt; reach it is told what it needs rather than being
answered with an undefined name:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;this reaches &apos;sysl.posix.regex&apos;, which requires &apos;posix&apos;, and this module declared &apos;no posix&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What is asked is whether the machine can have the capability, not whether the project provides
it.&lt;/strong&gt; &lt;a href=&quot;/reference/packages/#capabilities&quot;&gt;&lt;code&gt;package.hocon&lt;/code&gt;&lt;/a&gt; treats a capability it does not mention as
provided, so a freestanding target nominally offers &lt;code&gt;posix&lt;/code&gt; — a gate reading that would gate nothing
at all. The question here is physical and has one answer per target: an operating system, and POSIX.
Whether there is a &lt;strong&gt;heap&lt;/strong&gt; is not asked, because that is an engineering decision about a machine
that could have one either way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A file that requires nothing is measured wherever it is built.&lt;/strong&gt; Such a file claims to build
anywhere, so a header missing there is the file having mis-stated itself — the skip is a rule about
files that said what they need, not about which machine is in front of you.&lt;/p&gt;
&lt;h2 id=&quot;c-type-a-width-only-the-c-compiler-can-work-out&quot;&gt;&lt;code&gt;c type&lt;/code&gt; — a width only the C compiler can work out&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;c const&lt;/code&gt; can measure &lt;code&gt;sizeof(TickType_t)&lt;/code&gt; and cannot use the answer.&lt;/strong&gt; Nothing turns a constant
into the type of a parameter, so a typedef whose width the target or a &lt;code&gt;#define&lt;/code&gt; decides could be
measured and not &lt;em&gt;spelled&lt;/em&gt; — and a binding had to pick one integer and be right by luck.&lt;/p&gt;
&lt;p&gt;That is the version of the transcription problem with no symptom. &lt;code&gt;TickType_t&lt;/code&gt; is eight bytes for
FreeRTOS’s POSIX port, four on a Cortex-M and two under &lt;code&gt;configUSE_16_BIT_TICKS&lt;/code&gt;, and every one of
them appears in a signature. An &lt;code&gt;extern&lt;/code&gt; declaring the wrong one is not a size mismatch anything can
see: it links, and then passes garbage in the high half.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;c type&lt;/code&gt; block is the type the C compiler says a name is&lt;/strong&gt;, for the target being built for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;stddef.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A measured type &lt;strong&gt;is&lt;/strong&gt; the integer it was measured as — a second name for it, interchangeable with
it, checking nothing of its own — so arithmetic on one needs no cast and an &lt;code&gt;extern&lt;/code&gt; written against
one is an ordinary declaration:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;FreeRTOS.h&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt;  = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;TickType_t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Stack&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;configSTACK_DEPTH_TYPE&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;vTaskDelay&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;c_task_delay&lt;/span&gt;(ticks: &lt;span class=&quot;hl-type&quot;&gt;Tick&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything &lt;code&gt;c const&lt;/code&gt; says holds here: the same contextual &lt;code&gt;c&lt;/code&gt;, the same quoting, the same &lt;code&gt;@include&lt;/code&gt;
headers, the same probe compiled and never run, and the same rule that a library ships the answer
rather than the C name. &lt;strong&gt;A file writing both blocks asks the C compiler once&lt;/strong&gt;, since the two are one
question rather than a price per line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A line carries no sysl type&lt;/strong&gt;, which is the whole difference from a &lt;code&gt;c const&lt;/code&gt; line — the type is the
answer rather than the question. A program that wants to &lt;em&gt;state&lt;/em&gt; a width writes &lt;code&gt;@assert&lt;/code&gt; over a
&lt;code&gt;c const&lt;/code&gt; holding the &lt;code&gt;sizeof&lt;/code&gt;, which says the same thing where it can be checked.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;c const&lt;/code&gt; &lt;strong&gt;declared at&lt;/strong&gt; a measured type is the other half of the pair, and is written out above.
Two blocks in one file are one question, and a binding usually writes both.&lt;/p&gt;
&lt;h3 id=&quot;a-number-your-program-worked-out-reaches-one-under-the-type-s-own-name&quot;&gt;A number your program worked out reaches one under the type’s own name&lt;/h3&gt;
&lt;p&gt;A measured type is a transparent subtype, so a value of the integer it turns out to be flows in and
out with no cast at all. What a program &lt;em&gt;has&lt;/em&gt;, though, is usually a &lt;code&gt;usize&lt;/code&gt; — a &lt;code&gt;sizeof&lt;/code&gt;, a slice’s
&lt;code&gt;len&lt;/code&gt;, or arithmetic over them — and that is a different type from whatever C measured. The
conversion is the type’s own name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;stddef.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt;(xs.len)) + &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That spelling is the only portable one&lt;/strong&gt;, which is the whole reason it exists: the width is the
target’s, so writing &lt;code&gt;u32(xs.len)&lt;/code&gt; would be one configuration’s answer copied into the source — the
transcription a &lt;code&gt;c type&lt;/code&gt; is for abolishing. It is the ordinary case in a binding rather than a corner
of one: a queue’s item size and a task’s stack depth are both a number sysl worked out and C has a
typedef for.&lt;/p&gt;
&lt;p&gt;The conversion is &lt;strong&gt;written&lt;/strong&gt;, and an unwritten one is refused even where the widths happen to agree
on the machine in front of you:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;include&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;stddef.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;size_t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Size&lt;/span&gt; = n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;(n))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;n&apos; of &apos;take&apos; is Size, but usize was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A silent narrowing is exactly what breaks on the target where the typedef is sixteen bits, so it is
refused here where it can be seen. The &lt;a href=&quot;/tour/contracts/&quot;&gt;contracts&lt;/a&gt; page has the general rule, of
which this is one case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What comes back is a width and a signedness.&lt;/strong&gt; Three things follow, and each was measured against
the C compiler rather than assumed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;an &lt;strong&gt;enum&lt;/strong&gt; is measurable and carries the signedness the C compiler chose for it;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;qualifier&lt;/strong&gt; needs no special case, so &lt;code&gt;const unsigned short&lt;/code&gt; measures as &lt;code&gt;unsigned short&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;plain &lt;strong&gt;&lt;code&gt;char&lt;/code&gt;&lt;/strong&gt; is asked about rather than assumed, since C leaves its signedness to the
implementation — it is signed on an Apple arm64 machine and unsigned on many others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;_Bool&lt;/code&gt; arrives as &lt;code&gt;bool&lt;/code&gt;&lt;/strong&gt;, the one answer that is not an integer and is still given: C means by
&lt;code&gt;_Bool&lt;/code&gt; what sysl means by &lt;code&gt;bool&lt;/code&gt;, and the two already cross as a single unsigned byte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A type C does not describe as an integer is refused by name:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;c &lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;void *&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is not an integer type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A float, a pointer, a struct and an array each already have an answer here — a float by name, an
address as &lt;code&gt;*T&lt;/code&gt;, a struct as an &lt;code&gt;opaque struct&lt;/code&gt; — and each is better than a same-width integer
standing in for it and losing what it was.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-absent&quot;&gt;What is deliberately absent&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;absent&lt;/th&gt;&lt;th&gt;instead&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;an &lt;code&gt;fn(int) -&amp;gt; int&lt;/code&gt; type for sysl’s own callables&lt;/td&gt;&lt;td&gt;the &lt;code&gt;Fn&lt;/code&gt; trait; &lt;code&gt;*extern&lt;/code&gt; exists only where the representation is somebody else’s to choose&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a header parser or a binding generator&lt;/td&gt;&lt;td&gt;an &lt;code&gt;extern&lt;/code&gt; per declaration, and a &lt;code&gt;.c&lt;/code&gt; shim for what a header hides&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a calling convention on an export&lt;/td&gt;&lt;td&gt;open — &lt;code&gt;@export&lt;/code&gt; implies C’s, and &lt;code&gt;interrupt&lt;/code&gt; already built the shape a second one would take&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a capability gate on an extern&lt;/td&gt;&lt;td&gt;open — an extern reaching libc plausibly needs &lt;code&gt;os&lt;/code&gt;, and does not yet say so&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an alias for a pointer signature&lt;/td&gt;&lt;td&gt;open — what is missing is a type alias that is not a constrained subtype&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Both directions now exist. &lt;code&gt;extern&lt;/code&gt; calls out of sysl and &lt;code&gt;@export&lt;/code&gt; calls into it, which is what an
incremental replacement of a C codebase needs: the sysl side can sit underneath an existing C
program as readily as on top of an existing C library.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes and compile-time&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Expressions and operators</title>
    <link href="https://sysl.sh/reference/expressions/"/>
    <id>https://sysl.sh/reference/expressions/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The precedence ladder, every operator&apos;s meaning, evaluation order, and the traits an operator dispatches through.</summary>
    <content type="html">&lt;p&gt;Almost everything in sysl is an expression. Assignment yields the value assigned, &lt;code&gt;++&lt;/code&gt; yields a
value, and &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;match&lt;/code&gt; and the loops all yield the branch they took. What is &lt;em&gt;not&lt;/em&gt; an expression is
a short list — a declaration, a multiple assignment, and &lt;code&gt;defer&lt;/code&gt; — and each is named where it comes
up rather than left to be discovered.&lt;/p&gt;
&lt;p&gt;This page is about how expressions are built and what each operator means. Where an expression is a
control-flow form, &lt;a href=&quot;/reference/statements/&quot;&gt;statements and control flow&lt;/a&gt; has the details of the form
itself.&lt;/p&gt;
&lt;h2 id=&quot;precedence&quot;&gt;Precedence&lt;/h2&gt;
&lt;p&gt;Loosest at the top, tightest at the bottom. The set is &lt;strong&gt;closed&lt;/strong&gt;: there are no user-defined
operator symbols, and no facility to add one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Prec&lt;/th&gt;&lt;th&gt;Operators&lt;/th&gt;&lt;th&gt;Role&lt;/th&gt;&lt;th&gt;Associativity&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;&lt;code&gt;=&lt;/code&gt; &lt;code&gt;+=&lt;/code&gt; &lt;code&gt;-=&lt;/code&gt; &lt;code&gt;*=&lt;/code&gt; &lt;code&gt;/=&lt;/code&gt; &lt;code&gt;%=&lt;/code&gt; &lt;code&gt;&amp;amp;=&lt;/code&gt; &lt;code&gt;\|=&lt;/code&gt; &lt;code&gt;^=&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;lt;=&lt;/code&gt; &lt;code&gt;&amp;gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;assignment&lt;/td&gt;&lt;td&gt;right&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;&lt;code&gt;\|\|&lt;/code&gt;&lt;/td&gt;&lt;td&gt;logical or&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;logical and&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;&lt;code&gt;is&lt;/code&gt;, &lt;code&gt;is not&lt;/code&gt;&lt;/td&gt;&lt;td&gt;pattern test&lt;/td&gt;&lt;td&gt;non-associative&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;&lt;code&gt;==&lt;/code&gt; &lt;code&gt;!=&lt;/code&gt; &lt;code&gt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;lt;=&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;comparison&lt;/td&gt;&lt;td&gt;&lt;strong&gt;chained&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;&lt;code&gt;..&lt;/code&gt; &lt;code&gt;..&amp;lt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;range&lt;/td&gt;&lt;td&gt;non-associative&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;&lt;code&gt;\|&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bitwise or&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bitwise xor&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;bitwise and&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;td&gt;add, subtract&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;&lt;code&gt;*&lt;/code&gt; &lt;code&gt;/&lt;/code&gt; &lt;code&gt;%&lt;/code&gt; &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;multiply, divide, remainder, shift&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;12&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt; &lt;code&gt;!&lt;/code&gt; &lt;code&gt;~&lt;/code&gt; &lt;code&gt;*&lt;/code&gt; &lt;code&gt;&amp;amp;&lt;/code&gt; &lt;code&gt;++&lt;/code&gt; &lt;code&gt;--&lt;/code&gt;&lt;/td&gt;&lt;td&gt;prefix unary&lt;/td&gt;&lt;td&gt;right&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;13&lt;/td&gt;&lt;td&gt;&lt;code&gt;[]&lt;/code&gt; &lt;code&gt;.&lt;/code&gt; &lt;code&gt;()&lt;/code&gt; &lt;code&gt;::&lt;/code&gt; &lt;code&gt;?&lt;/code&gt; &lt;code&gt;++&lt;/code&gt; &lt;code&gt;--&lt;/code&gt;&lt;/td&gt;&lt;td&gt;postfix&lt;/td&gt;&lt;td&gt;left&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;*&lt;/code&gt; and &lt;code&gt;&amp;amp;&lt;/code&gt; appear at two levels each — prefix at 12 (dereference, address-of) and binary at 11 and 9
(multiply, bitwise and). Position tells them apart, and nothing else has to.&lt;/p&gt;
&lt;h3 id=&quot;two-deliberate-corrections-to-c&quot;&gt;Two deliberate corrections to C&lt;/h3&gt;
&lt;p&gt;Every level above matches C except two, and both are cases C is now widely held to have gotten wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bitwise binds tighter than comparison.&lt;/strong&gt; &lt;code&gt;x &amp;amp; mask == 0&lt;/code&gt; means &lt;code&gt;(x &amp;amp; mask) == 0&lt;/code&gt;, which is what it
looks like. In C it means &lt;code&gt;x &amp;amp; (mask == 0)&lt;/code&gt;, the single most-cited precedence bug in the language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Shift binds like multiplication&lt;/strong&gt;, at level 11 alongside &lt;code&gt;* / %&lt;/code&gt;, rather than looser than addition.
A shift &lt;em&gt;is&lt;/em&gt; a multiply or divide by a power of two, so it belongs with them. This is Go’s fix, and a
deliberate divergence from Rust and Zig toward it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x = &lt;span class=&quot;hl-number&quot;&gt;0b1100&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mask = &lt;span class=&quot;hl-number&quot;&gt;0b0100&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x &amp;amp; mask == &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; + &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
17
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both of those need parentheses in C, Rust and Zig. The payoff in systems code is that
&lt;code&gt;base + index &amp;lt;&amp;lt; shift&lt;/code&gt; and &lt;code&gt;a &amp;lt;&amp;lt; 8 + b&lt;/code&gt; group the way they read.&lt;/p&gt;
&lt;h2 id=&quot;operands&quot;&gt;Operands&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Both operands of a binary operator have the same type.&lt;/strong&gt; There is no implicit promotion anywhere,
so a mixed-width expression is a diagnostic asking for the conversion rather than a silent widening.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a + b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got int and long
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This includes the &lt;strong&gt;shift amount&lt;/strong&gt;: in &lt;code&gt;x &amp;lt;&amp;lt; 2&lt;/code&gt; the literal &lt;code&gt;2&lt;/code&gt; takes &lt;code&gt;x&lt;/code&gt;‘s type by the literal rule,
and shifting by a value of some other type is written &lt;code&gt;x &amp;lt;&amp;lt; u8(k)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;what-has-arithmetic&quot;&gt;What has arithmetic&lt;/h3&gt;
&lt;p&gt;Arithmetic is defined on the numeric types and nowhere else. &lt;code&gt;char&lt;/code&gt; has equality and ordering and no
arithmetic at all; &lt;code&gt;bool&lt;/code&gt; has equality, no ordering, and no arithmetic.&lt;/p&gt;
&lt;p&gt;Unary &lt;code&gt;-&lt;/code&gt; needs a type with a sign, so it is the signed integers and the floats — negating an
unsigned value is written as the subtraction it actually is. Unary &lt;code&gt;~&lt;/code&gt; is defined on every integer
type, signed or not.&lt;/p&gt;
&lt;p&gt;Integer arithmetic &lt;strong&gt;wraps&lt;/strong&gt; at the declared width; see &lt;a href=&quot;/reference/types/&quot;&gt;types&lt;/a&gt;. Integer division
by zero traps.&lt;/p&gt;
&lt;h3 id=&quot;equality-reaches-further-than-ordering&quot;&gt;Equality reaches further than ordering&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt; are defined wherever &lt;code&gt;&amp;lt;&lt;/code&gt; is, and additionally on &lt;code&gt;bool&lt;/code&gt; and on the two pointer-shaped
modes &lt;code&gt;*T&lt;/code&gt; and &lt;code&gt;&amp;amp;T&lt;/code&gt;, which compare by address. &lt;strong&gt;Ordering on an address is not defined&lt;/strong&gt; — a bare
address has no meaningful one.&lt;/p&gt;
&lt;h3 id=&quot;the-one-arithmetic-two-pointers-have-is&quot;&gt;The one arithmetic two pointers have is &lt;code&gt;-&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;p - q&lt;/code&gt;, between two &lt;code&gt;*T&lt;/code&gt;s of the same pointee, is an &lt;code&gt;isize&lt;/code&gt; counting the &lt;strong&gt;elements&lt;/strong&gt; between them
— C’s &lt;code&gt;ptrdiff_t&lt;/code&gt;, and the inverse of &lt;code&gt;&amp;amp;p[n]&lt;/code&gt;. It is the only operator whose result type is neither
operand’s.&lt;/p&gt;
&lt;p&gt;Nothing else is defined: &lt;code&gt;p + q&lt;/code&gt; names no address, &lt;code&gt;p - n&lt;/code&gt; is what &lt;code&gt;&amp;amp;p[n]&lt;/code&gt; is for, and a counted
&lt;code&gt;&amp;amp;T&lt;/code&gt; has no arithmetic at all.&lt;/p&gt;
&lt;h2 id=&quot;comparison-chains&quot;&gt;Comparison chains&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a &amp;lt; b &amp;lt; c&lt;/code&gt; is &lt;strong&gt;one comparison node&lt;/strong&gt;, not two comparisons and a &lt;code&gt;bool&lt;/code&gt;. It means &lt;code&gt;a &amp;lt; b &amp;amp;&amp;amp; b &amp;lt; c&lt;/code&gt;,
short-circuiting — and a middle operand is &lt;strong&gt;evaluated once&lt;/strong&gt; and compared twice.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;evaluated&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, n)
    n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &amp;lt; &lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;) &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt; &amp;lt; &lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;) &amp;lt; &lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;evaluated 5
true
evaluated 5
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line calls &lt;code&gt;bump&lt;/code&gt; &lt;strong&gt;once&lt;/strong&gt; although its value is compared twice. The second stops at the
first comparison that fails, so the &lt;code&gt;bump(6)&lt;/code&gt; on its right never runs at all.&lt;/p&gt;
&lt;h3 id=&quot;a-vector-comparison-is-not-a-chain&quot;&gt;A vector comparison is not a chain&lt;/h3&gt;
&lt;p&gt;Comparing two &lt;a href=&quot;/reference/vectors/&quot;&gt;vectors&lt;/a&gt; yields a mask rather than a &lt;code&gt;bool&lt;/code&gt;, and a chain of them
is &lt;strong&gt;refused&lt;/strong&gt;. The reason is the short-circuiting above: &lt;code&gt;a &amp;lt; b &amp;lt; c&lt;/code&gt; joins its links with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, and
there is no such thing as short-circuiting one lane of a register and not another. Reading the chain
as a lane-wise &lt;code&gt;&amp;amp;&lt;/code&gt; would give the same spelling a different meaning, so the reader is asked to write
the &lt;code&gt;&amp;amp;&lt;/code&gt; and see it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&amp;gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; m = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &amp;lt; a &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;compare two vectors at a time and combine the masks with &apos;&amp;amp;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;floats-compare-by-ieee-754-nan-and-all&quot;&gt;Floats compare by IEEE 754, &lt;code&gt;NaN&lt;/code&gt; and all&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;NaN&lt;/code&gt; is equal to nothing, itself included. So &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt; and &lt;code&gt;&amp;gt;=&lt;/code&gt; are &lt;strong&gt;all false&lt;/strong&gt; at
one — and &lt;code&gt;!=&lt;/code&gt; is &lt;strong&gt;true&lt;/strong&gt;, because IEEE makes it the negation of &lt;code&gt;==&lt;/code&gt; rather than a sixth ordered
comparison. Exactly one of the six answers true.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; zero = &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; nan = zero / zero

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(nan == nan, nan != nan)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(nan &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, nan &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false true
false false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also why a float is not hashable: a table assumes a reflexive equality, and one &lt;code&gt;NaN&lt;/code&gt; breaks
it.&lt;/p&gt;
&lt;h2 id=&quot;logical-operators&quot;&gt;Logical operators&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and &lt;code&gt;||&lt;/code&gt; take &lt;code&gt;bool&lt;/code&gt; and short-circuit; &lt;code&gt;!&lt;/code&gt; is prefix on a &lt;code&gt;bool&lt;/code&gt;. Nothing coerces to &lt;code&gt;bool&lt;/code&gt;, so
there is no integer-as-condition rule and no &lt;code&gt;if (p)&lt;/code&gt; idiom — write &lt;code&gt;p != null&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ranges&quot;&gt;Ranges&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a..b&lt;/code&gt; is inclusive, &lt;code&gt;a..&amp;lt;b&lt;/code&gt; is half-open. Either end may be omitted: &lt;code&gt;a..&lt;/code&gt;, &lt;code&gt;..b&lt;/code&gt;, &lt;code&gt;..&amp;lt;b&lt;/code&gt;, and a
bare &lt;code&gt;..&lt;/code&gt; meaning the whole thing.&lt;/p&gt;
&lt;p&gt;Ranges are &lt;strong&gt;non-associative&lt;/strong&gt; and sit below arithmetic and above comparison, which is Swift’s
placement — so &lt;code&gt;0..&amp;lt;n + 1&lt;/code&gt; is &lt;code&gt;0..&amp;lt;(n + 1)&lt;/code&gt; and needs no parentheses.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; lo = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; lo..lo + &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The spelling deviates from Swift’s &lt;code&gt;...&lt;/code&gt; toward Kotlin’s &lt;code&gt;..&lt;/code&gt; / &lt;code&gt;..&amp;lt;&lt;/code&gt;, because the two forms are
visually parallel and read as “through” and “up to, less than”. It lexes unambiguously: a float
literal needs digits after the &lt;code&gt;.&lt;/code&gt;, so &lt;code&gt;1..2&lt;/code&gt; is three tokens and not two.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;..=&lt;/code&gt; is not a spelling sysl has&lt;/strong&gt;, and is refused by name wherever a range may be written — it is
Rust’s inclusive range, and inclusive here is the bare &lt;code&gt;..&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; a..=&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;..=&apos; is not a range — inclusive is &apos;a..b&apos; and exclusive is &apos;a..&amp;lt;b&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;is-a-pattern-where-a-condition-is-wanted&quot;&gt;&lt;code&gt;is&lt;/code&gt; — a pattern where a condition is wanted&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;x is Pat&lt;/code&gt; tests a value against a pattern and yields a &lt;code&gt;bool&lt;/code&gt;; &lt;code&gt;x is not Pat&lt;/code&gt; negates it. The right
side is a full pattern, alternatives (&lt;code&gt;|&lt;/code&gt;) included — the same grammar a &lt;code&gt;match&lt;/code&gt; arm’s left side
uses, so it is not a second thing to learn.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(_, _) &amp;amp;&amp;amp; s &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(_)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;rectangular&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;rectangular
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its level — between &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and the comparisons — is what makes &lt;code&gt;a is P &amp;amp;&amp;amp; b &amp;gt; 0&lt;/code&gt; a chain of two terms
rather than an &lt;code&gt;is&lt;/code&gt; against a conjunction. Both &lt;code&gt;is&lt;/code&gt; and &lt;code&gt;not&lt;/code&gt; are &lt;strong&gt;soft&lt;/strong&gt; words: neither is
reserved, so both remain usable as ordinary names, and this is the only place either reads as a
keyword.&lt;/p&gt;
&lt;h2 id=&quot;assignment&quot;&gt;Assignment&lt;/h2&gt;
&lt;p&gt;Assignment is an &lt;strong&gt;expression&lt;/strong&gt; yielding the value assigned, lowest precedence and
right-associative.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

a = b = c = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b, c)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 7 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is what makes the capture idioms available — &lt;code&gt;while (c = next()) != 0&lt;/code&gt;,
&lt;code&gt;if (p = find(k)) != null&lt;/code&gt;. C’s classic &lt;code&gt;if (x = 0)&lt;/code&gt; bug is not caused by this; it is caused by C
additionally letting any integer serve as a truth value. sysl has a distinct &lt;code&gt;bool&lt;/code&gt; with no such
coercion, so the mistake is already a type error and needs no grammar ban:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; x = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;never&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;condition must be bool, got int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The compound forms &lt;code&gt;+=&lt;/code&gt;, &lt;code&gt;-=&lt;/code&gt;, &lt;code&gt;&amp;amp;=&lt;/code&gt; and the rest are &lt;strong&gt;not separate operators with their own
traits&lt;/strong&gt;: &lt;code&gt;a += b&lt;/code&gt; is defined as &lt;code&gt;a = a + b&lt;/code&gt; and requires exactly what &lt;code&gt;+&lt;/code&gt; requires. There is no
&lt;code&gt;AddAssign&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;statement-position-discards-a-block-s-value&quot;&gt;Statement position discards a block’s value&lt;/h3&gt;
&lt;p&gt;A block’s value is its trailing expression — but where the block’s own value is unused, the block has
&lt;strong&gt;none&lt;/strong&gt;, and its type is &lt;code&gt;unit&lt;/code&gt; whatever the last line yields. Without that rule an &lt;code&gt;if&lt;/code&gt; whose
branches merely each did something would be forced to make those somethings agree:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if c
    full = true          // bool
else
    len += 1             // usize
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The rule is about the &lt;strong&gt;position&lt;/strong&gt;, not the operator: it propagates into the branches of an &lt;code&gt;if&lt;/code&gt;, the
arms of a &lt;code&gt;match&lt;/code&gt;, and a loop’s &lt;code&gt;else&lt;/code&gt;. Statement position starts at a statement, at a loop body, and
at the body of a function that returns nothing.&lt;/p&gt;
&lt;p&gt;A block that does not &lt;em&gt;arrive&lt;/em&gt; keeps &lt;code&gt;never&lt;/code&gt; rather than collapsing to &lt;code&gt;unit&lt;/code&gt; — that is
reachability, not a value, and the code around it is entitled to know.&lt;/p&gt;
&lt;h3 id=&quot;several-places-at-once&quot;&gt;Several places at once&lt;/h3&gt;
&lt;p&gt;A comma-separated list of places takes a comma-separated list of values. &lt;strong&gt;The right side is
evaluated in full, into temporaries, before any assignment happens&lt;/strong&gt; — which is the entire content of
the feature, and what makes the first line below a swap rather than two statements that leave both
variables holding &lt;code&gt;b&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

a, b = b, a

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;]

xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;] = xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b, xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 1 30 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compound forms multi-assign too, and need no rule of their own — only the one above, read carefully.
Every place is located, then every place a compound form touches is &lt;strong&gt;read&lt;/strong&gt;, then the whole right
side is produced, and only then does anything land:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

a, b += b, a

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both arms saw the values the statement started with. Written as two statements it would not work:
&lt;code&gt;a += b&lt;/code&gt; followed by &lt;code&gt;b += a&lt;/code&gt; folds the new &lt;code&gt;a&lt;/code&gt; into &lt;code&gt;b&lt;/code&gt;, and nothing on the page says so.&lt;/p&gt;
&lt;p&gt;A place’s own subexpressions are evaluated &lt;strong&gt;exactly once&lt;/strong&gt;, before the assignments — so in
&lt;code&gt;xs[f()], xs[g()] = xs[g()], xs[f()]&lt;/code&gt; each of &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; runs once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A multiple assignment is a statement, not an expression&lt;/strong&gt;, and that is what keeps it small. A
single assignment yields the value assigned; a multiple one would have to yield several, and the only
thing that could be is a tuple — allocating a product type for a form whose whole point is that
several places change at once. So it does not nest, does not appear in a condition, and has no value
to discard. A binding takes the same list: &lt;code&gt;val a, b = 1, 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An element reached through a user type’s &lt;code&gt;Index&lt;/code&gt; is the one place the accepted set is &lt;em&gt;smaller&lt;/em&gt; than
a single &lt;code&gt;=&lt;/code&gt;‘s, because &lt;code&gt;b[i] = v&lt;/code&gt; there is a call rather than a store, and there is nothing to split
into the two halves the ordering rule is about.&lt;/p&gt;
&lt;h2 id=&quot;and&quot;&gt;&lt;code&gt;++&lt;/code&gt; and &lt;code&gt;--&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Expressions, both prefix and postfix. Prefix yields the new value; postfix yields the old one. This
is what the pointer-walking idioms need — &lt;code&gt;*p++&lt;/code&gt; only works if &lt;code&gt;++&lt;/code&gt; is an expression.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i++, i, ++i, i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 6 7 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C’s &lt;code&gt;i = i++ + ++i&lt;/code&gt; is undefined because C leaves evaluation order unspecified while allowing
unsequenced mutation of one object. sysl fixes the root cause rather than banning the operator:
&lt;strong&gt;evaluation order is strictly left to right&lt;/strong&gt;, everywhere — operands of a binary operator, function
arguments, index expressions. With an order defined, the expression above has one meaning. It is
merely hard to read, which makes it a lint candidate and not a footgun.&lt;/p&gt;
&lt;p&gt;Postfix binds tighter than prefix, so &lt;code&gt;*p++&lt;/code&gt; is &lt;code&gt;*(p++)&lt;/code&gt; and &lt;code&gt;-a.b&lt;/code&gt; is &lt;code&gt;-(a.b)&lt;/code&gt;, exactly as in C.&lt;/p&gt;
&lt;h2 id=&quot;the-postfix-tail&quot;&gt;The postfix tail&lt;/h2&gt;
&lt;p&gt;Six things attach to an expression on the right, and they compose left to right.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;tail&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e[i]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;index — an element of an array, a slice, or a type implementing &lt;code&gt;Index&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e.name&lt;/code&gt;&lt;/td&gt;&lt;td&gt;select a field, or call a method&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e.0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;select a tuple’s part by position&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e(…)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Attr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a type’s attribute rather than a value’s — a constrained type’s bounds live here&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e?&lt;/code&gt;&lt;/td&gt;&lt;td&gt;try — unwrap or propagate&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;e++&lt;/code&gt;, &lt;code&gt;e--&lt;/code&gt;&lt;/td&gt;&lt;td&gt;post-increment, post-decrement&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A tuple index is a &lt;code&gt;Field&lt;/code&gt; selection because it &lt;em&gt;is&lt;/em&gt; one: a tuple’s fields are named for their
positions. Note that &lt;code&gt;t.0.1&lt;/code&gt; does not work, because the lexer reads &lt;code&gt;0.1&lt;/code&gt; as a float before it is two
indices — write &lt;code&gt;(t.0).1&lt;/code&gt;, which is what the diagnostic says.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;?&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Postfix on an &lt;code&gt;Option&lt;/code&gt; or a &lt;code&gt;Result&lt;/code&gt;, and sugar for the most common &lt;code&gt;match&lt;/code&gt;: &lt;strong&gt;unwrap the success,
or early-return the failure.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On a &lt;code&gt;Result&lt;/code&gt;: &lt;code&gt;Ok(v)&lt;/code&gt; evaluates to &lt;code&gt;v&lt;/code&gt;; &lt;code&gt;Err(e)&lt;/code&gt; returns &lt;code&gt;Err(e)&lt;/code&gt; from the enclosing function
immediately.&lt;/li&gt;
&lt;li&gt;On an &lt;code&gt;Option&lt;/code&gt;: &lt;code&gt;Some(v)&lt;/code&gt; evaluates to &lt;code&gt;v&lt;/code&gt;; &lt;code&gt;None&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt; immediately.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h = &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(h)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;])
    r &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
        &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ok 2
err odd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two rules make it well defined. &lt;strong&gt;The enclosing function’s return type must carry the failure&lt;/strong&gt; — a
&lt;code&gt;?&lt;/code&gt; on a &lt;code&gt;Result&lt;/code&gt; is legal only inside a function returning &lt;code&gt;Result&lt;/code&gt;, and on an &lt;code&gt;Option&lt;/code&gt; only inside
one returning &lt;code&gt;Option&lt;/code&gt;. The early return has to have somewhere to go, and the two channels do not
cross. And &lt;strong&gt;the error types must match exactly&lt;/strong&gt;; there is no implicit widening, so a function with
its own error type converts a callee’s explicitly.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; is an expression and composes as one, so its unwrapped value flows into whatever surrounds it.&lt;/p&gt;
&lt;h2 id=&quot;conversions-are-calls&quot;&gt;Conversions are calls&lt;/h2&gt;
&lt;p&gt;Every conversion is written, with call syntax, and none is inferred — the visible-cost rule the
memory model rests on applies to representation changes too.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;from → to&lt;/th&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;behaviour&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;integer → integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;u16(n)&lt;/code&gt;, &lt;code&gt;byte(n)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;truncates or extends; sign-extends only when the &lt;em&gt;source&lt;/em&gt; is signed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;integer → float&lt;/td&gt;&lt;td&gt;&lt;code&gt;real(n)&lt;/code&gt;, &lt;code&gt;f32(n)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;rounds to nearest; signed and unsigned sources differ&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;float → integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;int(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;truncates toward zero&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;float → float&lt;/td&gt;&lt;td&gt;&lt;code&gt;f32(x)&lt;/code&gt;, &lt;code&gt;real(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;rounds to nearest&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;char&lt;/code&gt; → integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;u32(c)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;total — every &lt;code&gt;char&lt;/code&gt; is an integer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;integer → &lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;char(u)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;partial&lt;/strong&gt; — traps on a value that is not a Unicode scalar value&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;char&lt;/code&gt; → &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string(c)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;total — the one character, UTF-8 encoded into a fresh string&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*T&lt;/code&gt; → integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;usize(p)&lt;/code&gt;, &lt;code&gt;isize(p)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;total — an address is a number&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-string&quot;&gt;&apos;A&apos;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt;(n), &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;(n), &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;(c), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.9&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;44 300 65 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Everything else is rejected. There is &lt;strong&gt;no conversion to or from &lt;code&gt;bool&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;int(true)&lt;/code&gt; is an error
and so is &lt;code&gt;bool(0)&lt;/code&gt; — and &lt;strong&gt;no number converts to or from a &lt;code&gt;string&lt;/code&gt;&lt;/strong&gt;: &lt;code&gt;str(x)&lt;/code&gt; renders one and the
&lt;code&gt;strconv&lt;/code&gt; surface parses one, neither of them spelled as a conversion. The &lt;code&gt;char&lt;/code&gt; → &lt;code&gt;string&lt;/code&gt; row is
the one exception, and a narrow one: a &lt;code&gt;char&lt;/code&gt; is a single scalar value, so encoding it is total and
has nothing to say about failure.&lt;/p&gt;
&lt;p&gt;The pointer row goes only one way. An address &lt;em&gt;is&lt;/em&gt; a number of &lt;code&gt;usize&lt;/code&gt;‘s width, so reading it as one
loses nothing and produces a value that cannot be dereferenced. The inverse is not a conversion at
all — making a pointer out of an integer is &lt;code&gt;ptr_cast&lt;/code&gt;, in the raw tier, spelled apart from this
table because it is where the language’s guarantees stop.&lt;/p&gt;
&lt;p&gt;Because these are calls, they parse as postfix at level 13 rather than as an operator of their own.
The name in front may be a &lt;strong&gt;type parameter&lt;/strong&gt;, and then the row is chosen at the instantiation.&lt;/p&gt;
&lt;h2 id=&quot;sizeof-alignof-and-offsetof&quot;&gt;&lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt; and &lt;code&gt;offsetof&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The three forms whose first operand is a &lt;strong&gt;type&lt;/strong&gt; rather than a value. All take parentheses, and all
yield a &lt;code&gt;usize&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 4 8 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They are read as their own grammar rather than left to look like calls, because a call’s arguments
are expressions and &lt;code&gt;sizeof(*Node)&lt;/code&gt; would otherwise parse as a dereference. There is no form that
takes a value — a value’s type is what would be measured anyway.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;offsetof&lt;/code&gt; takes a type and then a &lt;strong&gt;field name&lt;/strong&gt;, and answers where that field starts in bytes. The
name is a name and not an expression, for the same reason the type is not one: there is no value here
for a &lt;code&gt;p.x&lt;/code&gt; to select from.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Header&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    length: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;
    flags: &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Header&lt;/span&gt;, tag), &lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Header&lt;/span&gt;, length), &lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Header&lt;/span&gt;, flags), &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Header&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 4 8 12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The padding after &lt;code&gt;tag&lt;/code&gt; is what puts &lt;code&gt;length&lt;/code&gt; at 4 — &lt;code&gt;@packed&lt;/code&gt; lays the same fields end to end and
makes them 0, 1 and 5. Its use is
&lt;a href=&quot;/reference/attributes/#checking-a-c-struct-s-layout&quot;&gt;checking a mirrored C struct&lt;/a&gt;, where a size
alone cannot see two same-width fields transposed. A field the struct does not have is refused by
name, and so is a &lt;a href=&quot;/reference/attributes/#bitfields-an-in-field-in-exactly-n-bits&quot;&gt;bitfield&lt;/a&gt; — the
answer is in bytes, and a field starting at bit twelve is not at byte one.&lt;/p&gt;
&lt;h2 id=&quot;closures&quot;&gt;Closures&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;x -&amp;gt; x + 1&lt;/code&gt; is a closure literal. It sits at the top of the expression grammar, so its body extends
as far to the right as an expression can: that is a closure over the sum, not a closure over &lt;code&gt;x&lt;/code&gt;
added to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Parameters are one bare name, or a parenthesized list — including the empty list, which is the one
arity with nowhere else to be written. A type annotation goes inside the parentheses and nowhere
else, so there is no second spelling to disagree with the first.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: () -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() + &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; twice = &lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(() -&amp;gt; n)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; inc = (x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; x + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(twice, &lt;span class=&quot;hl-function&quot;&gt;inc&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;20 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A closure’s parameter declares &lt;strong&gt;no default&lt;/strong&gt;. A call reaches a closure through the &lt;code&gt;Fn&lt;/code&gt; traits,
which carry types and not names, so there would be nothing at the call to fill one from.&lt;/p&gt;
&lt;h3 id=&quot;a-parameter-with-the-name-left-out&quot;&gt;&lt;code&gt;_&lt;/code&gt; — a parameter with the name left out&lt;/h3&gt;
&lt;p&gt;A bare &lt;code&gt;_&lt;/code&gt; in operand position is a closure parameter, and the closure it builds closes at the
nearest of three boundaries: a parenthesized group, an argument, or a statement.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(_ + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(_ * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The group is what a program reaches for when the other two boundaries fall in the wrong place. But
it cuts both ways, and this is the one thing to know about the form: &lt;strong&gt;the closure closes at the
group, so anything outside the group applies to the closure itself&lt;/strong&gt;, not to what it computes.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;((_ + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this &apos;_&apos; has no type here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;(_ + 1) * 2&lt;/code&gt; multiplies a &lt;em&gt;closure&lt;/em&gt; by two rather than closing over the doubled sum — so nothing is
left to say what the placeholder’s parameter is, and the diagnostic points at the &lt;code&gt;_&lt;/code&gt;. When the
boundary is not where you want it, write the arrow form: &lt;code&gt;x -&amp;gt; (x + 1) * 2&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An interpolation hole is a boundary too, so a placeholder cannot reach out of a string to close over
the whole of one.&lt;/p&gt;
&lt;h2 id=&quot;string-interpolation&quot;&gt;String interpolation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;s&amp;quot;…&amp;quot;&lt;/code&gt; renders each &lt;code&gt;${…}&lt;/code&gt; hole through &lt;code&gt;str&lt;/code&gt; and concatenates: &lt;code&gt;s&amp;quot;a${e}b&amp;quot;&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; &lt;code&gt;&amp;quot;a&amp;quot; + str(e) + &amp;quot;b&amp;quot;&lt;/code&gt;,
with no runtime formatting machinery involved. &lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt; allows a printf specifier after a hole, and
routes that hole through &lt;code&gt;format&lt;/code&gt; instead, where the analyzer checks the specifier against the
value’s type.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;world&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;name&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n * &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;n&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%4d&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello world, 42
[   7]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The embedded source is parsed as an ordinary expression — so a hole may itself interpolate — and it
is parsed as its own little source, so a diagnostic inside a hole points into the hole rather than at
an unrelated column of the line the string sits on.&lt;/p&gt;
&lt;h2 id=&quot;operator-dispatch&quot;&gt;Operator dispatch&lt;/h2&gt;
&lt;p&gt;An operator expression is a &lt;strong&gt;trait-method call&lt;/strong&gt;, resolved by one rule in every context. For an
operator &lt;code&gt;⊕&lt;/code&gt; mapped to trait &lt;code&gt;Op&lt;/code&gt; with method &lt;code&gt;m&lt;/code&gt;, &lt;code&gt;a ⊕ b&lt;/code&gt; means &lt;code&gt;Op::m(a, b)&lt;/code&gt;, and it type-checks
exactly when &lt;code&gt;a&lt;/code&gt;‘s type satisfies &lt;code&gt;Op&lt;/code&gt; &lt;strong&gt;at &lt;code&gt;b&lt;/code&gt;‘s type&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;What differs between a scalar, a user type and a bounded type parameter is only &lt;em&gt;where the impl comes
from&lt;/em&gt; — never the rule:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A built-in scalar&lt;/strong&gt; satisfies the operator traits by a compiler-provided impl, and codegen keeps
emitting the native machine instruction. No call, no vtable. The membership exists so the type
system agrees a scalar satisfies &lt;code&gt;Add&lt;/code&gt;, which is what lets one be passed where &lt;code&gt;[T: Add]&lt;/code&gt; is wanted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A user type with &lt;code&gt;impl Op for S&lt;/code&gt;&lt;/strong&gt; lowers to the member the impl produced. Overloading an
operator &lt;em&gt;is&lt;/em&gt; implementing its trait; there is no separate operator-method syntax.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A bounded parameter &lt;code&gt;[T: Op]&lt;/code&gt;&lt;/strong&gt; resolves abstractly at the definition, and monomorphization binds
it per instantiation.&lt;/li&gt;
&lt;/ul&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;trait&lt;/th&gt;&lt;th&gt;method&lt;/th&gt;&lt;th&gt;operator&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Add&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;add&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Sub&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;sub&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt; (binary)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Mul&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;mul&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Div&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;div&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Rem&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;rem&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BitAnd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bitand&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; (binary)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BitOr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bitor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;\|&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BitXor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bitxor&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Shl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;shl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Shr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;shr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Neg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;neg&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&lt;/code&gt; (unary)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Not&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;not&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;~&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Eq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;eq&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;==&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Ord&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;lt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Index&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;index&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;e[i]&lt;/code&gt; read&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;IndexSet&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;index_set&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;e[i] = v&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, rhs: &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.x + rhs.x, &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.y + rhs.y)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) + &lt;span class=&quot;hl-type&quot;&gt;Vec2&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.x, v.y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;11 22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A type becomes fully comparable by implementing &lt;strong&gt;one&lt;/strong&gt; method, &lt;code&gt;lt&lt;/code&gt;, and fully equatable by
implementing &lt;strong&gt;one&lt;/strong&gt;, &lt;code&gt;eq&lt;/code&gt; — the compiler derives the rest: &lt;code&gt;a != b&lt;/code&gt; is &lt;code&gt;!eq(a, b)&lt;/code&gt;, &lt;code&gt;a &amp;gt; b&lt;/code&gt; is
&lt;code&gt;lt(b, a)&lt;/code&gt;, &lt;code&gt;a &amp;lt;= b&lt;/code&gt; is &lt;code&gt;!lt(b, a)&lt;/code&gt;, &lt;code&gt;a &amp;gt;= b&lt;/code&gt; is &lt;code&gt;!lt(a, b)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Two of those &lt;strong&gt;swap their operands&lt;/strong&gt;, and the swap is of the two &lt;em&gt;values&lt;/em&gt;, applied at the call — so
&lt;code&gt;a &amp;gt; b&lt;/code&gt; still evaluates &lt;code&gt;a&lt;/code&gt; before &lt;code&gt;b&lt;/code&gt;, and the derivation is invisible in evaluation order as well
as in the answer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; are &lt;strong&gt;independent&lt;/strong&gt; traits, not a hierarchy. That is the scalar law lifted intact:
&lt;code&gt;bool&lt;/code&gt; and the pointer modes have &lt;code&gt;==&lt;/code&gt; and no &lt;code&gt;&amp;lt;&lt;/code&gt;. There is no four-way &lt;code&gt;PartialEq&lt;/code&gt;/&lt;code&gt;Eq&lt;/code&gt;/&lt;code&gt;PartialOrd&lt;/code&gt;
/&lt;code&gt;Ord&lt;/code&gt; tower.&lt;/p&gt;
&lt;p&gt;The scalars do not go through those derivations — the compiler-provided impls supply all six
comparisons directly at IEEE semantics, which is what keeps &lt;code&gt;NaN &amp;lt;= 1.0&lt;/code&gt; and &lt;code&gt;NaN &amp;gt;= 1.0&lt;/code&gt; both false
where negating &lt;code&gt;lt&lt;/code&gt; would have made one true.&lt;/p&gt;
&lt;h3 id=&quot;a-simple-enum-is-eq-and-nothing-else&quot;&gt;A simple enum is &lt;code&gt;Eq&lt;/code&gt;, and nothing else&lt;/h3&gt;
&lt;p&gt;An enum whose variants all carry nothing is a &lt;strong&gt;simple&lt;/strong&gt; enum, and its value &lt;em&gt;is&lt;/em&gt; its discriminant.
There is exactly one thing equality on it could mean, so the compiler supplies it — the same rule
that makes every width of integer &lt;code&gt;Eq&lt;/code&gt; without a block being written per width:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Colorspace&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Linear&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;same&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt;](a: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = a == b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt; == &lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt; == &lt;span class=&quot;hl-type&quot;&gt;Linear&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;same&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Linear&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Linear&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The membership satisfies an &lt;code&gt;Eq&lt;/code&gt; &lt;strong&gt;bound&lt;/strong&gt;, as the second line shows, and not merely the &lt;code&gt;==&lt;/code&gt; token —
so a simple enum goes into anything written over &lt;code&gt;[T: Eq]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;Ord&lt;/code&gt;. Declaration order is an order and it is not a &lt;em&gt;meaning&lt;/em&gt;: &lt;code&gt;Srgb &amp;lt; Linear&lt;/code&gt; says
nothing anybody wants a language to assert on their behalf, so an enum whose order means something
writes the &lt;code&gt;impl&lt;/code&gt; that says so. It is not &lt;code&gt;Hash&lt;/code&gt; either, for the same reason — that is a promise
about a distribution, and a program makes it deliberately.&lt;/p&gt;
&lt;p&gt;An enum that &lt;strong&gt;carries data&lt;/strong&gt; is not a member. Comparing two of those means comparing their payloads,
which needs every payload type to be &lt;code&gt;Eq&lt;/code&gt; itself; that is an &lt;code&gt;impl&lt;/code&gt; a program writes, and
&lt;a href=&quot;/library/core/&quot;&gt;the core module&lt;/a&gt; shows the shape.&lt;/p&gt;
&lt;p&gt;Writing the block by hand for a simple one is refused rather than ignored, because the comparison is
emitted whatever the block says:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Colorspace&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Linear&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Colorspace&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;eq&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, rhs: &lt;span class=&quot;hl-type&quot;&gt;Colorspace&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) == &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(rhs)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt; == &lt;span class=&quot;hl-type&quot;&gt;Srgb&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Colorspace&apos; already implements &apos;sysl.Eq&apos; — no variant of it carries anything, so its value is its discriminant and &apos;==&apos; is that comparison. Delete the block; a variant that needs an equality of its own has to carry something for it to be about
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-the-token-set-is-closed&quot;&gt;Why the token set is closed&lt;/h3&gt;
&lt;p&gt;Overloading the fixed set is the bare-metal consensus: Rust, C++, D and Ada all allow it, Zig and C
allow no overloading at all, and &lt;strong&gt;none&lt;/strong&gt; permits a new operator token. Low-level code is read while
reasoning about hardware, and a mystery operator that is secretly a user function fights that — the
same visible-cost value the memory model rests on. A closed set also lexes by longest match against a
fixed list, with no operator “muncher” and no parser-vocabulary registration to keep in step.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/statements/&quot;&gt;statements and control flow&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Error handling</title>
    <link href="https://sysl.sh/tour/errors/"/>
    <id>https://sysl.sh/tour/errors/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Two channels — a failure you handle is a value, and a bug stops the program.</summary>
    <content type="html">&lt;p&gt;Failure travels on two separate channels in sysl, and choosing between them is a real decision at
every API rather than a coin toss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A recoverable failure is a value.&lt;/strong&gt; &lt;code&gt;Result[T, E]&lt;/code&gt; or &lt;code&gt;Option[T]&lt;/code&gt; in the return type, propagated
with &lt;code&gt;?&lt;/code&gt;. The caller has to engage with it, because it is part of the signature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A bug is a trap.&lt;/strong&gt; An index past the end, an invalid cast, a broken contract. Not a value, not
catchable, and it stops the program.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keeping them apart is what makes a signature honest. A function returning &lt;code&gt;Result[T, E]&lt;/code&gt; is telling
you it can fail in a way you handle; one returning plain &lt;code&gt;T&lt;/code&gt; is telling you the only way it “fails”
is if the program is already wrong.&lt;/p&gt;
&lt;p&gt;The line between them is one question: &lt;strong&gt;could correct calling code ever hit this?&lt;/strong&gt; If yes — the
input came from a file, a socket, or a person, or the operation legitimately may not succeed — it is
a &lt;code&gt;Result&lt;/code&gt;. If only a bug reaches it, it traps.&lt;/p&gt;
&lt;h2 id=&quot;result-and-option&quot;&gt;&lt;code&gt;Result&lt;/code&gt; and &lt;code&gt;Option&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Both are ordinary generic enums from the library, exactly as the &lt;a href=&quot;/tour/enums/&quot;&gt;previous
chapter&lt;/a&gt; described. &lt;code&gt;Option[T]&lt;/code&gt; is &lt;strong&gt;absence with no reason attached&lt;/strong&gt;; &lt;code&gt;Result[T, E]&lt;/code&gt;
is &lt;strong&gt;failure with a reason&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;half:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;half:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;half: 5
refused: odd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;E&lt;/code&gt; is whatever carries the reason — a string here, but usually an enum, so a caller can match on
what went wrong instead of reading it.&lt;/p&gt;
&lt;p&gt;Type arguments come from inference, including the cases with nothing to infer from at the call: a
bare &lt;code&gt;None&lt;/code&gt; takes its &lt;code&gt;T&lt;/code&gt; from context, and &lt;code&gt;Ok(n)&lt;/code&gt; inside a &lt;code&gt;Result[int, string]&lt;/code&gt;-returning function
takes its &lt;code&gt;E&lt;/code&gt; from the return type.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;?&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Matching every call gets old fast, and &lt;code&gt;?&lt;/code&gt; is sugar for the match you would have written: &lt;strong&gt;unwrap
the success, or early-return the failure.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h = &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(h)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;quarter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 -1 -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;Ok(v)&lt;/code&gt; becomes &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;Err(e)&lt;/code&gt; returns &lt;code&gt;Err(e)&lt;/code&gt; from the enclosing function
immediately. On an &lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Some(v)&lt;/code&gt; becomes &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    label: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    next: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;second_label&lt;/span&gt;(head: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; nx = head.next?

    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(nx.label)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tail: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; head: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(tail))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;second_label&lt;/span&gt;(head).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(none)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;second_label&lt;/span&gt;(tail).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(none)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;b
(none)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; is an expression, not a statement, so its unwrapped value flows straight into whatever surrounds
it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The two channels do not cross.&lt;/strong&gt; An &lt;code&gt;Option&lt;/code&gt;‘s &lt;code&gt;?&lt;/code&gt; cannot early-return from a &lt;code&gt;Result&lt;/code&gt;-returning
function, and the enclosing function’s return type has to be able to carry the failure at all — the
early return needs somewhere to go:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n)?&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;?&apos; may only be used in a function returning sysl.Result, not int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The error types must match &lt;strong&gt;exactly&lt;/strong&gt;, too. There is no implicit widening, so a function whose own
error type differs from a callee’s converts at the call site:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;
    code: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; IoError&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;AppError&lt;/span&gt;
    why: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; AppError&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;read_it&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;IoError&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;AppError&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;read_it&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_ok&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;?&apos; propagates a IoError error, but this function returns AppError
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is a real ergonomic cost, and it is the shipping behaviour rather than the end state: the
intended answer is a &lt;code&gt;From&lt;/code&gt;-style conversion, where &lt;code&gt;?&lt;/code&gt; converts the callee’s error to the caller’s
whenever a conversion trait connects the two, as Rust’s &lt;code&gt;?&lt;/code&gt; calls &lt;code&gt;From::from&lt;/code&gt;. Writing that trait is
possible today — &lt;code&gt;impl From[IoError] for AppError&lt;/code&gt; and &lt;code&gt;impl From[ParseError] for AppError&lt;/code&gt; are two
different argument lists, and a type may implement a parameterized trait once at each of them (see
the &lt;a href=&quot;/reference/traits/&quot;&gt;reference&lt;/a&gt;). What is left is teaching &lt;code&gt;?&lt;/code&gt; to look for one.&lt;/p&gt;
&lt;h2 id=&quot;the-combinators&quot;&gt;The combinators&lt;/h2&gt;
&lt;p&gt;The conveniences on both types are &lt;strong&gt;ordinary members in the library&lt;/strong&gt;, not compiler knowledge. The
total ones ask a question or supply a fallback:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, target: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;xs.len
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; xs[i] == target &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(i)

    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(data, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(data, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_none&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;fallback:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(data, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true
fallback: 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Result&lt;/code&gt; has the matching pair &lt;code&gt;is_ok()&lt;/code&gt; and &lt;code&gt;is_err()&lt;/code&gt;, plus &lt;code&gt;unwrap_err()&lt;/code&gt; for reaching the reason.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;forcing&lt;/strong&gt; ones hand over the payload and stop the program when there is none — &lt;code&gt;unwrap()&lt;/code&gt;, and
&lt;code&gt;expect(msg)&lt;/code&gt; which says why you thought there would be one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; got: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(got.&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(), got.&lt;span class=&quot;hl-function&quot;&gt;expect&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a value was put here two lines ago&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That these are written in sysl rather than built in is the part worth pausing on, because it is what
keeps “a bug stops the program” from meaning “the compiler has to know the name of every way to
stop”:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(v) -&amp;gt; v
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt;
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;panic: unwrap of a None value&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two things make that ordinary code. A diverging arm has a type — &lt;code&gt;never&lt;/code&gt; — so &lt;code&gt;exit(1)&lt;/code&gt; sits beside
&lt;code&gt;Some(v) -&amp;gt; v&lt;/code&gt; and the &lt;code&gt;match&lt;/code&gt; still has the payload’s type rather than a conflict. And the departure
itself is an &lt;code&gt;extern&lt;/code&gt;: the library declares &lt;code&gt;exit(code: int) -&amp;gt; never&lt;/code&gt;, so stopping is a call.&lt;/p&gt;
&lt;h2 id=&quot;defer-releasing-what-arc-does-not&quot;&gt;&lt;code&gt;defer&lt;/code&gt; — releasing what ARC does not&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; has a consequence worth facing directly: it makes leaving early the &lt;strong&gt;normal&lt;/strong&gt; way out of a
function. That is fine for everything ARC owns — a &lt;code&gt;&amp;amp;T&lt;/code&gt;, a string, a slice’s backing all go back on
their own — and it is a problem for everything else. A file descriptor from &lt;code&gt;open&lt;/code&gt;, a block from
&lt;code&gt;malloc&lt;/code&gt;, a lock taken from a mutex: those are released by hand, and a function with four exits has
four places to remember.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;defer &amp;lt;statement&amp;gt;&lt;/code&gt; runs that statement on the way out of the block containing it, so the release is
written &lt;strong&gt;beside the call that took the resource&lt;/strong&gt;, once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;acquire&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cannot acquire&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;step&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd step&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h = &lt;span class=&quot;hl-function&quot;&gt;acquire&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;released&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, h)

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;step&lt;/span&gt;(h)?

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;finished with&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_ok&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;is_ok&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;finished with 40
released 4
true
released 3
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both exits ran it. &lt;code&gt;run(4)&lt;/code&gt; fell off the end and &lt;code&gt;run(3)&lt;/code&gt; left through the &lt;code&gt;?&lt;/code&gt; in the middle, and
neither one had to say so — which is the entire point, because the second exit is the one a program
forgets.&lt;/p&gt;
&lt;p&gt;Two rules make it predictable. &lt;strong&gt;Several in one block run last-registered-first&lt;/strong&gt;, so they undo in
the reverse of the order they were set up. And &lt;strong&gt;a &lt;code&gt;defer&lt;/code&gt; runs only if control reached it&lt;/strong&gt;: it is a
statement, not a declaration, so one below an early return never registered at all. In the program
above, a failure from &lt;code&gt;acquire&lt;/code&gt; returns before the &lt;code&gt;defer&lt;/code&gt; line, and nothing is released — correctly,
since nothing was acquired.&lt;/p&gt;
&lt;p&gt;The scope is the &lt;strong&gt;block&lt;/strong&gt;, not the function, and a loop is where that shows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, i)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, i)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;open 0
close 0
open 1
close 1
done
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go runs its &lt;code&gt;defer&lt;/code&gt; at function exit, so the same loop would hold two resources to the end and
release both at once — which is how a loop over ten thousand files runs out of descriptors. Here each
iteration is a block and each closes its own.&lt;/p&gt;
&lt;p&gt;One thing &lt;code&gt;defer&lt;/code&gt; is not: a &lt;code&gt;finally&lt;/code&gt;. &lt;strong&gt;A trap runs nothing.&lt;/strong&gt; A broken invariant means the
program’s model of itself is already wrong, and cleanup run against that state is how a corrupt
program writes its corruption out. &lt;code&gt;defer&lt;/code&gt; releases a resource; it does not rescue a bug — which is
the subject of the rest of this page.&lt;/p&gt;
&lt;h2 id=&quot;traps&quot;&gt;Traps&lt;/h2&gt;
&lt;p&gt;The other channel. A trap is the runtime response to a broken invariant, and what it does is settled:
&lt;strong&gt;it aborts.&lt;/strong&gt; No unwinding, no stack cleanup, no &lt;code&gt;catch&lt;/code&gt;, no exceptions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program compiles and then stops when it runs, because the bounds check fails. There is no
handler that could have caught it and no &lt;code&gt;defer&lt;/code&gt; that runs on the way down — &lt;code&gt;defer&lt;/code&gt; is a scope-exit
form, and a trap is not an exit. It is the program stopping because its model of itself is already
wrong, and cleanup code run against that state is how a corrupt program writes its corruption out.&lt;/p&gt;
&lt;p&gt;The trap sources are the runtime safety checks the safe subset rests on: an out-of-bounds index, an
inverted or out-of-range slice range, a checked cast that fails, an integer divide by zero, and a
violated &lt;code&gt;require&lt;/code&gt;/&lt;code&gt;ensure&lt;/code&gt; contract.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integer overflow is not one of them&lt;/strong&gt;, which is worth saying because Rust traps on it in a debug
build. Arithmetic wraps at the declared width, as &lt;a href=&quot;/tour/values/&quot;&gt;values&lt;/a&gt; showed — that is defined
behaviour rather than a broken invariant, so there is nothing for a trap to report.&lt;/p&gt;
&lt;p&gt;Two reasons abort is the only defensible choice here. A kernel and an embedded target have &lt;strong&gt;no
unwinding runtime&lt;/strong&gt; — landing pads, a personality routine and per-frame cleanup tables are exactly
what a freestanding target does not have. And an abort is one code path, where unwinding is a second,
invisible control-flow graph that every function in the program would have to be correct under.&lt;/p&gt;
&lt;p&gt;What a trap &lt;em&gt;does&lt;/em&gt; is an environment fact rather than a language one. A hosted program prints a
diagnostic and exits non-zero; a kernel installs its own panic handler and enters that. The decision
to stop is the language’s; the action on stopping is the environment’s.&lt;/p&gt;
&lt;h2 id=&quot;turning-a-trap-back-into-a-value&quot;&gt;Turning a trap back into a value&lt;/h2&gt;
&lt;p&gt;There is no &lt;code&gt;panic&lt;/code&gt; you can recover from, so a program that wants to survive bad input must &lt;strong&gt;not do
the trapping thing&lt;/strong&gt; — check the bound, validate before dividing, and use the fallible constructor
rather than the checked cast. That is the move to make wherever untrusted input enters:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;try&lt;/span&gt;(b) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(c) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(c)
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;byte &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(b) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; is not a Color&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(c)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(c))
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(c)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(c))
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;read: Green
byte 9 is not a Color
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Color(9)&lt;/code&gt; would have trapped. &lt;code&gt;Color.try(9)&lt;/code&gt; hands back a &lt;code&gt;None&lt;/code&gt; that this function turns into a
reason, and the byte off the wire stops being a bug in the program and starts being a value it
handles — which is the whole of the policy in one function.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-absent&quot;&gt;What is deliberately absent&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No exceptions.&lt;/strong&gt; Recoverable failure is a returned value and a bug is an abort. There is no
third, invisible control-flow channel.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No error return codes by convention.&lt;/strong&gt; The failure is in the type and it is checked, not an
&lt;code&gt;int&lt;/code&gt; a caller might forget to inspect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No panic that unwinds.&lt;/strong&gt; A trap is terminal.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;and-the-memory-model&quot;&gt;&lt;code&gt;?&lt;/code&gt; and the memory model&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; obeys ARC with no special rule, which matters most here because it is the operator most likely to
carry a heap payload across a function boundary.&lt;/p&gt;
&lt;p&gt;Unwrapping a &lt;code&gt;&amp;amp;T&lt;/code&gt; success payload retains it past the wrapper, so the reference outlives the &lt;code&gt;Result&lt;/code&gt;
it came out of and is released exactly once. Propagating a &lt;code&gt;&amp;amp;T&lt;/code&gt; error payload moves it through the
early return with its count intact.&lt;/p&gt;
&lt;p&gt;Neither is a rule about &lt;code&gt;?&lt;/code&gt;. Both fall out of retain-on-alias and release-at-scope-end — and they are
worth naming because a hand-rolled C error return leaks or double-frees at exactly these two
boundaries.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/traits/&quot;&gt;traits and generics&lt;/a&gt; — one implementation over many types, and what a bound is
really promising.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Errors, traps and contracts</title>
    <link href="https://sysl.sh/reference/errors/"/>
    <id>https://sysl.sh/reference/errors/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Two channels for failure — a value you handle and a stop you cannot — plus the constrained types, invariants and contracts that decide which one you get.</summary>
    <content type="html">&lt;p&gt;Failure travels on &lt;strong&gt;two separate channels&lt;/strong&gt;, and which one a given failure uses is a design decision
at every API rather than a coin toss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A recoverable failure is a value.&lt;/strong&gt; &lt;code&gt;Result[T, E]&lt;/code&gt; or &lt;code&gt;Option[T]&lt;/code&gt; in the return type, propagated
with &lt;a href=&quot;/reference/expressions/&quot;&gt;&lt;code&gt;?&lt;/code&gt;&lt;/a&gt;. It is part of the signature, so the caller has to engage
with it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A bug is a trap.&lt;/strong&gt; An index past the end, an invalid cast, a broken contract. Not a value, not
catchable, and the program stops.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keeping them apart is what makes a signature honest. A function returning &lt;code&gt;Result[T, E]&lt;/code&gt; is telling
you it can fail in a way you handle; one returning plain &lt;code&gt;T&lt;/code&gt; is telling you the only way it “fails”
is if the program is already wrong.&lt;/p&gt;
&lt;p&gt;This page covers both channels and then the three features that &lt;em&gt;create&lt;/em&gt; the second one —
constrained types, struct invariants, and function contracts — because a &lt;code&gt;within&lt;/code&gt; range and a
&lt;code&gt;require&lt;/code&gt; clause are only interesting once you know what happens when they are false.&lt;/p&gt;
&lt;h2 id=&quot;which-channel-the-policy&quot;&gt;Which channel — the policy&lt;/h2&gt;
&lt;p&gt;One question decides it: &lt;strong&gt;could correct calling code ever hit this?&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;answer&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt; — an expected outcome of valid use&lt;/td&gt;&lt;td&gt;&lt;code&gt;Result&lt;/code&gt; / &lt;code&gt;Option&lt;/code&gt;&lt;/td&gt;&lt;td&gt;The input came from outside the program — a file, a socket, a person — or the operation legitimately may not succeed. A correct caller still meets this case, so the type must force it to be handled.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt; — only a bug reaches it&lt;/td&gt;&lt;td&gt;a trap&lt;/td&gt;&lt;td&gt;Indexing past the end, converting an out-of-range integer to a &lt;code&gt;char&lt;/code&gt;, dividing by zero, violating a &lt;code&gt;require&lt;/code&gt;. A correct program never does these; reaching one means the program is already wrong.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The payoff of the split is that signatures stay clean — no &lt;code&gt;Result&lt;/code&gt; smeared across functions that
cannot meaningfully fail — while the failures that &lt;em&gt;are&lt;/em&gt; real are impossible to ignore, because they
are in the type.&lt;/p&gt;
&lt;h2 id=&quot;option-t-and-result-t-e&quot;&gt;&lt;code&gt;Option[T]&lt;/code&gt; and &lt;code&gt;Result[T, E]&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Both are &lt;strong&gt;ordinary generic enums declared in the standard library&lt;/strong&gt;, with no compiler privileges:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enum Option[T]                 enum Result[T, E]
    Some(value: T)                 Ok(value: T)
    None                           Err(error: E)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Option[T]&lt;/code&gt; is absence&lt;/strong&gt; — a value that may or may not be there, with no reason attached: a
missing key, the &lt;code&gt;next&lt;/code&gt; of a list tail, the result of a search. It is also what a
&lt;a href=&quot;/reference/memory/&quot;&gt;&lt;code&gt;weak&lt;/code&gt; reference&lt;/a&gt; degrades to, and what a fallible constructor like
&lt;code&gt;char.try&lt;/code&gt; answers with.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Result[T, E]&lt;/code&gt; is failure with a reason&lt;/strong&gt; — parsing, I/O, validation. &lt;code&gt;E&lt;/code&gt; is whatever carries the
reason: a string, an error enum, a &lt;code&gt;&amp;amp;Fail&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are constructed and taken apart like any enum, and their type arguments come from inference —
including the two cases with nothing to infer from at the call. A bare &lt;code&gt;None&lt;/code&gt; takes its &lt;code&gt;T&lt;/code&gt; from
context, and an &lt;code&gt;Ok(n)&lt;/code&gt; inside a &lt;code&gt;Result[int, string]&lt;/code&gt;-returning function takes its &lt;code&gt;E&lt;/code&gt; from the
return type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;first_even&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(x)

    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;half:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;half:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;refused:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;first_even&lt;/span&gt;(data).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;half: 5
refused: odd
8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;E&lt;/code&gt; is usually an enum rather than a string, so a caller can match on &lt;em&gt;what&lt;/em&gt; went wrong instead of
reading a sentence about it.&lt;/p&gt;
&lt;h3 id=&quot;the-members&quot;&gt;The members&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;total&lt;/strong&gt; ones ask a question or supply a fallback. None of them can stop the program:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;on &lt;code&gt;Option[T]&lt;/code&gt;&lt;/th&gt;&lt;th&gt;on &lt;code&gt;Result[T, E]&lt;/code&gt;&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;is_some()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;is_ok()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; when the value is there&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;is_none()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;is_err()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; when it is not&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unwrap_or(default)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;unwrap_or(default)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the payload, or &lt;code&gt;default&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The &lt;strong&gt;forcing&lt;/strong&gt; ones hand over the payload and stop the program when there is none:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;on &lt;code&gt;Option[T]&lt;/code&gt;&lt;/th&gt;&lt;th&gt;on &lt;code&gt;Result[T, E]&lt;/code&gt;&lt;/th&gt;&lt;th&gt;stops when&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unwrap()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;unwrap()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;None&lt;/code&gt; / &lt;code&gt;Err&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;expect(msg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;expect(msg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;None&lt;/code&gt; / &lt;code&gt;Err&lt;/code&gt;, printing &lt;code&gt;msg&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;&lt;code&gt;unwrap_err()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ok&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;—&lt;/td&gt;&lt;td&gt;&lt;code&gt;expect_err(msg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Ok&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; got: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad: &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(got.&lt;span class=&quot;hl-function&quot;&gt;is_some&lt;/span&gt;(), got.&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), got.&lt;span class=&quot;hl-function&quot;&gt;expect&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;put here two lines ago&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(bad.&lt;span class=&quot;hl-function&quot;&gt;is_err&lt;/span&gt;(), bad.&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), bad.&lt;span class=&quot;hl-function&quot;&gt;unwrap_err&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true 7 7
true -1 no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;unwrap_err&lt;/code&gt; is &lt;code&gt;Result&lt;/code&gt;‘s alone because &lt;code&gt;Option&lt;/code&gt;‘s empty case carries nothing to hand back.&lt;/p&gt;
&lt;h3 id=&quot;they-are-written-in-sysl-and-that-is-the-point&quot;&gt;They are written in sysl, and that is the point&lt;/h3&gt;
&lt;p&gt;The forcing members stop the program without any compiler support of their own:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(v) -&amp;gt; v
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt;
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;panic: unwrap of a None value&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is what keeps “a bug stops the program” from meaning “the compiler must know the name of every
way to stop”. Two ordinary features make it work. A diverging arm has a type — &lt;a href=&quot;/reference/types/&quot;&gt;&lt;code&gt;never&lt;/code&gt;&lt;/a&gt;
— so &lt;code&gt;exit(1)&lt;/code&gt; sits beside &lt;code&gt;Some(v) -&amp;gt; v&lt;/code&gt; and the &lt;code&gt;match&lt;/code&gt; still has the payload’s type rather than a
conflict between &lt;code&gt;T&lt;/code&gt; and nothing. And the departure itself is an &lt;code&gt;extern&lt;/code&gt;: the library declares
&lt;code&gt;exit(code: int) -&amp;gt; never&lt;/code&gt;, so stopping is a call.&lt;/p&gt;
&lt;p&gt;Nothing here costs a program that does not use it. The enums are generic, so a member exists only
where a call asks for one, and an &lt;code&gt;extern&lt;/code&gt; nothing reaches is never declared in the output.&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;?&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/reference/expressions/&quot;&gt;expressions page&lt;/a&gt; gives &lt;code&gt;?&lt;/code&gt; its place in the grammar — postfix, at
the tightest level, alongside &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;()&lt;/code&gt;. Its rules in full:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a &lt;code&gt;Result&lt;/code&gt;,&lt;/strong&gt; &lt;code&gt;Ok(v)&lt;/code&gt; evaluates to &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;Err(e)&lt;/code&gt; returns &lt;code&gt;Err(e)&lt;/code&gt; from the enclosing function
immediately. &lt;strong&gt;On an &lt;code&gt;Option&lt;/code&gt;,&lt;/strong&gt; &lt;code&gt;Some(v)&lt;/code&gt; evaluates to &lt;code&gt;v&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt; immediately.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The enclosing function’s return type must be able to carry the failure.&lt;/strong&gt; The early return has to
have somewhere to go:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n)?&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;?&apos; may only be used in a function returning sysl.Result, not int
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The two channels do not cross.&lt;/strong&gt; An &lt;code&gt;Option&lt;/code&gt;‘s &lt;code&gt;?&lt;/code&gt; cannot early-return from a &lt;code&gt;Result&lt;/code&gt;-returning
function, and the diagnostic names the type it wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;cross&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;?&apos; may only be used in a function returning sysl.Option, not sysl.Result[int, string]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The error types must match exactly.&lt;/strong&gt; There is no implicit widening, so a function with an error
type of its own converts a callee’s explicitly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fail&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Bad&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(n / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;other&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Fail&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(n)?

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;?&apos; propagates a string error, but this function returns Fail
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last rule is the shipping behaviour rather than the end state, and its ergonomic cost is real: a
program with its own &lt;code&gt;AppError&lt;/code&gt; cannot &lt;code&gt;?&lt;/code&gt;-propagate a library’s &lt;code&gt;IoError&lt;/code&gt; without a manual step at
each call. The eventual answer is a &lt;code&gt;From&lt;/code&gt;-style conversion inserted by &lt;code&gt;?&lt;/code&gt;, which is designed and
waiting on something else — a type implements a trait &lt;strong&gt;once&lt;/strong&gt;, so an &lt;code&gt;AppError&lt;/code&gt; cannot be
&lt;code&gt;From[IoError]&lt;/code&gt; and &lt;code&gt;From[ParseError]&lt;/code&gt; both, and lifting that needs a way for a use to say which
implementation it means. The conversion is additive: turning it on later invalidates no exact-match
&lt;code&gt;?&lt;/code&gt; written before it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;?&lt;/code&gt; is an expression&lt;/strong&gt;, so its unwrapped value flows straight into whatever surrounds it — &lt;code&gt;Ok(mk()?)&lt;/code&gt;
is ordinary, and a chain of hops is written as a sequence of &lt;code&gt;?&lt;/code&gt;-bound locals.&lt;/p&gt;
&lt;h3 id=&quot;and-the-memory-model&quot;&gt;&lt;code&gt;?&lt;/code&gt; and the memory model&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;?&lt;/code&gt; obeys &lt;a href=&quot;/reference/memory/&quot;&gt;ARC&lt;/a&gt; with no special rule, and this is where that
discipline is load-bearing, because &lt;code&gt;?&lt;/code&gt; is the operator most likely to carry a heap payload across a
function boundary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Unwrapping a &lt;code&gt;&amp;amp;T&lt;/code&gt; success payload retains it past the wrapper&lt;/strong&gt;, so the reference outlives the
&lt;code&gt;Result&lt;/code&gt; it came out of and is released exactly once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;mk&lt;/span&gt;(ok: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; ok &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;use&lt;/span&gt;(ok: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-function&quot;&gt;mk&lt;/span&gt;(ok)?

    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(p.x + p.y)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;use&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;use&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Propagating a &lt;code&gt;&amp;amp;T&lt;/code&gt; error payload moves it through the early return&lt;/strong&gt; with its count intact, freed
exactly once on whichever path consumes it.&lt;/p&gt;
&lt;p&gt;Neither is a rule about &lt;code&gt;?&lt;/code&gt;. Both fall out of retain-on-alias and release-at-scope-end, and they are
named here because a hand-rolled C error return leaks or double-frees at exactly these two
boundaries.&lt;/p&gt;
&lt;h2 id=&quot;traps&quot;&gt;Traps&lt;/h2&gt;
&lt;p&gt;The other channel. A trap is the runtime response to a &lt;strong&gt;broken invariant&lt;/strong&gt;, and its semantics are
settled:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trap aborts.&lt;/strong&gt; There is no unwinding, no stack cleanup, no &lt;code&gt;catch&lt;/code&gt;, no exceptions. When a check
fails the program stops; it does not run destructors up the stack, and it cannot be intercepted and
resumed.&lt;/p&gt;
&lt;p&gt;Two reasons this is the only defensible choice for the language’s targets. &lt;strong&gt;A kernel and an embedded
target have no unwinding runtime&lt;/strong&gt; — landing pads, a personality routine and per-frame cleanup tables
are exactly the machinery a freestanding &lt;code&gt;no alloc&lt;/code&gt; target does not have and does not want, and an
abort needs none of it. And &lt;strong&gt;determinism&lt;/strong&gt;: an abort is one code path, where unwinding is a second,
invisible control-flow graph that every function in the program would have to be correct under.
Removing it removes the whole “is this exception-safe?” class of reasoning, which is the same
simplification the memory model makes by having no move semantics.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nor does a trap run a deferred statement.&lt;/strong&gt; &lt;a href=&quot;/reference/statements/#defer&quot;&gt;&lt;code&gt;defer&lt;/code&gt;&lt;/a&gt; is the
language’s scope-exit form, and a trap is not an exit — it is the program stopping because its model
of itself is already wrong. Cleanup code run against that state is how a corrupt program writes its
corruption out on the way down. So &lt;code&gt;defer&lt;/code&gt; is for releasing a resource, not for restoring an
invariant.&lt;/p&gt;
&lt;h3 id=&quot;what-traps&quot;&gt;What traps&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;source&lt;/th&gt;&lt;th&gt;example&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;an out-of-bounds array or slice index&lt;/td&gt;&lt;td&gt;&lt;code&gt;xs[5]&lt;/code&gt; on a &lt;code&gt;[3]int&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an inverted or out-of-range slice range&lt;/td&gt;&lt;td&gt;&lt;code&gt;xs[3..1]&lt;/code&gt;, &lt;code&gt;xs[0..9]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a checked cast that fails&lt;/td&gt;&lt;td&gt;&lt;code&gt;char(u)&lt;/code&gt; on an invalid scalar, &lt;code&gt;Color(n)&lt;/code&gt; on an undeclared discriminant&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an integer divide by zero&lt;/td&gt;&lt;td&gt;&lt;code&gt;n / 0&lt;/code&gt;, &lt;code&gt;n % 0&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a violated &lt;code&gt;require&lt;/code&gt; or &lt;code&gt;ensure&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a violated struct &lt;code&gt;invariant&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a violated &lt;code&gt;within&lt;/code&gt; range or &lt;code&gt;where&lt;/code&gt; predicate, at a produce site&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Succ&lt;/code&gt; past &lt;code&gt;T::Last&lt;/code&gt;, &lt;code&gt;T::Pred&lt;/code&gt; below &lt;code&gt;T::First&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;overflow of &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt; where an operand came through a ranged type&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Integer overflow is otherwise not a trap source&lt;/strong&gt;, which is worth saying because Rust traps on it
in a debug build. Plain arithmetic &lt;a href=&quot;/reference/types/&quot;&gt;wraps at the declared width&lt;/a&gt;, so
overflow is defined behaviour rather than a broken invariant and there is nothing for a trap to
report. The last row of the table is the narrow exception, and it belongs to constrained types rather
than to arithmetic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No build option removes any of these.&lt;/strong&gt; There is no &lt;code&gt;--no-contracts&lt;/code&gt;, no bounds-check stripping, no
&lt;code&gt;NDEBUG&lt;/code&gt;. A check that is in the language is in every build, because a switch that removed one would
make a program’s meaning depend on how it was compiled.&lt;/p&gt;
&lt;h3 id=&quot;what-stopping-looks-like&quot;&gt;What stopping looks like&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;decision&lt;/em&gt; to stop is the language’s; the &lt;em&gt;action&lt;/em&gt; on stopping is the environment’s. Under the
&lt;code&gt;os&lt;/code&gt; capability a hosted program stops the process and exits non-zero; a kernel installs its own
panic handler and enters that.&lt;/p&gt;
&lt;p&gt;On a hosted target there are two observably different shapes, and the difference is worth knowing
before you debug one:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;stopped by&lt;/th&gt;&lt;th&gt;what you see&lt;/th&gt;&lt;th&gt;exit status&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;compiler-inserted check&lt;/strong&gt; — a bound, a cast, a range, a contract&lt;/td&gt;&lt;td&gt;nothing at all, and &lt;strong&gt;buffered output already written by the program is lost&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;the platform’s signal status for a trap instruction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;strong&gt;library forcing member&lt;/strong&gt; — &lt;code&gt;unwrap&lt;/code&gt;, &lt;code&gt;expect&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;panic: &amp;lt;message&amp;gt;&lt;/code&gt; on stdout, after everything the program printed before it&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The library’s route goes through &lt;code&gt;exit&lt;/code&gt;, which flushes on its way out; a compiler check goes straight
to the target’s trap instruction, which does not. So a program that printed diagnostics right up to
the failing line will appear to have printed &lt;strong&gt;none&lt;/strong&gt; of them if a bounds check is what stopped it.
Reconciling the two so that every stop says why it stopped is an open question in the design.&lt;/p&gt;
&lt;h2 id=&quot;turning-a-trap-back-into-a-value&quot;&gt;Turning a trap back into a value&lt;/h2&gt;
&lt;p&gt;There is no &lt;code&gt;panic&lt;/code&gt; you can recover from, so a program that must survive bad input has to &lt;strong&gt;not do
the trapping thing&lt;/strong&gt;: check the bound, validate before dividing, and use the fallible constructor
rather than the checked cast. That is the move to make wherever untrusted input enters, and it is
where a bug turns back into a value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(b: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Result&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;]
    &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;try&lt;/span&gt;(b) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(c) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(c)
        &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;byte &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(b) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; is not a Color&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(c)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(c))
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(c)  -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;read:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(c))
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;read: Green
byte 9 is not a Color
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Color(9)&lt;/code&gt; would have trapped. &lt;code&gt;Color.try(9)&lt;/code&gt; hands back a &lt;code&gt;None&lt;/code&gt; this function turns into a reason,
and the byte off the wire stops being a bug in the program and starts being a value it handles.&lt;/p&gt;
&lt;p&gt;For a constrained type the equivalent is &lt;code&gt;T::Valid&lt;/code&gt;, below.&lt;/p&gt;
&lt;h2 id=&quot;constrained-types&quot;&gt;Constrained types&lt;/h2&gt;
&lt;p&gt;One declaration form with three independent parts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;type Name = [new] Base [within lo..hi] [where predicate]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;new&lt;/code&gt;, &lt;code&gt;within&lt;/code&gt; and &lt;code&gt;where&lt;/code&gt; are &lt;strong&gt;contextual keywords&lt;/strong&gt; — ordinary identifiers everywhere else, so a
field, a function or a variable may still be called &lt;code&gt;where&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cfg&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;where&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = n * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Cfg&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;, c.&lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 4 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each of the three parts may be left out, with one exception:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;means&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type Meters = new f64&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a distinct type over &lt;code&gt;f64&lt;/code&gt;, no constraint&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type Age = int within 0..150&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt; with a range, but the &lt;em&gt;same type&lt;/em&gt; as &lt;code&gt;int&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type Even = int where value % 2 == 0&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;int&lt;/code&gt; with a predicate&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type Slot = new u8 within 0..&amp;lt;200&lt;/code&gt;&lt;/td&gt;&lt;td&gt;distinct &lt;strong&gt;and&lt;/strong&gt; constrained&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;type Alias = int&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;rejected&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The last row is the exception. A transparent alias with no constraint declares nothing — it neither
narrows the values nor makes a new type — so writing it can only be a mistake or an attempt at a
&lt;code&gt;typedef&lt;/code&gt; of one’s own, which is not a thing to write here:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Alias&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;Alias&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Alias&apos; has no constraint — add a &apos;within&apos; range or a &apos;where&apos; predicate, or &apos;new&apos; to make it a distinct type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that &lt;code&gt;type Name = Existing&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; legal as a &lt;a href=&quot;/reference/declarations/#type-declarations&quot;&gt;type alias&lt;/a&gt;
for a name that has grown long; what is refused is calling that a constrained type by adding nothing
to it. The diagnostic is what tells the two apart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The base must be a scalar&lt;/strong&gt; — an integer, a float, or a &lt;code&gt;char&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bad&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Bad&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a constrained subtype&apos;s base must be an integer, a float, or &apos;char&apos;, not Point
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A constraint here is a check on a &lt;em&gt;value&lt;/em&gt;. The two ways to narrow an aggregate are the struct
invariant below and, for an enum, having fewer variants.&lt;/p&gt;
&lt;h3 id=&quot;ranges&quot;&gt;Ranges&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;..&lt;/code&gt; includes the upper bound and &lt;code&gt;..&amp;lt;&lt;/code&gt; excludes it, matching the
&lt;a href=&quot;/reference/expressions/#ranges&quot;&gt;range expressions&lt;/a&gt;. A bound is a &lt;strong&gt;constant expression&lt;/strong&gt; — a
literal, a &lt;code&gt;const&lt;/code&gt;, or arithmetic over them, folded through the same path an array length and an enum
discriminant go through, so the three positions accept the same expressions and cannot drift apart:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; max_tasks: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;max_tasks
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Trimmed&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..max_tasks - &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t: &lt;span class=&quot;hl-type&quot;&gt;Task&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; u: &lt;span class=&quot;hl-type&quot;&gt;Trimmed&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t, u)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is one fact written once: &lt;code&gt;within 0..&amp;lt;max_tasks&lt;/code&gt; beside &lt;code&gt;[max_tasks]Task&lt;/code&gt;. What a bound may not
be is &lt;strong&gt;non-constant&lt;/strong&gt; — a module-level &lt;code&gt;val&lt;/code&gt; is read-only storage with an address rather than a
constant, and is refused here.&lt;/p&gt;
&lt;p&gt;Two shapes are rejected at the declaration. A bound outside the base’s own range:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Big&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;300&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Big&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the bound 300 does not fit byte
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And an inverted range:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inverted&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;Inverted&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;the lower bound of &apos;Inverted&apos; is above its upper bound
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;predicates&quot;&gt;Predicates&lt;/h3&gt;
&lt;p&gt;The predicate is an ordinary boolean expression, and the value it is about is named &lt;strong&gt;&lt;code&gt;value&lt;/code&gt;&lt;/strong&gt;,
bound only inside the predicate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Even&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt; value % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;HexDigit&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt; value &amp;gt;= &lt;span class=&quot;hl-string&quot;&gt;&apos;0&apos;&lt;/span&gt; &amp;amp;&amp;amp; value &amp;lt;= &lt;span class=&quot;hl-string&quot;&gt;&apos;9&apos;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; e: &lt;span class=&quot;hl-type&quot;&gt;Even&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h: &lt;span class=&quot;hl-type&quot;&gt;HexDigit&lt;/span&gt; = &lt;span class=&quot;hl-string&quot;&gt;&apos;7&apos;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e, h)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A predicate may read module constants, which is what lets a range and a table’s size be stated once.
Where both a range and a predicate are written, &lt;strong&gt;the range is checked first&lt;/strong&gt;, so a value the range
rejects never reaches the predicate.&lt;/p&gt;
&lt;p&gt;A non-boolean predicate is reported against the type, without leaking the name of the function the
compiler synthesised to hold it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Odd&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt; value + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o: &lt;span class=&quot;hl-type&quot;&gt;Odd&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(o)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;where&apos; predicate must be a &apos;bool&apos;, but this one is int
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;new-is-what-makes-it-a-type&quot;&gt;&lt;code&gt;new&lt;/code&gt; is what makes it a type&lt;/h3&gt;
&lt;p&gt;Without &lt;code&gt;new&lt;/code&gt;, a constrained type &lt;strong&gt;is&lt;/strong&gt; its base with a checked range. &lt;code&gt;Age&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt; are the same
type, values flow between them in both directions with no cast, and what the declaration buys is the
check:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;birthday&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = a + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;birthday&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With &lt;code&gt;new&lt;/code&gt; it is a &lt;strong&gt;distinct nominal type&lt;/strong&gt;, and that is the whole of the difference. Two derived
types over one base do not mix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Feet&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;) + &lt;span class=&quot;hl-type&quot;&gt;Feet&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got Meters and Feet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A derived type does not mix with its &lt;strong&gt;base&lt;/strong&gt; either, and no position excuses it — an initializer, an
argument and a returned value each refuse it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q: &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(q))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;cannot initialize &apos;q&apos;: declared Meters but the value is real
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Going in either direction is a &lt;strong&gt;written conversion&lt;/strong&gt;: &lt;code&gt;Meters(x)&lt;/code&gt; wraps, &lt;code&gt;f64(m)&lt;/code&gt; unwraps, and the
wrap is where the constraint is checked.&lt;/p&gt;
&lt;p&gt;The payoff is a specific bug. A table-driven program has several small integers that index different
things — a task number, a lock number, a priority level — and the mistake such a program actually
makes is passing one where another was wanted. Three &lt;code&gt;new u8&lt;/code&gt;s with three ranges make that a compile
error rather than a plausible-looking wrong answer. &lt;strong&gt;It is an argument about types, not about
checking.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;a-derivation-inherits-its-base-s-behaviour-and-may-replace-none-of-it&quot;&gt;A derivation inherits its base’s behaviour and may replace none of it&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;new&lt;/code&gt; type over a scalar arrives with &lt;strong&gt;everything the scalar could do&lt;/strong&gt; — the arithmetic
operators, the remainder, the bitwise operators and the shifts, unary &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;~&lt;/code&gt;, the comparisons,
the compound assignments, &lt;code&gt;++&lt;/code&gt; and &lt;code&gt;--&lt;/code&gt;, and &lt;code&gt;str&lt;/code&gt; — working at itself and producing itself.&lt;/p&gt;
&lt;p&gt;And no &lt;code&gt;impl&lt;/code&gt; may replace or extend any of it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Span&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Add&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Span&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, other: &lt;span class=&quot;hl-type&quot;&gt;Span&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) + &lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;(other))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;add&apos; is how &apos;Add&apos; is implemented for Stamp, and the compiler provides that — a member of this name would hide it
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Span&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Span&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Span&apos; already implements &apos;sysl.Display&apos; — every &apos;sysl.Integer&apos; does, through one block written over the family, and a subtype has its base&apos;s memberships
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two refusals arrive by different routes, which the messages say. &lt;code&gt;Add&lt;/code&gt; is a membership the
&lt;strong&gt;compiler&lt;/strong&gt; provides, so a member of that name would hide something with no block behind it.
&lt;code&gt;Display&lt;/code&gt; is an ordinary &lt;code&gt;impl&lt;/code&gt; the &lt;strong&gt;library&lt;/strong&gt; writes — one blanket block covering every integer —
and a derivation has its base’s memberships, so the block covers &lt;code&gt;Span&lt;/code&gt; too.&lt;/p&gt;
&lt;p&gt;Both halves are deliberate. &lt;strong&gt;Inheriting is right&lt;/strong&gt; because a derivation does not change what the
values &lt;em&gt;are&lt;/em&gt;: a &lt;code&gt;Slot&lt;/code&gt; is some of the &lt;code&gt;u8&lt;/code&gt;s, not a different set of things that happens to be stored
in a byte. A derivation that started with nothing would make every &lt;code&gt;new u8&lt;/code&gt; cost a dozen &lt;code&gt;impl&lt;/code&gt;
blocks, and nobody would use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Refusing to replace is the harder call, and it is a ruling.&lt;/strong&gt; If &lt;code&gt;Stamp&lt;/code&gt; could redefine &lt;code&gt;&amp;lt;&lt;/code&gt;, then
&lt;code&gt;Stamp&lt;/code&gt; would be a set of &lt;code&gt;i64&lt;/code&gt;s that do not order the way &lt;code&gt;i64&lt;/code&gt;s order, and every fact the base
guarantees would hold only until somebody looked. A derivation is a &lt;em&gt;narrowing&lt;/em&gt;, and a narrowing that
alters behaviour is not a narrowing.&lt;/p&gt;
&lt;p&gt;So the answer to “I want my own &lt;code&gt;+&lt;/code&gt;“ is that you do not want a derivation, you want a &lt;strong&gt;struct&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;except-rendering-which-a-derivation-may-take-back&quot;&gt;Except rendering, which a derivation may take back&lt;/h3&gt;
&lt;p&gt;The second refusal above is the &lt;em&gt;unmarked&lt;/em&gt; one, and that is the whole of what it refuses. Say
&lt;a href=&quot;/reference/traits/#override-when-the-overlap-is-deliberate&quot;&gt;&lt;code&gt;override&lt;/code&gt;&lt;/a&gt; and the block is yours:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)), out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Stamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;#7
7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The line is what the base guarantees about its values.&lt;/strong&gt; Ordering is such a guarantee — that is the
&lt;code&gt;&amp;lt;&lt;/code&gt; argument above, and it still stands. How a value &lt;em&gt;renders&lt;/em&gt; is not: a &lt;code&gt;Stamp&lt;/code&gt; printing as &lt;code&gt;#7&lt;/code&gt; is
the same &lt;code&gt;i64&lt;/code&gt; it always was, and nothing downstream reasons about it differently. So rendering is
the one row a derivation may replace, and the operators are not.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;a &lt;code&gt;new&lt;/code&gt; derivation&lt;/th&gt;&lt;th&gt;a one-field struct&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;distinct type&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the base’s catalogue&lt;/td&gt;&lt;td&gt;free; only &lt;code&gt;Display&lt;/code&gt; is replaceable&lt;/td&gt;&lt;td&gt;nothing, write it all&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an operation the base does not have&lt;/td&gt;&lt;td&gt;impossible&lt;/td&gt;&lt;td&gt;ordinary&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an operation the base has that is now nonsense&lt;/td&gt;&lt;td&gt;present anyway&lt;/td&gt;&lt;td&gt;absent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;rendering as something other than the base&lt;/td&gt;&lt;td&gt;&lt;code&gt;override impl Display&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ordinary&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Use a derivation for an identity&lt;/strong&gt; — a slot number, a handle, a unit-tagged measurement, anything
whose operations are its representation’s operations. &lt;strong&gt;Use a struct for a quantity with an algebra
of its own&lt;/strong&gt;: an instant plus a duration is an instant, an instant plus an instant is nonsense, and
no derived scalar can be told the difference. The cost is real and was measured — a date-and-time
library written this way needs one-field structs and five &lt;code&gt;impl&lt;/code&gt; blocks per type.&lt;/p&gt;
&lt;p&gt;What has no answer today is the case in the middle: a type that wants most of its base’s catalogue
and one row of its own. &lt;code&gt;impl Add[Duration] for Instant&lt;/code&gt; takes something the base could never have
taken and touches no guarantee of &lt;code&gt;i64&lt;/code&gt;‘s, but it is refused because the check is on the method
&lt;em&gt;name&lt;/em&gt;, and &lt;code&gt;add&lt;/code&gt; is taken.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A subtype narrows which values a type has, never which operations it has&lt;/strong&gt; — so what the base does
not have, the subtype does not either, and the diagnostic names the subtype rather than the base:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;neg&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = -s&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;unary &apos;-&apos; is not defined for the unsigned type Slot
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ratio&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;flip&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;Ratio&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Ratio&lt;/span&gt; = ~r&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;unary &apos;~&apos; is not defined for Ratio
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-operations-are-the-base-s-their-overflow-is-not&quot;&gt;The operations are the base’s; their overflow is not&lt;/h3&gt;
&lt;p&gt;Raw integer arithmetic wraps, and a wrapped result reaching a produce site is a wrong answer the
range check can pass without noticing. On a &lt;code&gt;Slot = u8 within 0..&amp;lt;200&lt;/code&gt;, &lt;code&gt;Slot(150) + Slot(150)&lt;/code&gt; is
300, which wraps to 44 — which is in range.&lt;/p&gt;
&lt;p&gt;So &lt;strong&gt;where an operand came through a &lt;code&gt;within&lt;/code&gt; type and the operands’ declared ranges permit a result
the base width cannot hold, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt; and &lt;code&gt;*&lt;/code&gt; are overflow-detecting and trap.&lt;/strong&gt; A range narrow enough
that its results always fit stays on the plain instruction, so a counter, an index and an &lt;code&gt;x + 1&lt;/code&gt;
cost exactly what they did before. A left shift is checked on its own terms — it has no overflow
intrinsic, so a bit pushed out of the top is caught by shifting back, and a shift amount at or past
the width traps rather than being undefined. Arithmetic on a type with &lt;strong&gt;no&lt;/strong&gt; range still wraps.&lt;/p&gt;
&lt;p&gt;For a &lt;strong&gt;transparent&lt;/strong&gt; subtype the arithmetic happens at the base and yields a base value, so a
literal beside one is an ordinary base value and what has to be in range is only what is stored:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s: &lt;span class=&quot;hl-type&quot;&gt;Small&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(s * &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;200
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The multiplier is not a &lt;code&gt;Small&lt;/code&gt; and does not have to be. A &lt;strong&gt;derived&lt;/strong&gt; subtype is its own
representation, so it mixes with the base only through the cast above, and its results are its own
and are checked where they are produced.&lt;/p&gt;
&lt;h3 id=&quot;where-a-constraint-is-checked&quot;&gt;Where a constraint is checked&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;At every point a value of the constrained type is produced, and nowhere else.&lt;/strong&gt; That is not a list
of syntactic forms to memorize: a value comes to have the type wherever it &lt;strong&gt;flows into a slot the
type is written on&lt;/strong&gt;, plus wherever an operation of the type’s own &lt;strong&gt;yields one&lt;/strong&gt;. The slots are
enumerable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a variable’s initializer, and every later assignment to it — including one arm of a
multi-assignment, and &lt;strong&gt;a write through a pointer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;an argument at a call, and a function’s returned value — a plain function’s, a method’s, a nested
function’s, or a closure’s&lt;/li&gt;
&lt;li&gt;an explicit cast, &lt;code&gt;T(x)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a field written into a struct, at construction and at every later write, however the struct is
reached&lt;/li&gt;
&lt;li&gt;an element of an array, at a literal and at every later write, through the array or through a view
of it&lt;/li&gt;
&lt;li&gt;a part of a tuple, and the payload of an enum variant&lt;/li&gt;
&lt;li&gt;an item entering a &lt;strong&gt;generic&lt;/strong&gt; container instantiated at the type — the slot is written &lt;code&gt;T&lt;/code&gt; there,
so the check follows the type &lt;em&gt;argument&lt;/em&gt; and not the spelling&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; slot: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(a)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;a

&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p = &lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, slot.&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;41 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the two sites that are the type’s own doing rather than a slot’s:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;an operation on a derived subtype&lt;/strong&gt;, which gets the base’s catalogue &lt;em&gt;producing itself&lt;/em&gt; — so
&lt;code&gt;Slot(199) + Slot(1)&lt;/code&gt; is a produce site and traps. A &lt;strong&gt;transparent&lt;/strong&gt; subtype has no such site: its
arithmetic happens at its base and yields a base value, checked by the store that gives it the
subtype again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a compound assignment and an increment&lt;/strong&gt;, which compute and store in one step and so are checked
between the two. &lt;code&gt;a += e&lt;/code&gt; produces exactly what &lt;code&gt;a = a + e&lt;/code&gt; produces: what the operator is applied
to is a base value either way, so &lt;code&gt;t += 120&lt;/code&gt; on a &lt;code&gt;Temp = int within -100..100&lt;/code&gt; holding &lt;code&gt;-50&lt;/code&gt; is
&lt;code&gt;70&lt;/code&gt;, and not a complaint that 120 is no temperature.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A value that &lt;strong&gt;already has&lt;/strong&gt; the type is not re-checked when it is merely read, passed along, or
copied — it could not have got there unchecked. Passing one to a &lt;em&gt;different&lt;/em&gt; subtype over the same
base &lt;strong&gt;is&lt;/strong&gt; a produce site and is checked again, which is what keeps a wider type from leaking into a
narrower one.&lt;/p&gt;
&lt;h3 id=&quot;a-constrained-type-has-no-zero-value&quot;&gt;A constrained type has no zero value&lt;/h3&gt;
&lt;p&gt;The one site that is closed by not existing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;Age has no zero value, so &apos;a&apos; needs an initial value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That holds whether or not the range contains zero. Making it the &lt;strong&gt;type’s&lt;/strong&gt; rule rather than the
range’s means widening a range never silently changes whether a declaration compiles somewhere else.&lt;/p&gt;
&lt;h3 id=&quot;a-violated-check-traps-and-there-is-no-try&quot;&gt;A violated check traps, and there is no &lt;code&gt;try&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;It is not an error value and it is not catchable. A constrained type states something its values
&lt;em&gt;are&lt;/em&gt;, so a value that is not one of them is a bug in the code that made it rather than a condition
to handle — which means the fallible constructor an enum has is deliberately absent here, and the
diagnostic says so by name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;try&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Age&apos; is a constrained type and has no &apos;try&apos;: a value outside its range is a mistake in the code that produced it rather than a condition to handle, so &apos;Age(x)&apos; checks it and traps, and &apos;Age::Valid(x)&apos; asks the question without trapping
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-the-type-s-own-name-offers-attributes&quot;&gt;What the type’s own name offers: &lt;code&gt;::&lt;/code&gt; attributes&lt;/h2&gt;
&lt;p&gt;A constrained type’s name is a type and not a value, so nothing is &lt;em&gt;read&lt;/em&gt; from it. What it answers
are &lt;strong&gt;attributes&lt;/strong&gt;, written with &lt;code&gt;::&lt;/code&gt; rather than &lt;code&gt;.&lt;/code&gt; so they stay out of the member namespace:
&lt;code&gt;Age::First&lt;/code&gt; cannot be confused with a field, a property or an associated function, and no &lt;code&gt;impl&lt;/code&gt; can
shadow one by declaring a member of that name.&lt;/p&gt;
&lt;p&gt;The set is small and closed, and every member of it is a question about &lt;strong&gt;integer bounds&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;th&gt;notes&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::First&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the lower bound&lt;/td&gt;&lt;td&gt;a &lt;code&gt;T&lt;/code&gt;, a constant, no argument&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Last&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the upper bound&lt;/td&gt;&lt;td&gt;a &lt;code&gt;T&lt;/code&gt;; one &lt;em&gt;below&lt;/em&gt; the written bound where the range is exclusive&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Valid(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;whether &lt;code&gt;x&lt;/code&gt; is in range&lt;/td&gt;&lt;td&gt;takes the &lt;strong&gt;base&lt;/strong&gt;; a &lt;code&gt;bool&lt;/code&gt;, and &lt;strong&gt;total&lt;/strong&gt; — it never traps&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Succ(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the next value&lt;/td&gt;&lt;td&gt;a &lt;code&gt;T&lt;/code&gt; from a &lt;code&gt;T&lt;/code&gt;; traps at &lt;code&gt;T::Last&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Pred(x)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the previous value&lt;/td&gt;&lt;td&gt;a &lt;code&gt;T&lt;/code&gt; from a &lt;code&gt;T&lt;/code&gt;; traps at &lt;code&gt;T::First&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Range&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the range itself&lt;/td&gt;&lt;td&gt;only as a &lt;code&gt;for&lt;/code&gt; loop’s iterable, &lt;code&gt;First..Last&lt;/code&gt; inclusive, the variable a &lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Min&lt;/code&gt; / &lt;code&gt;T::Max&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same two numbers&lt;/td&gt;&lt;td&gt;the &lt;em&gt;magnitude&lt;/em&gt; question, which agrees with the ordinal one here — see below&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Min&lt;/code&gt;/&lt;code&gt;Max&lt;/code&gt; are not aliases of &lt;code&gt;First&lt;/code&gt;/&lt;code&gt;Last&lt;/code&gt;, and the reason matters where the two come apart.&lt;/strong&gt;
&lt;code&gt;First&lt;/code&gt; and &lt;code&gt;Last&lt;/code&gt; name the ends of a &lt;em&gt;declared sequence&lt;/em&gt;; &lt;code&gt;Min&lt;/code&gt; and &lt;code&gt;Max&lt;/code&gt; the extremes a type can
hold. A &lt;code&gt;within&lt;/code&gt; range is written in order, so both questions have the same answer here and both are
offered — refusing &lt;code&gt;Min&lt;/code&gt; on the one kind of type whose whole purpose is bounds would be the odd
outcome, and a reader who met &lt;code&gt;Min&lt;/code&gt; on &lt;code&gt;u32&lt;/code&gt; should not find it renamed on a subtype of &lt;code&gt;u32&lt;/code&gt;. A
&lt;strong&gt;simple enum answers only &lt;code&gt;First&lt;/code&gt;/&lt;code&gt;Last&lt;/code&gt;&lt;/strong&gt;, because that is where they diverge: discriminants may be
explicit and non-contiguous, so the first-declared variant need not carry the smallest one. An
&lt;strong&gt;integer type answers only &lt;code&gt;Min&lt;/code&gt;/&lt;code&gt;Max&lt;/code&gt;&lt;/strong&gt;, on the &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; page.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Last&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Valid&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Valid&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Succ&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Pred&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; k &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Range&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(k))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sum of every slot:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 7 true false
4 2
sum of every slot: 28
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every attribute but &lt;code&gt;Valid&lt;/code&gt; speaks the subtype.&lt;/strong&gt; A bound of &lt;code&gt;T&lt;/code&gt; is a value of &lt;code&gt;T&lt;/code&gt;, the step from
one &lt;code&gt;T&lt;/code&gt; is another, and the values &lt;code&gt;Range&lt;/code&gt; walks are &lt;code&gt;T&lt;/code&gt;s. That is invisible on a transparent
subtype, where &lt;code&gt;T&lt;/code&gt; and its base agree anyway — it is what makes the set usable on a &lt;strong&gt;derived&lt;/strong&gt; one,
which would otherwise be the only kind of type whose own attributes had to be cast back into it. A
&lt;code&gt;new&lt;/code&gt; subtype exists to stay out of its base’s traffic, and an attribute surface that handed back the
base would make its own declaration the thing you had to undo to use it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Valid&lt;/code&gt; is the exception, and the asymmetry is its job.&lt;/strong&gt; It takes the base, because asking whether
a value is a &lt;code&gt;T&lt;/code&gt; is only a question about something that is not one yet. Handed a &lt;code&gt;T&lt;/code&gt; it is refused,
since the answer could only be yes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Valid&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Slot::Valid&apos; takes a byte, not Slot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The numbers it can be asked about are therefore the ones the &lt;strong&gt;base&lt;/strong&gt; can hold, so a subtype over a
&lt;code&gt;u8&lt;/code&gt; cannot be asked about &lt;code&gt;-1&lt;/code&gt;. That is not a narrowing of the question; it is the base’s range being
what a base is.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Valid&lt;/code&gt; is the answer to “how do I ask instead of trapping”. A produce site traps because a value
outside the range is a mistake and not a condition; &lt;code&gt;Valid&lt;/code&gt; is how a program holding a number it has
not vetted puts the question, and a cast after a &lt;code&gt;Valid&lt;/code&gt; that answered true is the ordinary way in.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Succ&lt;/code&gt; and &lt;code&gt;Pred&lt;/code&gt; &lt;strong&gt;trap&lt;/strong&gt; rather than saturating or wrapping, on the same argument: a step past the
end is not a value of the type, so making one is the mistake, and no single answer would be right for
every caller.&lt;/p&gt;
&lt;p&gt;Two shapes are refused. &lt;code&gt;Range&lt;/code&gt; is meaningful only where an iterable is — it names nothing a program
can hold, because a range is not yet a type a program can name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Range&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Slot::Range&apos; is only meaningful as the iterable of a &apos;for&apos; loop
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a subtype over a &lt;strong&gt;float&lt;/strong&gt; or a &lt;code&gt;char&lt;/code&gt;, or one written with &lt;strong&gt;no range&lt;/strong&gt;, has no attributes at
all — each of these is a question about integer bounds, and there are none to ask about. The
diagnostic names the part that would have to change:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ratio&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ratio&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Ratio::First&apos; needs an integer subtype, not real
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Plain&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Plain&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Last&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Plain::Last&apos; needs a &apos;within&apos; range
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;struct-invariants&quot;&gt;Struct invariants&lt;/h2&gt;
&lt;p&gt;A struct body may carry &lt;code&gt;invariant &amp;lt;bool&amp;gt;&lt;/code&gt; clauses among its fields. The clause is an expression over
the struct’s own fields, in scope by name, and several clauses all have to hold — each checked
independently, so the diagnostic names the one that failed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;
    lo: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    hi: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; lo &amp;lt;= hi
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; hi - lo &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4096&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w = &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

w.hi += &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.lo, w.hi, w.hi - w.lo)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 15 13
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An invariant may read a module constant. &lt;code&gt;invariant&lt;/code&gt; is contextual here too, and the grammar
disambiguates by shape: a &lt;strong&gt;member&lt;/strong&gt; declaration has a parameter list or a &lt;code&gt;-&amp;gt;&lt;/code&gt;, an &lt;strong&gt;invariant
clause&lt;/strong&gt; is the word followed by an expression, and anything else is a &lt;strong&gt;field&lt;/strong&gt; — so a field may
still be named &lt;code&gt;invariant&lt;/code&gt;, as the &lt;code&gt;Cfg&lt;/code&gt; example above showed, since &lt;code&gt;invariant: int&lt;/code&gt; matches neither
of the first two.&lt;/p&gt;
&lt;h3 id=&quot;checked-at-every-write-not-only-at-construction&quot;&gt;Checked at every write, not only at construction&lt;/h3&gt;
&lt;p&gt;That is the part worth stating, because the cheap implementation checks the constructor and calls it
done. The obligation covers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;constructing the struct, including one built directly as an argument or as a returned value&lt;/li&gt;
&lt;li&gt;assigning a whole struct over an existing one&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;assigning a single field&lt;/strong&gt;, including a compound assignment (&lt;code&gt;w.hi += 1&lt;/code&gt;) and an increment
(&lt;code&gt;w.hi++&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;a field written through a pointer&lt;/li&gt;
&lt;li&gt;a field written into an array element&lt;/li&gt;
&lt;li&gt;a field written &lt;strong&gt;inside&lt;/strong&gt; one of these — &lt;code&gt;o.a.n = 9&lt;/code&gt;, or &lt;code&gt;g.items[0].n = 9&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is owed for a reason a narrow reading misses. A clause may read &lt;em&gt;through&lt;/em&gt; a field:
&lt;code&gt;invariant a.n &amp;lt;= b&lt;/code&gt; is legal, and &lt;code&gt;a.n&lt;/code&gt; is then not a field of the struct at all, so the write that
breaks it is a write the struct never sees. The obligation is therefore on &lt;strong&gt;every struct a place is
written inside&lt;/strong&gt;, not only on the one whose field is named last, and the checks nest
innermost-first — so the smallest struct the write broke is the one that stops it. An index locates a
place rather than owning one, so it contributes no check and is walked through.&lt;/p&gt;
&lt;p&gt;The consequence is the intended one: &lt;strong&gt;a sequence of writes that ends in a valid state but passes
through an invalid one traps at the step that broke it.&lt;/strong&gt; There is no “I am mid-update” mode.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;/reference/expressions/#assignment&quot;&gt;multiple assignment&lt;/a&gt; is the exception that proves it — it
lands both writes before either invariant is consulted, so a pair that ends legal is legal even where
each half alone would not be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;
    lo: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    hi: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; lo &amp;lt;= hi

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w = &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

w.lo, w.hi = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.lo, w.hi)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pair that needs it is the one that crosses: &lt;code&gt;w.lo = 12&lt;/code&gt; followed by &lt;code&gt;w.hi = 14&lt;/code&gt; traps at the
first write, because 12 is briefly above the 10 still in &lt;code&gt;hi&lt;/code&gt;. &lt;code&gt;w.lo, w.hi = 12, 14&lt;/code&gt; does not, and
the two writes land on a struct that was legal before and is legal after.&lt;/p&gt;
&lt;h3 id=&quot;when-a-struct-cannot-be-updated-one-field-at-a-time&quot;&gt;When a struct cannot be updated one field at a time&lt;/h3&gt;
&lt;p&gt;Three answers, and the order matters, because the last one is the expensive one and it is the one
reached for first:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Look for an order in which no intermediate state is illegal&lt;/strong&gt;, and often there is one. A
&lt;code&gt;count &amp;lt;= high&lt;/code&gt; watermark is updated by raising the ceiling before the floor, and needs nothing
else; the same two writes in the other order are refused. That the same clause accepts one order
and refuses the other is the whole of the answer here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ask whether the clause is pointing at a redundant field.&lt;/strong&gt; An invariant relating two fields is a
claim about the &lt;em&gt;representation&lt;/em&gt;, and the trap is often the compiler observing that the struct
carries one fact twice. A ring buffer keeping &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; cannot move any two of
them one at a time; one keeping &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; and computing the end has no clause to break,
because nothing is left to disagree. Two of the three fields is the honest design either way.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Otherwise assign the whole struct&lt;/strong&gt;, which is what whole-struct assignment is for — and know the
price. &lt;code&gt;*self = Ring(self.buf, …)&lt;/code&gt; restates the &lt;em&gt;whole&lt;/em&gt; value to move two bytes, so an invariant
across two fields makes a container’s own update cost the size of the container. For a buffer,
that is its entire storage, per element.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-may-be-aliased&quot;&gt;What may be aliased&lt;/h3&gt;
&lt;p&gt;Everything above is discharged by walking outward through the &lt;strong&gt;place&lt;/strong&gt; being written, so the whole
obligation rests on the place still naming the struct. A pointer is where that runs out — inside a
function taking a &lt;code&gt;*Inner&lt;/code&gt;, there is no &lt;code&gt;Outer&lt;/code&gt; to re-read and no way to learn there ever was one.&lt;/p&gt;
&lt;p&gt;It is therefore a rule about &lt;strong&gt;what may be aliased&lt;/strong&gt;, and it restricts alias &lt;em&gt;creation&lt;/em&gt;, which is
local and a question about types, rather than alias &lt;em&gt;use&lt;/em&gt;, which would need the borrow checker sysl
does not have. Four parts, and &lt;strong&gt;none of them applies to a program that declares no invariants&lt;/strong&gt; —
each is a question asked about a clause, and there is no clause to ask about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A pointer that would be typed below a clause is refused where it is made:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; a.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o = &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;o.a

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(bad.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;&amp;amp;&apos; here makes a &apos;*Inner&apos; pointing inside Outer, whose invariant reads &apos;a.n&apos; — and a &apos;*Inner&apos; names no Outer, so a write through it would break the clause with nothing left to re-check it against. Take the address of the Outer itself, which keeps the invariant in its type, or make the change through a method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A writable view is the same licence to write by another spelling&lt;/strong&gt;, and is refused the same way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Group&lt;/span&gt;
    items: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; items[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;].n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g = &lt;span class=&quot;hl-type&quot;&gt;Group&lt;/span&gt;([&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)])
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; view = g.items[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(view.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this view may be written, and it views storage inside Group, whose invariant reads &apos;items.n&apos; — a &apos;[]Inner&apos; names no Group, so a write through it would break the clause with nothing left to re-check it against. Take it as a &apos;[]const Inner&apos;, which may not write, or make the change through a method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;[]const T&lt;/code&gt; is ordinary, since giving up the write is exactly what makes a view carry no promise it
could break. So is &lt;code&gt;&amp;amp;o&lt;/code&gt; itself, whose &lt;code&gt;*Outer&lt;/code&gt; names the struct and is checked by the ordinary walk.
And so is a pointer to a field &lt;strong&gt;no clause mentions&lt;/strong&gt; — the refusal is about the clause, not about
the struct:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    c: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; a.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o = &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cp = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;o.c

&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;cp = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(o.a.n, o.c)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A mutating method call on such a field is allowed, and re-checks the clause when it returns.&lt;/strong&gt;
&lt;code&gt;o.a.set(4)&lt;/code&gt; hands &lt;code&gt;set&lt;/code&gt; the same severed &lt;code&gt;*Inner&lt;/code&gt; — and it is allowed because the &lt;em&gt;call site&lt;/em&gt; still
knows the whole place: &lt;code&gt;o&lt;/code&gt; is right there, so the clause is re-run the moment the call returns:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n = v

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; a.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; o = &lt;span class=&quot;hl-type&quot;&gt;Outer&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))

o.a.&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(o.a.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since there are no parameter modes, a receiver is the only way a callee is handed somewhere to write
without an &lt;code&gt;&amp;amp;&lt;/code&gt; in the caller’s own source — which is why this one channel is worth keeping open, and
why keeping it open costs a mutating method nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;*self&lt;/code&gt; method may not let a pointer into its receiver outlive the call.&lt;/strong&gt; That is what makes the
paragraph above sound: a &lt;code&gt;set&lt;/code&gt; that returned &lt;code&gt;&amp;amp;self.n&lt;/code&gt; would hand out the severed alias by a route no
&lt;code&gt;&amp;amp;&lt;/code&gt; in the caller spells:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;leak&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Holder&lt;/span&gt;
    c: &lt;span class=&quot;hl-type&quot;&gt;Cell&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; c.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;*self&apos; method may not let a pointer into the receiver&apos;s own storage outlive the call, and this one is returned — the receiver may be a field of a struct whose invariant reads it, and a pointer that gets out is somewhere to write that names no such struct. Hand back a copy of the value, or an index into it, and let the caller reach the storage through the receiver it already has
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The check is local to the body, and it is asked only of methods whose struct can &lt;em&gt;be&lt;/em&gt; a field of one
carrying clauses — a struct that lies inside nothing can never have a severed receiver, so its
methods are left alone. Storage on the far side of a reference or a view is not the receiver’s to
lose either, so &lt;code&gt;&amp;amp;self.bytes[0]&lt;/code&gt; where &lt;code&gt;bytes&lt;/code&gt; is a &lt;code&gt;[]u8&lt;/code&gt; field is ordinary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A clause may only read storage the struct owns.&lt;/strong&gt; All of the above is a rule about aliases of the
struct’s own bytes, so a clause reading through a pointer, a reference, or a view’s &lt;em&gt;elements&lt;/em&gt; is
refused where it is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ptr&lt;/span&gt;
    p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Inner&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; p.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an invariant may only read storage the struct owns, and &apos;n&apos; is read through *Inner — what is on the far side has an identity of its own, so another alias of it could break the clause with nothing left to re-check it against. Hold the value in a field of the struct, and state the invariant over that
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A view’s &lt;code&gt;len&lt;/code&gt; is on the near side — the three words are stored in the struct — and may be read.&lt;/p&gt;
&lt;p&gt;What none of this does is make a &lt;code&gt;*T&lt;/code&gt; safe, and it does not try to. A pointer handed to a &lt;em&gt;third&lt;/em&gt;
function that stores it is out of reach of a local check, exactly as the
&lt;a href=&quot;/reference/memory/&quot;&gt;memory model&lt;/a&gt; says every guarantee about a raw pointer is. What the
rule buys is that the &lt;strong&gt;silent&lt;/strong&gt; severing — the one that looks like ordinary code, reads like
ordinary code, and leaves a clause quietly false — is refused.&lt;/p&gt;
&lt;h3 id=&quot;generic-structs&quot;&gt;Generic structs&lt;/h3&gt;
&lt;p&gt;Invariants on a generic struct are not supported, and say so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Gen&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;invariants on generic structs are not supported yet — &apos;Gen&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The open question is what a clause over a field of type &lt;code&gt;T&lt;/code&gt; could even mean when nothing about &lt;code&gt;T&lt;/code&gt; is
known. Most useful invariants compare, which needs a bound — and a bound the &lt;em&gt;struct&lt;/em&gt; carries is
inherited by every member, so the machinery is there.&lt;/p&gt;
&lt;h2 id=&quot;contracts-on-a-function&quot;&gt;Contracts on a function&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; x &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a half of a negative is not what this means&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; result &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    x / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;require&lt;/code&gt; is checked &lt;strong&gt;on entry&lt;/strong&gt;. &lt;code&gt;ensure&lt;/code&gt; is checked &lt;strong&gt;before every return&lt;/strong&gt;, including early
ones — an early &lt;code&gt;return&lt;/code&gt; that violates the postcondition traps exactly as the fall-through path
would. Both take an optional message after a comma.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Both kinds form one block at the top of the body.&lt;/strong&gt; A clause of either kind after an ordinary
statement is rejected — a precondition that runs after some of the work is not a precondition, and a
postcondition is &lt;em&gt;written&lt;/em&gt; with them because that is where a reader looks for what the function
promises, not because that is when it runs. Clauses may not be nested inside an inner block either:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; y = x + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; y &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    y&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;require&apos;/&apos;ensure&apos; clauses must come before any other statement in a function body
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;result-and-old&quot;&gt;&lt;code&gt;result&lt;/code&gt; and &lt;code&gt;old&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Two names exist only inside a contract.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;result&lt;/code&gt;&lt;/strong&gt; is the value being returned, available in an &lt;code&gt;ensure&lt;/code&gt; only. It is rejected in a
&lt;code&gt;require&lt;/code&gt; — there is no value yet — in an ordinary statement, and in the &lt;code&gt;ensure&lt;/code&gt; of a function that
returns nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; result &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    x&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;result&apos; is only meaningful inside an &apos;ensure&apos; of a value-returning function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A local actually named &lt;code&gt;result&lt;/code&gt; shadows it, which is the ordinary scoping rule rather than a special
case:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;triple&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; result &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; result = n * &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

    result

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;triple&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;old(expr)&lt;/code&gt;&lt;/strong&gt; is &lt;code&gt;expr&lt;/code&gt; evaluated &lt;strong&gt;on entry&lt;/strong&gt;, available in an &lt;code&gt;ensure&lt;/code&gt; only. It takes exactly one
argument, and several &lt;code&gt;old&lt;/code&gt; snapshots in one function are independent of each other. This is what
lets a postcondition talk about what a mutating function &lt;em&gt;changed&lt;/em&gt; rather than only about what it
left behind:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    m: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n &amp;gt; &lt;span class=&quot;hl-function&quot;&gt;old&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n) &amp;amp;&amp;amp; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.m &amp;gt; &lt;span class=&quot;hl-function&quot;&gt;old&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.m)

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.m += &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

c.&lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;()
c.&lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.n, c.m)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Contracts work the same on a &lt;strong&gt;method&lt;/strong&gt;, including one with a &lt;code&gt;*self&lt;/code&gt; receiver, where they are at
their most useful: &lt;code&gt;ensure result &amp;gt; old(self.n)&lt;/code&gt; on a mutating method says the thing the method is
&lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Like a constraint, a violated contract &lt;strong&gt;traps&lt;/strong&gt;, and contracts are checked in &lt;strong&gt;every&lt;/strong&gt; build. There
is no release mode that drops them, and adding one would make a program’s meaning depend on how it
was compiled.&lt;/p&gt;
&lt;h2 id=&quot;the-third-shape-a-latch&quot;&gt;The third shape: a latch&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Result&lt;/code&gt; and a trap are the two channels for an &lt;em&gt;operation&lt;/em&gt; that failed. A &lt;strong&gt;stream&lt;/strong&gt; is the case
neither fits well, and the library answers it with a third shape — a trait whose one member reports
whether the stream has gone wrong:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meter&lt;/span&gt;
    written: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    bad: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.bad = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.written += n

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meter&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.bad

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Meter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;)

m.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(), m.written)

m.&lt;span class=&quot;hl-function&quot;&gt;put&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(), m.written)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;false 3
true 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Fallible&lt;/code&gt; is required by both &lt;code&gt;Writer&lt;/code&gt; and &lt;code&gt;Reader&lt;/code&gt;, which is what lets one open file be both — two
traits each declaring a &lt;code&gt;failed&lt;/code&gt; for one type could not be told apart at a call, because &lt;code&gt;failed&lt;/code&gt;
takes no arguments and so nothing about the call could say which was meant.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It latches rather than returning&lt;/strong&gt;, and that is the shape everything above it is built on: an
implementation stays straight-line, &lt;code&gt;print(x)&lt;/code&gt; stays a statement, and a caller asks once after a run
of operations rather than after each. Whether a stream &lt;em&gt;ended&lt;/em&gt; is a separate question from whether it
ended badly, which is why reading answers the first with an empty result and leaves this to answer
the second.&lt;/p&gt;
&lt;p&gt;The default is &lt;code&gt;false&lt;/code&gt; — most streams cannot fail, and one that cannot should not have to write down
that it cannot, so an &lt;code&gt;impl&lt;/code&gt; with an empty body is a complete one.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-absent&quot;&gt;What is deliberately absent&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;absent&lt;/th&gt;&lt;th&gt;instead&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;exceptions, &lt;code&gt;throw&lt;/code&gt;, &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a returned value, or an abort. There is no third, invisible control-flow channel&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;error return codes by convention&lt;/td&gt;&lt;td&gt;&lt;code&gt;Result&lt;/code&gt;, in the type, checked — not an &lt;code&gt;int&lt;/code&gt; a caller might forget to inspect&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;panic&lt;/code&gt; that unwinds&lt;/td&gt;&lt;td&gt;a trap is terminal&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;try&lt;/code&gt; on a constrained type&lt;/td&gt;&lt;td&gt;&lt;code&gt;T::Valid(x)&lt;/code&gt;, then the ordinary cast&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a build flag that strips checks&lt;/td&gt;&lt;td&gt;every check is in every build&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a contract discharged instead of checked&lt;/td&gt;&lt;td&gt;it is a branch and a trap wherever the value is produced, whether or not a prover has been over it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Nothing on this page is proved while compiling: a &lt;code&gt;require&lt;/code&gt; is a branch and a trap, an invariant is a
call to a synthesised predicate, a &lt;code&gt;within&lt;/code&gt; is two comparisons. What that buys is that &lt;strong&gt;the failure
lands where the mistake is&lt;/strong&gt; — plus, for &lt;code&gt;new&lt;/code&gt; types, a compile-time guarantee that has nothing to do
with the checking at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proving is a separate tool and it removes nothing.&lt;/strong&gt; &lt;a href=&quot;/reference/verification/&quot;&gt;Verification&lt;/a&gt; adds
the specification vocabulary — quantifiers, loop invariants, termination measures, &lt;code&gt;@pure&lt;/code&gt; and
&lt;code&gt;@ghost&lt;/code&gt; — and &lt;code&gt;sysl prove&lt;/code&gt;, which discharges the obligations with Why3. A clause proved redundant is
still compiled, because a program whose emitted code depended on whether a prover had been available
is one nobody could reason about. That is why the row above says &lt;em&gt;instead of&lt;/em&gt;: the two are additive.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/ffi/&quot;&gt;the foreign interface&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Enums and patterns</title>
    <link href="https://sysl.sh/tour/enums/"/>
    <id>https://sysl.sh/tour/enums/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A named set of constants, or a closed set of shapes — and the one expression that takes either apart.</summary>
    <content type="html">&lt;p&gt;One keyword covers two things a lot of languages spell separately: a &lt;strong&gt;named-constant set&lt;/strong&gt;, and a
&lt;strong&gt;sum type&lt;/strong&gt; whose variants carry data. Which one you get is decided by whether any variant has a
payload, so there is no second keyword to learn and no way for two declarations to disagree about
which kind this is.&lt;/p&gt;
&lt;h2 id=&quot;a-named-set-of-constants&quot;&gt;A named set of constants&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Yellow&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    c &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;  -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;   -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;blue&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Yellow&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yellow&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Yellow&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;blue 10 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The discriminant rule is C’s: a bare variant is the previous one plus one, starting at zero, and an
explicit &lt;code&gt;= 10&lt;/code&gt; is a value the counting continues from. What is &lt;em&gt;not&lt;/em&gt; C’s is that &lt;code&gt;Color&lt;/code&gt; is its own
type — a &lt;code&gt;Color&lt;/code&gt; and an &lt;code&gt;int&lt;/code&gt; do not mix without the conversion being written, which is what makes
this a type-safe constant set rather than a bag of integers.&lt;/p&gt;
&lt;p&gt;Two variants may not stand for one value, however the collision arises. A simple enum’s value &lt;em&gt;is&lt;/em&gt;
its identity, so two names for one number would be one value with two spellings, and the second one’s
&lt;code&gt;match&lt;/code&gt; arm could never run. Deliberately naming a value twice is what a &lt;code&gt;const&lt;/code&gt; is for.&lt;/p&gt;
&lt;h2 id=&quot;pinning-the-width&quot;&gt;Pinning the width&lt;/h2&gt;
&lt;p&gt;C leaves an enum’s underlying integer type implementation-defined, which makes it useless for the two
things a systems programmer most wants it for: a struct field of known width, and a value read off a
wire. sysl lets you say:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pin&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;A0&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;A1&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;A2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pin&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;A1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Pin&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Pos&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;A2&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pin&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Last&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;A1 2 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The type after the &lt;code&gt;:&lt;/code&gt; may be any integer type, including an arbitrary-width one like &lt;code&gt;u4&lt;/code&gt; — which
turns a simple enum into a usable tool for packed hardware-register fields. Unspecified, it is &lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Those &lt;code&gt;::&lt;/code&gt; names are a fixed set of questions the enum’s own name answers, kept out of the member
namespace so they can never collide with a variant. &lt;code&gt;Image&lt;/code&gt; gives a variant’s name as a string,
&lt;code&gt;Pos&lt;/code&gt; gives its 0-based position in the declaration, &lt;code&gt;Val&lt;/code&gt; goes back the other way, &lt;code&gt;First&lt;/code&gt;/&lt;code&gt;Last&lt;/code&gt;
are the ends and &lt;code&gt;Succ&lt;/code&gt;/&lt;code&gt;Pred&lt;/code&gt; the neighbours.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Position is not the discriminant&lt;/strong&gt;, and that is why both exist: discriminants may be explicit,
non-contiguous and not zero-based, so an ordinal has to be looked up rather than computed. A value’s
discriminant is &lt;code&gt;int(c)&lt;/code&gt;; its position is &lt;code&gt;Pos&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;coming-from-an-integer&quot;&gt;Coming from an integer&lt;/h2&gt;
&lt;p&gt;Going &lt;em&gt;to&lt;/em&gt; the underlying integer is total — every enum value is a valid integer. Coming &lt;em&gt;from&lt;/em&gt; one
has two spellings, chosen by how much you trust the value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))

&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;try&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(c) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;got&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(c))
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;7 is not a Color&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Green
7 is not a Color
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Color(n)&lt;/code&gt; is a checked cast that &lt;strong&gt;traps&lt;/strong&gt; on an integer no variant declares — the fast path for a
value already known good. &lt;code&gt;Color.try(n)&lt;/code&gt; returns an &lt;code&gt;Option&lt;/code&gt;, and it is the required path for bytes
off a wire. That closes C’s other enum hole, where every &lt;code&gt;int&lt;/code&gt; is silently a valid enum value, the
same way the &lt;code&gt;char&lt;/code&gt; rules close it for codepoints.&lt;/p&gt;
&lt;h2 id=&quot;variants-that-carry-data&quot;&gt;Variants that carry data&lt;/h2&gt;
&lt;p&gt;Give a variant a payload and the same keyword builds a sum type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(radius: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r)  -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; * r * r
        &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w, h) -&amp;gt; w * h
        &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;      -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12 12 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Constructing is calling the variant — &lt;code&gt;Circle(3)&lt;/code&gt;, with no &lt;code&gt;Shape.&lt;/code&gt; to write, because a variant name
is in scope as a constructor of its own enum. A nullary variant like &lt;code&gt;Empty&lt;/code&gt; is legal in either kind
of enum and reads the same in both.&lt;/p&gt;
&lt;p&gt;Which memory mode the result takes follows the ordinary rule from the &lt;a href=&quot;/tour/memory/&quot;&gt;memory
chapter&lt;/a&gt;: a data enum is a &lt;strong&gt;value&lt;/strong&gt;, sized for its widest variant plus a tag, and it
lands on the heap only where a &lt;code&gt;&amp;amp;Shape&lt;/code&gt; is expected. Being a sum type changes nothing about the three
modes — an enum is a struct-shaped value with a tag on it.&lt;/p&gt;
&lt;p&gt;The payload really is one region, not one field per variant. A four-variant enum carrying one integer
each is one integer wide, so a table of two hundred of them costs what you would expect rather than
four times that.&lt;/p&gt;
&lt;h2 id=&quot;the-check-that-makes-it-worth-having&quot;&gt;The check that makes it worth having&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;match&lt;/code&gt; on a data enum must cover every value, and the diagnostic names what is missing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(radius: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r) -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; * r * r&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;match on &apos;Shape&apos; is not exhaustive; missing Rect (add an &apos;else&apos; arm)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the central payoff of a closed set of variants: adding one turns every match on the enum into
a checked to-do list rather than a bug that shows up at run time.&lt;/p&gt;
&lt;p&gt;Coverage is about which &lt;em&gt;values&lt;/em&gt; are guaranteed handled, not which tags appear, and the arms answer
that question together. &lt;code&gt;Some(Circle(r))&lt;/code&gt;, &lt;code&gt;Some(Rect(w, h))&lt;/code&gt; and &lt;code&gt;None&lt;/code&gt; cover an &lt;code&gt;Option[Shape]&lt;/code&gt;
between them though no single arm covers a variant on its own — while &lt;code&gt;Some(0)&lt;/code&gt; alone does not cover
&lt;code&gt;Some&lt;/code&gt;, because a &lt;code&gt;Some&lt;/code&gt; holding anything else slips through.&lt;/p&gt;
&lt;p&gt;A guarded arm never discharges a variant’s obligation, since the compiler cannot prove a guard holds.
That is what keeps exhaustiveness a real guarantee instead of a formality.&lt;/p&gt;
&lt;h2 id=&quot;option-and-result-are-just-enums&quot;&gt;&lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt; are just enums&lt;/h2&gt;
&lt;p&gt;Nothing above is special-cased for them. They are ordinary generic declarations in the library:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first_even&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(x)

    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;first_even&lt;/span&gt;(data) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(n) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;found:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, n)
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;found: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is worth knowing early, because it means everything this chapter says about matching, binding
and exhaustiveness is what you already know about &lt;code&gt;Option&lt;/code&gt; — and everything you learn about &lt;code&gt;Option&lt;/code&gt;
transfers to an enum you write yourself.&lt;/p&gt;
&lt;h2 id=&quot;what-a-pattern-can-be&quot;&gt;What a pattern can be&lt;/h2&gt;
&lt;p&gt;Literals, ranges, alternatives, bindings and guards, in the order the arms are tried:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;                    -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;zero&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;            -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;  -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;medium even&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;                -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;medium odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;                    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;large&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;zero small medium even medium odd large
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arms are tried top to bottom and the first whose pattern matches wins, so a failed guard &lt;strong&gt;falls
through&lt;/strong&gt; to a later overlapping arm — which is why the two &lt;code&gt;4..10&lt;/code&gt; arms read as “even, otherwise
odd” rather than as a contradiction. The scrutinee is evaluated exactly once, whatever the arms do.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;else&lt;/code&gt; arm carries no &lt;code&gt;-&amp;gt;&lt;/code&gt;. The arrow separates a pattern from what to do when it matches, and
&lt;code&gt;else&lt;/code&gt; is not a pattern — it is the fallback, and it takes its body the way an &lt;code&gt;if&lt;/code&gt;‘s &lt;code&gt;else&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;Ranges are limited to the numeric types and &lt;code&gt;char&lt;/code&gt;, where a contiguous interval means something.
Literals work on anything &lt;code&gt;==&lt;/code&gt; can test, including &lt;code&gt;string&lt;/code&gt; and &lt;code&gt;bool&lt;/code&gt; — so matching a boolean with
&lt;code&gt;true -&amp;gt;&lt;/code&gt; and &lt;code&gt;false -&amp;gt;&lt;/code&gt; arms is exhaustive with no catch-all needed.&lt;/p&gt;
&lt;h2 id=&quot;destructuring-a-struct&quot;&gt;Destructuring a struct&lt;/h2&gt;
&lt;p&gt;Two forms, and they are a division of labour rather than two spellings of one thing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;locate&lt;/span&gt;(p: &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    p &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;origin&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{x: &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;} -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;on the y axis&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{y: &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;} -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;on the x axis&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;           &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;somewhere&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;locate&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;locate&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;locate&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;locate&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;origin on the y axis on the x axis somewhere
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Positional is total.&lt;/strong&gt; It mirrors construction, and it must name every field — so adding a field to
the struct turns each positional pattern into a checked arity error, exactly as a new enum variant
does. This is the handle-everything tool.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Named-field is partial.&lt;/strong&gt; It binds by name, so it survives a field reorder, it can rename
(&lt;code&gt;{x: a}&lt;/code&gt;), and any field left out is simply unconstrained. Adding a field never breaks one. This is
the grab-what-I-need tool.&lt;/p&gt;
&lt;p&gt;Both nest inside each other and inside variant patterns — &lt;code&gt;Some(Point{x})&lt;/code&gt;, &lt;code&gt;Wrap(Point(a, b))&lt;/code&gt; — and
every sub-pattern is itself any pattern in this section.&lt;/p&gt;
&lt;h2 id=&quot;the-bare-name-trap-closed&quot;&gt;The bare-name trap, closed&lt;/h2&gt;
&lt;p&gt;A bare identifier in a pattern is a nullary-variant pattern when it names one, and a binding
otherwise. The dangerous middle case is a name that &lt;em&gt;is&lt;/em&gt; a variant but carries data, and it is a hard
error rather than a silent catch-all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(radius: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    s &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;circle&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;  -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;variant &apos;Circle&apos; carries data — match it as &apos;Circle(…)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Without that rule, &lt;code&gt;Circle&lt;/code&gt; would have quietly become a binding that matched everything, and the
&lt;code&gt;Empty&lt;/code&gt; arm below it would have been dead code the compiler was happy with.&lt;/p&gt;
&lt;h2 id=&quot;matching-through-a-reference&quot;&gt;Matching through a reference&lt;/h2&gt;
&lt;p&gt;Field selection dereferences one level on its own, but &lt;code&gt;match&lt;/code&gt; does not. Matching a &lt;code&gt;&amp;amp;Enum&lt;/code&gt; is
written &lt;code&gt;match *e&lt;/code&gt;, which keeps “am I matching the reference or the thing” a visible question:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Tree&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Leaf&lt;/span&gt;(value: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Node&lt;/span&gt;(left: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Tree&lt;/span&gt;, right: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Tree&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(t: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Tree&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;t &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Leaf&lt;/span&gt;(v)    -&amp;gt; v
        &lt;span class=&quot;hl-function&quot;&gt;Node&lt;/span&gt;(l, r) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(l) + &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(r)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Tree&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Leaf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Leaf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Leaf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sum:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(t))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;sum: 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is also the shape a recursive enum takes: a variant holding its own enum by value would be
infinitely sized, so recursion goes through a &lt;code&gt;&amp;amp;T&lt;/code&gt; or a &lt;code&gt;*T&lt;/code&gt; — the same indirection rule the memory
chapter gives for structs.&lt;/p&gt;
&lt;p&gt;Binding a &lt;code&gt;&amp;amp;T&lt;/code&gt; payload out of an enum retains it, so the extracted reference outlives the enum it
came from and the count stays exact. That is not a rule about patterns; it is ARC’s retain-on-alias
applied to the temporary a binding introduces.&lt;/p&gt;
&lt;h2 id=&quot;one-shape-and-nothing-to-say-about-the-rest&quot;&gt;One shape, and nothing to say about the rest&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;match&lt;/code&gt; asks a value to choose between several shapes. Very often a program cares about &lt;strong&gt;one&lt;/strong&gt;, and
exhaustiveness then makes it pay for the arms it did not want — a one-arm match on an &lt;code&gt;Option&lt;/code&gt; is
forced to write a do-nothing catch-all.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;expr is Pat&lt;/code&gt; tests a pattern and yields a &lt;code&gt;bool&lt;/code&gt;, binding whatever the pattern names:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, target: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;xs.len
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; xs[i] == target &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(i)

    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(data, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(i) &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;at index:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, i)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(data, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(_) &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nine is not there&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;at index: 1
nine is not there
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The right side is a match arm’s left side, entire — a literal, a range, a variant, a struct, nested to
any depth, and &lt;code&gt;|&lt;/code&gt; alternatives. Terms chain with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, which is what keeps the form from evaporating
the moment a condition appears:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Row&lt;/span&gt;
    active: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    age: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;lookup&lt;/span&gt;(id: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;Row&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; id == &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Row&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;))
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lookup&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(row) &amp;amp;&amp;amp; row.active &amp;amp;&amp;amp; row.age &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;65&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;admitted at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, row.age)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;admitted at 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;is&lt;/code&gt; is a term of an &lt;code&gt;if&lt;/code&gt;‘s or a &lt;code&gt;while&lt;/code&gt;‘s condition and is legal nowhere else — not under &lt;code&gt;||&lt;/code&gt;,
not under &lt;code&gt;!&lt;/code&gt;, not on the right of an &lt;code&gt;=&lt;/code&gt;. The restriction is about the &lt;strong&gt;binding&lt;/strong&gt;, not the boolean:
everywhere else in sysl a name is introduced by a declaration whose scope you can see from the
indentation, and confining &lt;code&gt;is&lt;/code&gt; to a condition is what keeps the answer to “where does this name hold
something?” to one sentence.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A binding is live from its own &lt;code&gt;is&lt;/code&gt; rightward through the rest of the condition, and through the
branch that condition guards.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;||&lt;/code&gt; is excluded by that sentence rather than by a separate rule: there is no path through
&lt;code&gt;a is P(x) || b&lt;/code&gt; on which &lt;code&gt;x&lt;/code&gt; was bound. A &lt;code&gt;while&lt;/code&gt;‘s bindings are per-iteration — made by the test,
released at the bottom of the body — which is what makes the drain loop the natural spelling and
keeps a loop over a million elements holding one round’s refcounts rather than a million.&lt;/p&gt;
&lt;p&gt;Two things &lt;code&gt;is&lt;/code&gt; will not do. A pattern under &lt;code&gt;is not&lt;/code&gt; may not bind, since it would name something on
the one path where nothing matched it — &lt;code&gt;x is not Some(_)&lt;/code&gt; is the form that was wanted. And a pattern
that cannot fail is refused rather than folded away to &lt;code&gt;true&lt;/code&gt;: &lt;code&gt;x is n&lt;/code&gt; is a declaration wearing a
test’s clothes.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/errors/&quot;&gt;error handling&lt;/a&gt; — &lt;code&gt;Result&lt;/code&gt;, the &lt;code&gt;?&lt;/code&gt; operator, and the line between an error and
a trap.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The encoding module</title>
    <link href="https://sysl.sh/library/encoding/"/>
    <id>https://sysl.sh/library/encoding/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.encoding` — hexadecimal and base64 in both directions, fixed-width integers to and from bytes at either byte order, and a `DecodeError` that says what a caller can act on.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.encoding&lt;/code&gt; turns bytes into text and back, and integers into bytes and back. Three files, one
error type, and no allocator required for any of the core surface.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.{hex_string, base64_string, &lt;span class=&quot;hl-type&quot;&gt;Standard&lt;/span&gt;}

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hex_string&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;foobar&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64_string&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;foobar&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-type&quot;&gt;Standard&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;666f6f626172
Zm9vYmFy
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-two-directions-are-shaped-differently-on-purpose&quot;&gt;The two directions are shaped differently, on purpose&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Encoding writes to a &lt;a href=&quot;/library/core/#rendering-to-a-sink&quot;&gt;&lt;code&gt;Writer&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; That means hex straight to a file or to
standard output with no intermediate string — which is the case that actually matters for a codec.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.hex_encode

&lt;span class=&quot;hl-function&quot;&gt;hex_encode&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-function&quot;&gt;stdout&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6869
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Decoding writes into a slice the caller supplies&lt;/strong&gt;, and answers how many bytes it wrote. The output
length is computable before anything is read — half the text for hex, three quarters for base64 — so
there is nothing to discover by allocating, and the module stays usable where there is no allocator.
&lt;code&gt;hex_decoded_len&lt;/code&gt; and &lt;code&gt;base64_decoded_len&lt;/code&gt; are exported so a caller can size the slice.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.{hex_decode, hex_decoded_len}
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.from_utf8

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; text = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;666f6f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hex_decoded_len&lt;/span&gt;(text))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hex_decode&lt;/span&gt;(text, out).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;from_utf8&lt;/span&gt;(out[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
3
foo
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;_string&lt;/code&gt; conveniences beside each encoder are the only things in the module that allocate, and
they exist because assembling a sink for the common case would be the library refusing to do the easy
half.&lt;/p&gt;
&lt;h2 id=&quot;base64-has-two-axes-and-they-are-parameters&quot;&gt;base64 has two axes, and they are parameters&lt;/h2&gt;
&lt;p&gt;The alphabet and the padding are independent, so naming every combination ends at
&lt;code&gt;base64_encode_urlsafe_nopad&lt;/code&gt;. An enum and a &lt;code&gt;bool&lt;/code&gt; say the same thing and compose.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.{base64_string, &lt;span class=&quot;hl-type&quot;&gt;Standard&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;UrlSafe&lt;/span&gt;}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bytes: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0xfb&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0xff&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0xbf&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64_string&lt;/span&gt;(bytes, &lt;span class=&quot;hl-type&quot;&gt;Standard&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64_string&lt;/span&gt;(bytes, &lt;span class=&quot;hl-type&quot;&gt;UrlSafe&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64_string&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;fo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, &lt;span class=&quot;hl-type&quot;&gt;Standard&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;+/+/
-_-_
Zm8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Decoding accepts either alphabet without being told&lt;/strong&gt;, which costs nothing: &lt;code&gt;+/&lt;/code&gt; and &lt;code&gt;-_&lt;/code&gt; do not
overlap, so there is no input the two readings disagree about. Padding is optional on input and
checked when present. That asymmetry is deliberate — a writer should be exact and a reader should be
forgiving about what cannot be ambiguous.&lt;/p&gt;
&lt;h2 id=&quot;what-a-refusal-says&quot;&gt;What a refusal says&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;DecodeError&lt;/code&gt; has four cases, separated by what a caller would &lt;strong&gt;do&lt;/strong&gt; about each rather than by
taxonomy.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BadByte(at)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a byte outside the alphabet, and where&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BadLength&lt;/code&gt;&lt;/td&gt;&lt;td&gt;not a whole number of encoded units&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BadPadding(at)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;=&lt;/code&gt; somewhere it cannot be&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Short(needed)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the output slice is too small, and by how much&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Short&lt;/code&gt; carries the length that &lt;em&gt;would&lt;/em&gt; have been enough, so a caller resizes once rather than
discovering the requirement a byte at a time.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.{hex_decode, &lt;span class=&quot;hl-type&quot;&gt;BadByte&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;Short&lt;/span&gt;}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tiny: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; bad = &lt;span class=&quot;hl-function&quot;&gt;hex_decode&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;66zz&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, out) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;BadByte&lt;/span&gt;(at)) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bad byte at $at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    _ -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;something else&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;short&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;hex_decode&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;666f6f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes, tiny) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Short&lt;/span&gt;(n)) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;needs $n bytes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    _ -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;something else&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(bad)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;short&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;bad byte at 2
needs 3 bytes
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is a type of its own rather than &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;ParseError&lt;/code&gt;, which is about
reading a &lt;em&gt;number&lt;/em&gt; out of text: two of that type’s four cases could never occur here, and a caller
matching on it would be told cases exist that cannot.&lt;/p&gt;
&lt;h2 id=&quot;fixed-width-integers-at-either-byte-order&quot;&gt;Fixed-width integers, at either byte order&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.encoding.{get_u32_be, get_u32_le, put_u16_be, get_u16_be}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0x11&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0x22&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0x33&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0x44&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;get_u32_be&lt;/span&gt;(b).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;get_u32_le&lt;/span&gt;(b).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;put_u16_be&lt;/span&gt;(w, &lt;span class=&quot;hl-number&quot;&gt;0xbeef&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;get_u16_be&lt;/span&gt;(w).&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;287454020
1144201745
true
48879
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading answers an &lt;code&gt;Option&lt;/code&gt; and writing a &lt;code&gt;bool&lt;/code&gt;, rather than trapping: walking a buffer whose length
came from somewhere else is the ordinary use, and running off the end of one is an expected condition
there rather than a program’s mistake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;These are free functions at concrete widths, and that is exactly why they can exist.&lt;/strong&gt;
&lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;Bits&lt;/code&gt; trait deliberately has no &lt;code&gt;swap_bytes&lt;/code&gt;, because every member of
that trait must be total over every integer type and a &lt;code&gt;u24&lt;/code&gt; has no byte order at all. Nothing here is
a trait member, so nothing here reopens that — &lt;code&gt;get_u32_le&lt;/code&gt; names its width, and the widths written
are the ones with a whole number of bytes.&lt;/p&gt;
&lt;p&gt;Unsigned only: the signed read of the same bytes is a cast at the call site, and doubling a
twelve-function surface to spare one cast is not a trade worth making.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Declarations</title>
    <link href="https://sysl.sh/reference/declarations/"/>
    <id>https://sysl.sh/reference/declarations/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Bindings, functions, structs, enums and type declarations — what each form states, and what it leaves to be inferred.</summary>
    <content type="html">&lt;p&gt;A declaration is a &lt;strong&gt;statement&lt;/strong&gt;, so anything that can be declared at the top of a file can also be
declared inside a function body. A helper function used by one function belongs inside it, and needs
no separate rule to allow it.&lt;/p&gt;
&lt;h2 id=&quot;bindings&quot;&gt;Bindings&lt;/h2&gt;
&lt;p&gt;Three forms, and the differences between them are about &lt;em&gt;when&lt;/em&gt; the value is fixed rather than about
where it lives.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;form&lt;/th&gt;&lt;th&gt;mutable&lt;/th&gt;&lt;th&gt;value&lt;/th&gt;&lt;th&gt;type&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;var name = v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;optional — a &lt;code&gt;var&lt;/code&gt; may be declared and assigned later&lt;/td&gt;&lt;td&gt;optional&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;val name = v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no, written once&lt;/td&gt;&lt;td&gt;&lt;strong&gt;required&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;optional&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;const Name: T = v&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no, and known while compiling&lt;/td&gt;&lt;td&gt;required&lt;/td&gt;&lt;td&gt;&lt;strong&gt;required&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The type is mandatory on a &lt;code&gt;const&lt;/code&gt; and optional on a &lt;code&gt;val&lt;/code&gt;, and that arrangement is deliberate in
both directions. A &lt;code&gt;const&lt;/code&gt; states an interface — its value is substituted where it is used, so what
that value &lt;em&gt;is&lt;/em&gt; matters less than what it is a value &lt;strong&gt;of&lt;/strong&gt;. A &lt;code&gt;val&lt;/code&gt; has its type readable off the
value it was given, and a &lt;code&gt;val&lt;/code&gt; with no value is not a declaration of anything.&lt;/p&gt;
&lt;h3 id=&quot;the-value-may-be-an-indented-block&quot;&gt;The value may be an indented block&lt;/h3&gt;
&lt;p&gt;A binding’s &lt;code&gt;=&lt;/code&gt; takes one expression, or an &lt;strong&gt;indented block&lt;/strong&gt; whose trailing expression is the
value — the same arrangement a function body has, and the same one an &lt;code&gt;if&lt;/code&gt; branch has. What the block
binds is the block’s own, and goes out of scope with it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; limits =
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; raw = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; capped = raw * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

    capped

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(limits)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reach for it when the value takes more than one step to work out. The alternative is a name in the
enclosing scope that exists only to be read once on the next line, which says the value is available
to everything below when it is not.&lt;/p&gt;
&lt;p&gt;It composes with the branching forms rather than competing with them — an &lt;code&gt;if&lt;/code&gt; too long for its line
goes on the line under the &lt;code&gt;=&lt;/code&gt;, which is the shape the form was built for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(c: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n =
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt;
            &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

            a + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    n * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;pick&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;40 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A block of one expression is that expression.&lt;/strong&gt; Moving a value to the next line to fit the margin
changes nothing else about the declaration: a module &lt;code&gt;val&lt;/code&gt; written that way is still laid into the
object file, rather than becoming something the program computes before it starts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A block that ends in something other than an expression yields &lt;code&gt;unit&lt;/code&gt;&lt;/strong&gt;, exactly as an &lt;code&gt;if&lt;/code&gt; with no
&lt;code&gt;else&lt;/code&gt; does, and the complaint arrives where the value is used rather than where it was bound.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;const&lt;/code&gt; does not take one.&lt;/strong&gt; A constant is folded into every use of it rather than run, so there
is nowhere for the statements to happen. Its value may still sit on the next line — that is one
expression rather than a block, by the rule above — and what is refused is a block that binds
something:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; =
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; base = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

    base * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Limit&apos; is a &apos;const&apos;, so its value is folded into every use of it
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-module-member-states-its-type&quot;&gt;A module member states its type&lt;/h3&gt;
&lt;p&gt;Where a binding is a &lt;strong&gt;member of a module&lt;/strong&gt; rather than a local, the annotation stops being optional
even on a &lt;code&gt;val&lt;/code&gt;. That is a rule about &lt;em&gt;where&lt;/em&gt; the binding was written, so the grammar accepts either
form and the analyzer applies the rule.&lt;/p&gt;
&lt;p&gt;It is worth reading as one rule rather than two, because it is one: &lt;strong&gt;anything visible outside its
file states its types&lt;/strong&gt;, and a module member always could be, while a local states nothing to anyone
and so infers exactly as a &lt;code&gt;var&lt;/code&gt; does. Most of it the syntax already enforced — a parameter type and
a field type are mandatory, and an absent return type &lt;em&gt;means&lt;/em&gt; &lt;code&gt;unit&lt;/code&gt; rather than being inferred — so
a module-level binding is simply the last declaration the rule had left to reach.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The payoff is that interface extraction is parse-only.&lt;/strong&gt; A file’s exported surface can be read off
its syntax tree without resolving a name, checking a body, or having compiled anything the file
imports, which is what lets the collect pass depend on nothing but parsing — and that is what a fast,
parallel, eventually incremental build rests on. Scala infers types for public members and pays for
it with a far heavier extraction step; this is a deliberate divergence, and a cheap one here because
sysl’s signatures were already explicit for other reasons.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; doubled = &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt; * &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sysl&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    count += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(count, doubled, name, &lt;span class=&quot;hl-type&quot;&gt;Limit&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 6 sysl 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two &lt;code&gt;val&lt;/code&gt;s in that program are one keyword doing one thing: the module member says &lt;code&gt;: int&lt;/code&gt;
because it is visible outside its file, and the one inside &lt;code&gt;show&lt;/code&gt; is visible to nobody and does not
have to. The &lt;code&gt;static&lt;/code&gt; is what asks for the member — this is the file the program starts in, so a plain
&lt;code&gt;val&lt;/code&gt; there would be a local of its body, and a local infers exactly as a &lt;code&gt;var&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A module-level &lt;code&gt;val&lt;/code&gt; may hold a counted value, and never releases it.&lt;/strong&gt; Storage that exists for the
whole run is never let go of, so the one release with nowhere to go is the one at exit — and not
taking it is what a static &lt;em&gt;is&lt;/em&gt;. A &lt;code&gt;&amp;amp;T&lt;/code&gt;, a &lt;code&gt;weak T&lt;/code&gt;, a slice and a &lt;code&gt;string&lt;/code&gt; the program &lt;strong&gt;builds&lt;/strong&gt;
are all admissible:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(name)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That was refused until the reason was read again, and what it cost was every shape that needs a
value to outlive every frame. What the initializer &lt;em&gt;is&lt;/em&gt; still decides where the storage gets filled —
a &lt;strong&gt;literal&lt;/strong&gt;‘s bytes are a constant in the object file and its owner word is null, so nothing is
allocated and the storage is complete before the program starts, while a built value is stored by a
prologue. That difference is why a module with &lt;code&gt;no alloc&lt;/code&gt; may still hold a table of literals:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; greeting: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; names: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(greeting, names[i])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello beta
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what a module with no allocator uses for its messages. A &lt;code&gt;const&lt;/code&gt; could not serve it: a
constant is folded into its uses and has no address, so it cannot be indexed at a position computed
while running. Anything the program had to build is a &lt;strong&gt;local&lt;/strong&gt; instead, which is ordinary — that is
what the first program above does with its &lt;code&gt;val name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A raw pointer may be held&lt;/strong&gt;, because it counts nothing and so there is no release to write. What a
&lt;code&gt;val&lt;/code&gt; promises is that its &lt;em&gt;own&lt;/em&gt; storage is written once and never again, and holding an address
keeps that promise exactly as holding a number does. This is the shape that has no substitute — a
device register block named at file scope, reached by every function in the driver rather than
re-materialised in each:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const UART: usize = 0x1000_0000
val regs: *Uart = ptr_cast(UART)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An address that is a constant is laid into the object file rather than stored by a prologue, so a
&lt;code&gt;val&lt;/code&gt; at pointer type needs nothing ordered and is readable before the first initializer runs — which
is what a freestanding program starting at a reset vector requires.&lt;/p&gt;
&lt;p&gt;Writing to a &lt;code&gt;val&lt;/code&gt; twice is refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sysl&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    name = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(name)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;val&apos; is written once, so assignment has nothing to write through
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Read-only means read-only at every depth.&lt;/strong&gt; &lt;code&gt;k = …&lt;/code&gt;, &lt;code&gt;k[0] = …&lt;/code&gt;, &lt;code&gt;k[0] += 1&lt;/code&gt; and &lt;code&gt;k[0]++&lt;/code&gt; are all
refused on a module-level &lt;code&gt;val&lt;/code&gt;, and so is &lt;code&gt;&amp;amp;k[0]&lt;/code&gt; — a &lt;code&gt;*T&lt;/code&gt; is a licence to write, and handing one
out would move the mistake one step away from where it could still be reported.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Slicing is allowed, and yields a &lt;code&gt;[]const T&lt;/code&gt;.&lt;/strong&gt; That is what lets a table be &lt;em&gt;read and passed&lt;/em&gt;
rather than only read: the read-only property travels with the view, through a name, through a call,
and through a second subscript, so every write above is refused through it too. &lt;code&gt;&amp;amp;v[0]&lt;/code&gt; on such a
view is a &lt;code&gt;*T&lt;/code&gt;, the tier the memory model excludes on purpose, and is how the view reaches C.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The one module-level storage none of this reaches is an &lt;code&gt;extern&lt;/code&gt; variable.&lt;/strong&gt; Every rule above is a
promise this program makes about storage it laid down; an &lt;code&gt;extern&lt;/code&gt; variable is storage the &lt;em&gt;linker&lt;/em&gt;
supplies — &lt;code&gt;stdout&lt;/code&gt;, &lt;code&gt;environ&lt;/code&gt;, &lt;code&gt;optind&lt;/code&gt; — so there is no such promise to keep. It is a place, it may
be written, and it holds whatever the other side put there.&lt;/p&gt;
&lt;h3 id=&quot;several-at-once&quot;&gt;Several at once&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;var&lt;/code&gt; and &lt;code&gt;val&lt;/code&gt; both take a comma list, binding several names to several values. Each part’s type is
inferred from its own value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a, b = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; lo, hi = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b, lo, hi)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 0 10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two or more names and an initializer are both required: one name is the ordinary form, and a multiple
binding with nothing to take apart names nothing. The right side is produced before any name is
bound, so a value there still means whatever the enclosing scope calls it — the binding does not
shadow itself half way through its own right-hand side.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is a local form.&lt;/strong&gt; The parts carry no type annotation and there is nowhere to write one, so a
multiple &lt;code&gt;val&lt;/code&gt; at the top of a file collides with the rule above and is refused rather than becoming
a quiet local of the entry point. A module member that wants the form declares its names separately.&lt;/p&gt;
&lt;p&gt;The same spelling also takes a &lt;strong&gt;result list&lt;/strong&gt; and a &lt;strong&gt;tuple&lt;/strong&gt; apart, which is why a function with
several results needs no special form at the call.&lt;/p&gt;
&lt;h3 id=&quot;by-pattern-when-the-shape-matters&quot;&gt;By pattern, when the shape matters&lt;/h3&gt;
&lt;p&gt;A comma list says how &lt;em&gt;many&lt;/em&gt; things to bind. A &lt;strong&gt;pattern&lt;/strong&gt; says the shape, and so reaches inside a
tuple that holds another one — which is the whole of the difference between the two forms.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (a, b) = (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; ((x, y), z) = ((&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;val&lt;/span&gt; (first, _) = (&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;var&lt;/span&gt; (lo, hi) = (&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

    hi = hi + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b, x, y, z, first, lo, hi)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 3 4 5 6 0 11
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;_&lt;/code&gt; binds nothing and skips its part. A &lt;code&gt;var&lt;/code&gt; pattern makes every name it binds assignable, and a
&lt;code&gt;val&lt;/code&gt; pattern makes each of them write-once, exactly as the single-name forms do.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;struct pattern&lt;/strong&gt; stands here on the same terms, naming fields rather than positions. It may name
them in any order, may leave fields out, and may rename one to a sub-pattern:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Line&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{x, y} = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Line&lt;/span&gt;{a: &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;{x: ax}, b} = &lt;span class=&quot;hl-type&quot;&gt;Line&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;))

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x, y, ax, b.x, b.y)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 4 1 5 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A field the pattern does not name simply binds nothing — unlike a &lt;code&gt;match&lt;/code&gt; arm, a binding has no
exhaustiveness to discharge.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;positional&lt;/strong&gt; spelling &lt;code&gt;Point(a, b)&lt;/code&gt; stands here too, and takes the fields in declaration order.
It differs in the one way it differs in a &lt;code&gt;match&lt;/code&gt;: it names every field, so a struct that grows one
turns each positional binding into a checked to-do rather than one that goes on binding the same
names. See &lt;a href=&quot;/reference/patterns/#only-an-irrefutable-pattern-may-stand-there&quot;&gt;Patterns&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only a pattern that cannot fail may stand at a binding&lt;/strong&gt; — a tuple pattern, a struct pattern, a
name, a wildcard, and those nested inside one another. A struct qualifies because it has exactly one
shape, which is the same property that makes a tuple pattern irrefutable.&lt;/p&gt;
&lt;p&gt;A literal, a range, or a &lt;strong&gt;variant&lt;/strong&gt; is a &lt;em&gt;test&lt;/em&gt;, and a binding has no other arm to take when the
test does not match, so each is refused with that as the reason. Those belong in a &lt;code&gt;match&lt;/code&gt; (see
&lt;a href=&quot;/../patterns/&quot;&gt;Patterns&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Like the comma form, this is &lt;strong&gt;a local form&lt;/strong&gt;: the parts have nowhere to carry a type, so one at the
top of a file is refused rather than becoming a quiet local of the entry point.&lt;/p&gt;
&lt;h2 id=&quot;functions&quot;&gt;Functions&lt;/h2&gt;
&lt;p&gt;A name, a parameter list, an optional &lt;code&gt;-&amp;gt; result&lt;/code&gt;, and a body. There is no keyword: the shape is what
identifies it. An absent result type means &lt;code&gt;unit&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The body is either &lt;code&gt;= expr&lt;/code&gt; — whose value is the result — or an indented block, whose &lt;strong&gt;trailing
expression&lt;/strong&gt; is the result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = n * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = a + b

    t

&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(name: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hi&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, name)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;you&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 42
hi you
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;= &lt;/code&gt; may also open an indented block, so a body does not have to change shape when it outgrows a
line.&lt;/p&gt;
&lt;h3 id=&quot;tail-calls&quot;&gt;Tail calls&lt;/h3&gt;
&lt;p&gt;A function whose &lt;strong&gt;last act&lt;/strong&gt; is a call to itself does not open a second frame. The call becomes a
branch back to the function’s own entry, so the recursion is bounded by the arithmetic rather than by
the stack:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, acc: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; =
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; acc &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, acc + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1000000&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1000000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A million frames is not a stack any machine has. Nothing is written to ask for this — it applies
wherever it applies.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In tail position&lt;/strong&gt; is the last thing the function does: the body’s trailing expression, the operand
of a &lt;code&gt;return&lt;/code&gt;, and the arms of the &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt; those reach through. Nothing may wait on the
result — &lt;code&gt;n + count(n - 1)&lt;/code&gt; is an ordinary call, because the addition happens after it comes back.&lt;/p&gt;
&lt;p&gt;A tail call is a call, so the jump lands where a call would: &lt;strong&gt;every &lt;code&gt;require&lt;/code&gt; is checked again&lt;/strong&gt; on
the arguments the jump wrote, and &lt;strong&gt;every &lt;code&gt;old(e)&lt;/code&gt; is snapshotted again&lt;/strong&gt;. A recursion that violates
its own precondition at depth four stops at depth four.&lt;/p&gt;
&lt;p&gt;Two things end a tail position instead of being optimized around:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a &lt;code&gt;defer&lt;/code&gt; in scope&lt;/strong&gt;, which runs on the way out of a scope — after the callee returns for an
ordinary call, and before it is entered for a jump;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;an &lt;code&gt;ensures&lt;/code&gt; on the function&lt;/strong&gt;, which is checked when a call &lt;em&gt;returns&lt;/em&gt;, and a tail call never
returns.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either one leaves the function compiled exactly as written.&lt;/p&gt;
&lt;p&gt;It is &lt;strong&gt;self-recursion only&lt;/strong&gt;. Mutual recursion and calls through a &lt;code&gt;Fn&lt;/code&gt; or a &lt;code&gt;*extern&lt;/code&gt; are ordinary
calls, however they are written.&lt;/p&gt;
&lt;h3 id=&quot;tailrec&quot;&gt;&lt;code&gt;@tailrec&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The jump is silent, which is what you want until an edit takes it away. &lt;code&gt;@tailrec&lt;/code&gt; asserts it is
there and is refused when it is not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tailrec&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; =
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; n + &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;calls itself nowhere the jump can replace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It changes nothing about what is emitted — write it on the functions where losing the jump silently
would be a bug, and leave it off the rest.&lt;/p&gt;
&lt;h3 id=&quot;several-results&quot;&gt;Several results&lt;/h3&gt;
&lt;p&gt;A signature may declare more than one result, and the trailing expression or &lt;code&gt;return&lt;/code&gt; supplies them
as a comma list.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;minmax&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; a &amp;lt; b
        a, b
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
        b, a

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; lo, hi = &lt;span class=&quot;hl-function&quot;&gt;minmax&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(lo, hi)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is not a tuple. A tuple is a value with a type of its own; a result list is several values
handed back at once, and the multiple binding above is what receives them.&lt;/p&gt;
&lt;p&gt;A result list is &lt;strong&gt;a whole line by construction&lt;/strong&gt;, so it cannot be the body of an inline branch:
&lt;code&gt;if a &amp;lt; b then a, b else b, a&lt;/code&gt; does not parse, because the comma there would have to belong to the
branch rather than to whatever expression the branch is part of. The block form above is how a
conditional supplies several results.&lt;/p&gt;
&lt;h3 id=&quot;default-parameters-and-named-arguments&quot;&gt;Default parameters and named arguments&lt;/h3&gt;
&lt;p&gt;A parameter may say what a call that leaves it out gets instead. The default is a full expression, so
a call or a conditional may stand there — it is evaluated at the call site that omitted it, and it
may not name anything local to the declaration.&lt;/p&gt;
&lt;p&gt;An argument may be written &lt;code&gt;name = value&lt;/code&gt;, which stands at the parameter it names rather than at the
one its position would have given it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;box&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, fill: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;w * h
        s += fill

    s

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;box&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, fill = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;*** **** ##
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;name = value&lt;/code&gt; is also a legal expression — assignment yields the value stored — so the two readings
collide, and the named argument is the one taken. It applies only where the name is a bare
identifier: &lt;code&gt;p.x = 1&lt;/code&gt; and &lt;code&gt;b[i] = v&lt;/code&gt; are stores as they always were, since neither is a name a
parameter list could have written. A store to a plain variable is still reachable in an argument by
parenthesizing it.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;closure’s&lt;/strong&gt; parameter declares no default. A call reaches a closure through the &lt;code&gt;Fn&lt;/code&gt; traits,
which carry the types and not the names, so there would be nothing at the call to fill one from.&lt;/p&gt;
&lt;h3 id=&quot;overloading&quot;&gt;Overloading&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A name may be declared more than once, and every use of it still means exactly one declaration.&lt;/strong&gt;
Which one is decided by the &lt;strong&gt;arguments&lt;/strong&gt; a use passes: how many, and what type each is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;int $x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;str $x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;pair $x $y&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;int 1
str a
pair 1 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The result is never part of it.&lt;/strong&gt; A pair differing only in what they return is refused where the
second is written. sysl reads an expected type &lt;em&gt;inwards&lt;/em&gt;, from the context to the expression, so a
call whose meaning depended on its own result would need its context typed before it could be
resolved and would need resolving before its context could be typed.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;h&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;function &apos;h&apos; is already declared — which declaration a call means is decided by its arguments and never by what it returns, so two that differ only in the result have no call that tells them apart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That is the plain duplicate message with its sentence finished&lt;/strong&gt;, and the wording is deliberate:
the two parameter lists are the same, so this &lt;em&gt;is&lt;/em&gt; one declaration written twice. Somebody who wrote
that by accident is told so plainly; the clause is added only where the results differ, because that
is the pair a reader wrote on purpose and expected to work.&lt;/p&gt;
&lt;p&gt;The rule behind it is wider than the identical case. Each declaration takes a &lt;em&gt;range&lt;/em&gt; of argument
counts — from its parameters that have no default up to all of them — and two collide when their
ranges overlap at some count and their first that-many parameters agree in type. So a difference
hidden behind a default is refused too, and there the point is sharper: the default is
&lt;strong&gt;unreachable&lt;/strong&gt;, because no call could ever supply one argument to the longer declaration.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;g&apos; is already declared with parameters this one could not be told from — a call passing 1 argument would fit both, and which declaration a call means is decided by its arguments and never by what it returns. Two declarations of one name have to differ in a way a call site can show
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Reporting that at the declaration rather than at the call is the point.&lt;/strong&gt; The mistake is in the
pair; reporting it where the name is &lt;em&gt;used&lt;/em&gt; would report one mistake once per call site, in files
whose authors did not write it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A use that fits none of them, or several, is refused where the use is&lt;/strong&gt;, and the message carries
the roster — the reader’s question at that point is which declarations exist:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;k&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;k&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;k&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;no &apos;k&apos; takes these arguments — the declarations of that name are:
    k(x: int)
    k(x: string)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Three tie-breaks decide a use that fits more than one.&lt;/strong&gt; A candidate that needed no default fitted
the call as written and beats one that did; and a candidate whose parameters are exactly the
arguments’ own types beats one reached by a conversion — which is what lets a literal’s natural type
choose between two widths:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;width&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;width&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;i64&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;width&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;width&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1i64&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;int
i64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What is deliberately absent is any ranking &lt;em&gt;between&lt;/em&gt; conversions. Two candidates each reached by a
different one are ambiguous, and saying so beats a ladder of precedences nobody could predict from
the source.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exactness is asked of the types a candidate was fitted at, which for a generic one is what the call
solved it to.&lt;/strong&gt; &lt;code&gt;g[T]&lt;/code&gt; below takes the &lt;code&gt;[]int&lt;/code&gt; at &lt;code&gt;T = []int&lt;/code&gt;, as it was written; the other takes it
only by giving up the ability to write. So the generic declaration is the exact one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;(s: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;generic&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a[..]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;(v))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;generic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The third tie-break is that a candidate that named its parameters beats one that was solved for
them, where both are exact.&lt;/strong&gt; &lt;code&gt;f(x: int)&lt;/code&gt; and &lt;code&gt;f[T](x: T)&lt;/code&gt; both fit &lt;code&gt;f(0)&lt;/code&gt; at &lt;code&gt;int&lt;/code&gt;, and the ordinary
declaration is the one that said what it takes:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;plain&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;generic&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;plain
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That ranks a declaration against a declaration, which is a different question from ranking the routes
the arguments took — the thing the paragraph above refuses.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An address chooses by the type the context wants&lt;/strong&gt;, which is the mechanism a generic function’s
address already uses. With no expected type there is nothing to read, and the address is refused
rather than guessed at.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a + b

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; one: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;add
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; two: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;add

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;two&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 13
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;overloading-an-extern&quot;&gt;Overloading an &lt;code&gt;extern&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Two &lt;code&gt;extern&lt;/code&gt;s of one name are two functions exactly when they name two symbols.&lt;/strong&gt; A C library’s
naming is not sysl’s, and a family C spells &lt;code&gt;_solid&lt;/code&gt;/&lt;code&gt;_shaded&lt;/code&gt;/&lt;code&gt;_blended&lt;/code&gt; is one operation with an
option — which a binding may now say, without inventing a sysl name per C symbol.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strnlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, cap: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Two naming the &lt;em&gt;same&lt;/em&gt; symbol are refused.&lt;/strong&gt; That is one C function claimed at two signatures, and
the symbol is what gets emitted — both calls would reach the same code with different arguments, and
nothing downstream could tell which had been meant.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;strlen&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(s: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;, cap: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;size&apos; is already declared as an &apos;extern&apos; for the symbol &apos;strlen&apos; — two declarations of one name are two functions, and one C function cannot be two. Overloads of an &apos;extern&apos; are told apart by the symbol each names, so give this one a symbol of its own or take its address and &apos;ptr_cast&apos; it where the other signature is wanted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;extern&lt;/code&gt; and a sysl function do not overload each other, in either order, for the same reason:
what tells overloads of an &lt;code&gt;extern&lt;/code&gt; apart is the symbol, and a sysl function declares none.&lt;/p&gt;
&lt;h3 id=&quot;type-parameters&quot;&gt;Type parameters&lt;/h3&gt;
&lt;p&gt;A bracketed list directly after the name declares type parameters, with optional bounds. See
&lt;a href=&quot;/reference/generics/&quot;&gt;generics and traits&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;structs&quot;&gt;Structs&lt;/h2&gt;
&lt;p&gt;A named product type. Fields are declared one per line; methods, properties and an &lt;code&gt;invariant&lt;/code&gt; may
follow among them, in any order.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; w &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; h &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h

    perimeter -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; * (&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w + &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h)

    &lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.w *= k
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.h *= k
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Rect&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(), r.perimeter)

r.&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(r.&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(), r.w, r.h)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12 14
48 6 8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four things are on display there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A constructor is the struct’s name applied to its fields&lt;/strong&gt;, in declaration order. There is no
separate constructor declaration to write or to keep in step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A field declares no default.&lt;/strong&gt; What an unwritten field gets is decided by the constructor that
builds the value, not by the field — and the compiler says so rather than leaving a &lt;code&gt;= v&lt;/code&gt; after a
field to fail as whatever the grammar happened to want there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A property is a method with the parameter list left off&lt;/strong&gt; — &lt;code&gt;perimeter -&amp;gt; int&lt;/code&gt;, called as
&lt;code&gt;r.perimeter&lt;/code&gt; with no parentheses. It takes the same body forms a method does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The receiver says how the method reaches its value&lt;/strong&gt;, and is written as the first thing in the
parameter list:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;receiver&lt;/th&gt;&lt;th&gt;meaning&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;by value — the method gets a copy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;*self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;by pointer — the method may write through it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;by reference, counted&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;&amp;amp;sync self&lt;/code&gt;&lt;/td&gt;&lt;td&gt;by reference, and safe to share across threads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;(none)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;associated function&lt;/strong&gt; — no receiver, called on the type&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;origin&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;origin&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.x, p.y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;invariant&quot;&gt;&lt;code&gt;invariant&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;A condition every value of the struct must satisfy, re-checked whenever the struct is built or one of
its fields is written. Bare field names are in scope inside it. A multiple assignment re-checks it
&lt;strong&gt;once&lt;/strong&gt;, after every write has landed, which is what lets two fields that relate to each other be
changed together.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;invariant&lt;/code&gt; is a contextual word — an ordinary identifier everywhere else. See
&lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt; for what happens when one is broken.&lt;/p&gt;
&lt;h3 id=&quot;a-struct-with-no-fields&quot;&gt;A struct with no fields&lt;/h3&gt;
&lt;p&gt;A struct may declare no fields at all. Its emptiness has to be &lt;em&gt;written&lt;/em&gt; — the &lt;code&gt;end&lt;/code&gt; marker, optional
everywhere else, is what says so — because a struct whose body the author forgot to indent looks
exactly like one that has no body, and that is much the likelier mistake.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Stdout&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, bytes: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(bytes)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Stdout&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out = &lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;()

    x.&lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
    &lt;span class=&quot;hl-function&quot;&gt;printc&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;\n&apos;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; show&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;through a sink of one&apos;s own&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
through a sink of one&apos;s own
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What wants one is a &lt;strong&gt;sink&lt;/strong&gt;: a value standing for a destination fixed at compile time — the console,
a serial port — which has nothing to keep and so has no field to keep it in. Being a value rather
than a global is what lets it be passed to a function, held in a struct, and chosen by a caller.&lt;/p&gt;
&lt;p&gt;Such a type occupies no bytes, so embedding one costs the struct holding it nothing. The cost of that
is that two of them have nothing to tell their storage apart, and &lt;code&gt;&amp;amp;a == &amp;amp;b&lt;/code&gt; on two such locals may
well be true. There is no state behind either address for the answer to be about.&lt;/p&gt;
&lt;h3 id=&quot;opaque&quot;&gt;&lt;code&gt;opaque&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;opaque struct Name&lt;/code&gt; withholds the layout from every module but the one declaring it. Outside, the
type is &lt;em&gt;incomplete&lt;/em&gt;: only &lt;code&gt;*Name&lt;/code&gt; may be said, so a value cannot be built, copied, or have a field
read. This is a &lt;strong&gt;different axis from visibility&lt;/strong&gt; — &lt;code&gt;private&lt;/code&gt; decides who may say the name, &lt;code&gt;opaque&lt;/code&gt;
decides who may know the shape. See &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;An opaque struct with no body at all is C’s incomplete type, &lt;code&gt;struct sqlite3;&lt;/code&gt; — nothing in sysl lays
one out, and the declaration exists so that &lt;code&gt;*Session&lt;/code&gt; is a type a &lt;code&gt;*u8&lt;/code&gt; cannot be mistaken for.&lt;/p&gt;
&lt;h2 id=&quot;enums&quot;&gt;Enums&lt;/h2&gt;
&lt;p&gt;Two shapes under one keyword. A &lt;strong&gt;simple&lt;/strong&gt; enum is a set of named discriminants over an underlying
integer type; a &lt;strong&gt;data&lt;/strong&gt; enum gives its variants payloads, which makes it a sum type. Both may carry
members.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Status&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Warn&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Fail&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;severe&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Warn&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;severe&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Fail&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;severe&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 false true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;: u8&lt;/code&gt; pins the storage; without it the compiler picks. A variant is a bare name, a name with an
explicit integer value, or a name with a payload:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r)  -&amp;gt; &lt;span class=&quot;hl-number&quot;&gt;3.14159&lt;/span&gt; * r * r
        &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w, h) -&amp;gt; w * h

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3.14159 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A member is told from a variant by what follows it: a member needs a body after its header, so
&lt;code&gt;Circle(r: real)&lt;/code&gt; — a header with nothing after it — is a variant.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Option[T]&lt;/code&gt; and &lt;code&gt;Result[T, E]&lt;/code&gt; are ordinary data enums declared in the standard library, with no
compiler privileges.&lt;/p&gt;
&lt;h2 id=&quot;type-declarations&quot;&gt;Type declarations&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;type Name = Existing&lt;/code&gt; introduces a second spelling, interchangeable with the first. It creates &lt;strong&gt;no&lt;/strong&gt;
new type and no checking — an alias is for shortening a name that has grown long.&lt;/p&gt;
&lt;p&gt;Adding &lt;code&gt;new&lt;/code&gt; makes it a genuinely distinct type, and &lt;code&gt;within&lt;/code&gt; and &lt;code&gt;where&lt;/code&gt; add checked bounds:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.5&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(d) * &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(s))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;new&lt;/code&gt;, &lt;code&gt;within&lt;/code&gt; and &lt;code&gt;where&lt;/code&gt; are contextual words, so a function or field may still be named &lt;code&gt;where&lt;/code&gt;.
See &lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt; for what a bound costs and when it is checked.&lt;/p&gt;
&lt;h2 id=&quot;traits-impls-and-externs&quot;&gt;Traits, impls, and externs&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;trait Name&lt;/code&gt; declares a set of requirements; &lt;code&gt;impl Trait for Type&lt;/code&gt; supplies them. Both are covered on
&lt;a href=&quot;/reference/traits/&quot;&gt;traits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;extern&lt;/code&gt; declares a function or a variable the other side of the link owns, and is covered on
&lt;a href=&quot;/reference/ffi/&quot;&gt;the foreign interface&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;visibility&quot;&gt;Visibility&lt;/h2&gt;
&lt;p&gt;A declaration is &lt;strong&gt;public unless it says otherwise&lt;/strong&gt; — the unmarked case is the one that writes
nothing, because it is the common one.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;reach&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;(nothing)&lt;/em&gt;&lt;/td&gt;&lt;td&gt;public — anything that can see the module can see it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this file only&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;private[mod]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the named enclosing module and everything under it&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A struct’s and an enum’s &lt;strong&gt;members and fields&lt;/strong&gt; each take their own modifier, so a type may be public
while part of its shape is not. A trait’s members and an &lt;code&gt;impl&lt;/code&gt; block’s take none: a trait’s member is
as visible as the trait, and an implementation supplies what the trait asked for.&lt;/p&gt;
&lt;p&gt;The details — what a module is, how the reach is computed, and how visibility interacts with &lt;code&gt;opaque&lt;/code&gt;
— are on &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;end-markers&quot;&gt;&lt;code&gt;end&lt;/code&gt; markers&lt;/h2&gt;
&lt;p&gt;Every block-shaped declaration may be closed with &lt;code&gt;end Name&lt;/code&gt;, naming what it closes. It is optional
everywhere and checked when written, so it cannot drift from the thing it claims to close.&lt;/p&gt;
&lt;p&gt;The one place it is &lt;strong&gt;required&lt;/strong&gt; is a struct with no fields, where it is the only thing distinguishing
a body that is deliberately empty from one that was meant to be there.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;end&lt;/code&gt; is a &lt;strong&gt;soft&lt;/strong&gt; word: it is an ordinary identifier everywhere except immediately before a name or
a construct keyword, so &lt;code&gt;end&lt;/code&gt; stays usable as a variable.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/patterns/&quot;&gt;patterns and matching&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>datetime</title>
    <link href="https://sysl.sh/guides/datetime/"/>
    <id>https://sysl.sh/guides/datetime/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A conversion that can succeed twice — wall clocks, timelines, daylight saving, and the operator whose result no row can name.</summary>
    <content type="html">&lt;p&gt;Instants, durations, a calendar, and zones with daylight-saving rules — the whole point being the
conversion between a wall clock and a timeline, which can fail &lt;em&gt;and&lt;/em&gt; can succeed twice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: a conversion with three answers.&lt;/strong&gt; A local date-time is a reading on a wall clock. It is
not a point on the timeline and does not become one until somebody says where the wall is. On the
night a clock goes back, one reading names two instants; on the night it goes forward, one reading
names none. A library that returns a single answer there is wrong twice a year.&lt;/p&gt;
&lt;p&gt;The reference values were computed against the real tz database with Python’s &lt;code&gt;zoneinfo&lt;/code&gt;, and that was
worth doing for its own sake: Python subtracts two aware date-times in one zone by &lt;strong&gt;wall clock&lt;/strong&gt;, so
the first attempt at the reference values reported the week across the spring change as 168 hours. The
confusion this program is about is not a hypothetical one.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The difference of two moments could not be spelled &lt;code&gt;-&lt;/code&gt; — answered.&lt;/strong&gt; Every operator row was
&lt;code&gt;op(self, rhs: Rhs) -&amp;gt; Self&lt;/code&gt;, so an implementation said what it &lt;em&gt;took&lt;/em&gt; and never what it &lt;em&gt;produced&lt;/em&gt;.
&lt;code&gt;Instant + Duration&lt;/code&gt;, &lt;code&gt;Instant - Duration&lt;/code&gt; and &lt;code&gt;Duration ± Duration&lt;/code&gt; all wrote themselves;
&lt;code&gt;Instant - Instant -&amp;gt; Duration&lt;/code&gt; was refused, because &lt;code&gt;Sub&lt;/code&gt;‘s result was fixed to the type on the
left. Three quarters of an algebra was spellable, and the quarter that was not was the operation the
library exists to provide.&lt;/p&gt;
&lt;p&gt;An operator trait carries its result as &lt;code&gt;Out&lt;/code&gt; now, as well as its operand as &lt;code&gt;Rhs&lt;/code&gt; — the same change
&lt;a href=&quot;/guides/matrix/&quot;&gt;matrix&lt;/a&gt; was written for. A vector space needs &lt;code&gt;Vector * Vector -&amp;gt; real&lt;/code&gt; and a
timeline needs &lt;code&gt;Instant - Instant -&amp;gt; Duration&lt;/code&gt;; they are one feature asked for by two problems.
&lt;code&gt;sysl.time&lt;/code&gt; writes both rows of &lt;code&gt;Sub&lt;/code&gt; on &lt;code&gt;Instant&lt;/code&gt;, told apart by the type of the right operand and
nothing else — &lt;a href=&quot;/library/time/&quot;&gt;the library page runs both&lt;/a&gt;. &lt;code&gt;since&lt;/code&gt; stays as the named spelling,
because &lt;code&gt;later - earlier&lt;/code&gt; is right and &lt;code&gt;earlier - later&lt;/code&gt; is just as easy to write.&lt;/p&gt;
&lt;p&gt;The finding moved into the library with the types and was answered there, which is the part worth
keeping: a gap that becomes a shipped module’s gap is fixed once for everybody instead of worked
around once per program that wants a date.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A derived scalar and a one-field struct are exactly complementary, and neither is what a quantity
wants.&lt;/strong&gt; &lt;code&gt;type Instant = new i64&lt;/code&gt; inherits its base’s whole catalogue for free — &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;
— and &lt;a href=&quot;/reference/errors/&quot;&gt;may replace none of it&lt;/a&gt;, so it arrives with &lt;code&gt;Instant + Instant&lt;/code&gt;, which is
nonsense, and cannot be given &lt;code&gt;Instant + Duration&lt;/code&gt;, which is not. A struct of one field gets the
algebra exactly right and arrives with &lt;strong&gt;nothing&lt;/strong&gt;: five &lt;code&gt;impl&lt;/code&gt; blocks per type before anything can be
compared or printed. So a quantity type chooses between the catalogue and the meaning, and this
program pays the struct’s price on every one of its six types.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The three-way answer needed nothing new&lt;/strong&gt;, and that is a result rather than an absence. A data enum
already spells “one answer, or none, or two, and here they are”; the resolution type is an ordinary
enum and &lt;a href=&quot;/reference/patterns/&quot;&gt;coverage checking&lt;/a&gt; is what makes a caller handle all three. The axis
the problem was chosen for turns out to be covered by machinery that was already there — which is the
useful thing to know before designing a library around it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An enum cannot render its own variant names — and the three tables here turn out to be three
different asks.&lt;/strong&gt; A simple enum’s name answers &lt;code&gt;T::Image(v)&lt;/code&gt; with the word the variant is spelled
with, so the name-only case never needed a table: the library’s &lt;code&gt;weekday_name&lt;/code&gt; is that case, and is
one attribute read.&lt;/p&gt;
&lt;p&gt;Neither of this program’s own two is that case, and saying why is worth more than the original
complaint. The zone enum maps &lt;code&gt;NewYork&lt;/code&gt; to &lt;code&gt;&amp;quot;America/New_York&amp;quot;&lt;/code&gt; — a tz identifier, which is a fact
about the database and not about the declaration, so nothing but a table can hold it. The resolution
type is a &lt;strong&gt;data&lt;/strong&gt; enum, where &lt;code&gt;Image&lt;/code&gt; is refused in as many words, because a value there is a
variant plus a payload and a name answers for half of it — and its renderer builds a sentence out of
that payload anyway.&lt;/p&gt;
&lt;p&gt;What is left of the finding is the narrow thing: &lt;code&gt;str&lt;/code&gt; on an enum is still refused, so a value that
is nothing but its name is printed by asking for the name rather than by rendering the value.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;val&lt;/code&gt; could not be sliced&lt;/strong&gt;, third program to report that, and the report was acted on: a view of
read-only storage is a &lt;a href=&quot;/reference/arrays/&quot;&gt;&lt;code&gt;[]const T&lt;/code&gt;&lt;/a&gt;, which carries the property rather than losing
it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A built-in is on nobody’s left.&lt;/strong&gt; &lt;code&gt;Duration * 2&lt;/code&gt; is writable and &lt;code&gt;2 * Duration&lt;/code&gt; is not, so the
scaling in a date-time library only ever reads one way round.&lt;/p&gt;
&lt;h2 id=&quot;worth-noticing&quot;&gt;Worth noticing&lt;/h2&gt;
&lt;p&gt;Both quantities are counts of &lt;strong&gt;microseconds&lt;/strong&gt;, and the representation argument is written out in the
source rather than assumed. Packing civil fields to the nanosecond needs 30 bits for the nanosecond,
17 for the time of day and 9 for day and month — 56, leaving 8 bits of year, which is a range of ±128
years and not a calendar. A &lt;em&gt;count&lt;/em&gt; fits more comfortably at the same width and costs nothing to
compute with, because comparing, subtracting and adding a length are one instruction each on a count
and an unpack-recompute-repack on packed fields.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/datetime&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/matrix/&quot;&gt;matrix&lt;/a&gt; — an operator whose result is neither operand’s type.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The core module</title>
    <link href="https://sysl.sh/library/core/"/>
    <id>https://sysl.sh/library/core/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl` itself — the names every program has without asking: rendering, hashing, subscripting, iteration, callables, and the two ways a program stops.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl&lt;/code&gt; is the one module a program does not import. Every other module in this section — &lt;code&gt;sysl.buf&lt;/code&gt;,
&lt;code&gt;sysl.text&lt;/code&gt;, &lt;code&gt;sysl.io&lt;/code&gt; and the rest — is an offer, reached by name or by an &lt;code&gt;import&lt;/code&gt;. The core is
what arrives unasked-for, and the reason it does is narrow: &lt;strong&gt;a program cannot avoid needing what the
language desugars onto.&lt;/strong&gt; &lt;code&gt;print(x)&lt;/code&gt; is a call to a library function. &lt;code&gt;?&lt;/code&gt; unwraps a library enum.
&lt;code&gt;a + b&lt;/code&gt; is a library trait’s method. A language whose own forms reach names a program had to import
first would be a language with a required import, which is a worse thing than an auto-imported
module.&lt;/p&gt;
&lt;p&gt;So the rule for what belongs here is not “useful” — a growable sequence is useful and lives in
&lt;code&gt;sysl.buf&lt;/code&gt;. It is &lt;strong&gt;reached by the language itself&lt;/strong&gt;, or so close to that as to make no difference.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; maybe: &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(maybe.&lt;span class=&quot;hl-function&quot;&gt;unwrap_or&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;— and not one import above this line&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 — and not one import above this line
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-is-in-it&quot;&gt;What is in it&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;area&lt;/th&gt;&lt;th&gt;names&lt;/th&gt;&lt;th&gt;where it is written up&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;absence and failure&lt;/td&gt;&lt;td&gt;&lt;code&gt;Option&lt;/code&gt;, &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;Fallible&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;stopping&lt;/td&gt;&lt;td&gt;&lt;code&gt;panic&lt;/code&gt;, &lt;code&gt;assert&lt;/code&gt;, &lt;code&gt;exit&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below, and &lt;a href=&quot;/reference/attributes/&quot;&gt;attributes&lt;/a&gt; for &lt;code&gt;@test&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;rendering to standard output&lt;/td&gt;&lt;td&gt;&lt;code&gt;print&lt;/code&gt;-family: &lt;code&gt;prints&lt;/code&gt;, &lt;code&gt;printi&lt;/code&gt;, &lt;code&gt;printu&lt;/code&gt;, &lt;code&gt;printr&lt;/code&gt;, &lt;code&gt;printb&lt;/code&gt;, &lt;code&gt;printc&lt;/code&gt;, &lt;code&gt;putbytes&lt;/code&gt;, &lt;code&gt;encode_utf8&lt;/code&gt;; the sink itself, &lt;code&gt;Stdout&lt;/code&gt; and &lt;code&gt;stdout&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;rendering to standard error&lt;/td&gt;&lt;td&gt;&lt;code&gt;eprints&lt;/code&gt;, &lt;code&gt;eputbytes&lt;/code&gt;; the sink itself, &lt;code&gt;Stderr&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;rendering to a sink&lt;/td&gt;&lt;td&gt;&lt;code&gt;Display&lt;/code&gt;, &lt;code&gt;FormatSpec&lt;/code&gt;, &lt;code&gt;Writer&lt;/code&gt;, the &lt;code&gt;display_*&lt;/code&gt; family&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;hashing&lt;/td&gt;&lt;td&gt;&lt;code&gt;Hash&lt;/code&gt;, &lt;code&gt;hash_u64&lt;/code&gt;, &lt;code&gt;hash_u128&lt;/code&gt;, &lt;code&gt;hash_bool&lt;/code&gt;, &lt;code&gt;hash_str&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;destruction&lt;/td&gt;&lt;td&gt;&lt;code&gt;Drop&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;/reference/memory/&quot;&gt;the memory model&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;operators&lt;/td&gt;&lt;td&gt;&lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;Sub&lt;/code&gt;, &lt;code&gt;Mul&lt;/code&gt;, &lt;code&gt;Div&lt;/code&gt;, &lt;code&gt;Rem&lt;/code&gt;, &lt;code&gt;BitAnd&lt;/code&gt;, &lt;code&gt;BitOr&lt;/code&gt;, &lt;code&gt;BitXor&lt;/code&gt;, &lt;code&gt;Shl&lt;/code&gt;, &lt;code&gt;Shr&lt;/code&gt;, &lt;code&gt;Neg&lt;/code&gt;, &lt;code&gt;Not&lt;/code&gt;, &lt;code&gt;Eq&lt;/code&gt;, &lt;code&gt;Ord&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;/reference/expressions/&quot;&gt;expressions&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;subscripting and walking&lt;/td&gt;&lt;td&gt;&lt;code&gt;Index&lt;/code&gt;, &lt;code&gt;IndexSet&lt;/code&gt;, &lt;code&gt;Iterate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;calling&lt;/td&gt;&lt;td&gt;&lt;code&gt;Fn0&lt;/code&gt; … &lt;code&gt;Fn4&lt;/code&gt;&lt;/td&gt;&lt;td&gt;below&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;None of it is a language feature.&lt;/strong&gt; &lt;code&gt;Option&lt;/code&gt; is a generic enum, &lt;code&gt;Display&lt;/code&gt; is a trait, &lt;code&gt;panic&lt;/code&gt; is a
function that prints and exits. What the compiler knows is a short list of &lt;em&gt;names&lt;/em&gt; — it asks
&lt;code&gt;Option&lt;/code&gt; for its variants when it lowers a &lt;code&gt;?&lt;/code&gt;, and it asks the &lt;code&gt;print&lt;/code&gt; family which function renders
an &lt;code&gt;int&lt;/code&gt; — and it implements none of the behaviour behind them. Rewriting &lt;code&gt;printi&lt;/code&gt; is something a
program can do; rewriting &lt;code&gt;?&lt;/code&gt; is not.&lt;/p&gt;
&lt;h2 id=&quot;stopping-the-program&quot;&gt;Stopping the program&lt;/h2&gt;
&lt;p&gt;Two functions stop a program on purpose, and both are ordinary sysl:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;panic&lt;/span&gt;(msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, file: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;__FILE__&lt;/span&gt;, line: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;__LINE__&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;never&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;panic: &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(msg)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(file)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;printi&lt;/span&gt;(line)
    &lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(cond: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;, msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, file: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;__FILE__&lt;/span&gt;, line: &lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;__LINE__&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; !cond &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; msg.len == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;panic&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;assertion failed&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, file, line)
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;panic&lt;/span&gt;(msg, file, line)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;panic&lt;/code&gt; returns &lt;a href=&quot;/reference/types/&quot;&gt;&lt;code&gt;never&lt;/code&gt;&lt;/a&gt;, so a call to it is an expression of any type — which
is what lets it sit in one arm of a &lt;code&gt;match&lt;/code&gt; whose other arms produce values, exactly as &lt;code&gt;unwrap&lt;/code&gt;
does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The message is optional, because a failure names the line it happened on.&lt;/strong&gt; &lt;code&gt;__FILE__&lt;/code&gt; and
&lt;code&gt;__LINE__&lt;/code&gt; are &lt;a href=&quot;/reference/lexical/&quot;&gt;reserved identifiers&lt;/a&gt;, and a default is evaluated at the call —
so a parameter defaulted to one reports the &lt;em&gt;caller’s&lt;/em&gt; position rather than the library’s. Write a
message where it says something the condition does not; leave it out where the condition speaks for
itself.&lt;/p&gt;
&lt;p&gt;Two details of that are worth copying if you write a checking function of your own. &lt;code&gt;assert&lt;/code&gt; passes
&lt;code&gt;file&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt; &lt;strong&gt;on&lt;/strong&gt; to &lt;code&gt;panic&lt;/code&gt; rather than letting &lt;code&gt;panic&lt;/code&gt; fill its own defaults — otherwise
every assertion in every program would report the line inside the library that calls &lt;code&gt;panic&lt;/code&gt;. And the
location is composed with &lt;code&gt;prints&lt;/code&gt; and &lt;code&gt;printi&lt;/code&gt; instead of an interpolated string, because building a
string makes heap storage, which would put &lt;code&gt;assert&lt;/code&gt; out of reach of a module that declared
&lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;@no_alloc&lt;/code&gt;&lt;/a&gt; — the module that wants an assertion most.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;divide&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(b != &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
    a / b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;divide&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;84&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;assert-eq-the-assertion-that-says-what-the-values-were&quot;&gt;&lt;code&gt;assert_eq&lt;/code&gt; — the assertion that says what the values were&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;assert(a == b)&lt;/code&gt; names the line, so you know &lt;em&gt;which&lt;/em&gt; check broke. You then run the program again to
find out what the two values actually were — and running it again is exactly what the report could
have saved you.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;assert_eq&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](got: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, want: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, …)
&lt;span class=&quot;hl-function&quot;&gt;assert_slice_eq&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt; + &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;](got: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, want: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;, msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, …)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
        total = total + x

    total

&lt;span class=&quot;hl-function&quot;&gt;assert_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]), &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;assert_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]), &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the running total&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;both held&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;both held
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A failure prints the pair, in the order it is read in — what happened, then what was meant to:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;panic: got 5, want 6 (main.sysl:9)
panic: the running total: got 5, want 6 (main.sysl:10)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Why this is a function and not advice to write the message yourself.&lt;/strong&gt; The hand-written form is
&lt;code&gt;assert(a == b, s&amp;quot;got $a, want $b&amp;quot;)&lt;/code&gt;, and it has two costs: it evaluates each side twice, and it
builds a string. Building one makes heap storage, which puts it out of reach of a module that
declared &lt;a href=&quot;/reference/attributes/&quot;&gt;&lt;code&gt;@no_alloc&lt;/code&gt;&lt;/a&gt; — the module that wants an assertion most. Rendering
through &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Display&lt;/code&gt;&lt;/a&gt; into the output costs neither.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One function rather than one per type.&lt;/strong&gt; &lt;code&gt;Eq&lt;/code&gt; says the comparison means something and &lt;code&gt;Display&lt;/code&gt;
says the value can be shown, which together are the whole of what a report needs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;assert_slice_eq&lt;/code&gt; earns a name of its own because a report saying two slices differ sends you to
find out &lt;em&gt;where&lt;/em&gt;. It checks the lengths first — a length mismatch explains every index after the
shorter one — and otherwise names the first index the two disagree at, with both elements at it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;panic: got 2 elements, want 3 (main.sysl:4)
panic: got 2, want 5 at index 1 (main.sysl:9)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Floats use a different pair, in &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; &lt;code&gt;==&lt;/code&gt; is the wrong question to ask
about a float, so &lt;code&gt;assert_approx_eq&lt;/code&gt; and &lt;code&gt;assert_approx_eq_rel&lt;/code&gt; take a tolerance and are built on
&lt;code&gt;approx_eq&lt;/code&gt; / &lt;code&gt;approx_eq_rel&lt;/code&gt;, which is where the right question already lives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;These are the &lt;em&gt;runtime&lt;/em&gt; half of the language’s checking, and they are not the same half as
&lt;a href=&quot;/reference/errors/&quot;&gt;contracts&lt;/a&gt;.&lt;/strong&gt; A &lt;code&gt;require&lt;/code&gt; clause is a promise about a &lt;strong&gt;call&lt;/strong&gt;, checked where
the call arrives. &lt;code&gt;assert&lt;/code&gt; is a promise about a &lt;strong&gt;moment&lt;/strong&gt;, checked where the moment is. A function
whose fifth statement has just computed something it can verify has no contract to hang that on —
the contract was about the arguments, four statements ago.&lt;/p&gt;
&lt;p&gt;They also stop the program &lt;em&gt;differently&lt;/em&gt; from the checks the compiler inserts, and the difference is
visible:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;stopped by&lt;/th&gt;&lt;th&gt;what you see&lt;/th&gt;&lt;th&gt;exit status&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a compiler-inserted check (a bounds test, a broken contract)&lt;/td&gt;&lt;td&gt;nothing at all — a trap instruction, and buffered output is lost&lt;/td&gt;&lt;td&gt;the platform’s signal status&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;panic&lt;/code&gt;, &lt;code&gt;assert&lt;/code&gt;, &lt;code&gt;unwrap&lt;/code&gt;, &lt;code&gt;expect&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;panic: &amp;lt;message&amp;gt;&lt;/code&gt; on stdout, after everything printed before it&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That is not an inconsistency. A trap is for a check the &lt;em&gt;language&lt;/em&gt; makes, where the source line
already says everything a message could; &lt;code&gt;panic&lt;/code&gt; is for a check a &lt;em&gt;program&lt;/em&gt; makes, about something it
knows and the compiler does not, where the message is the entire point. The full account is on
&lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;exit&lt;/code&gt; is the third name here and the only &lt;code&gt;extern&lt;/code&gt; the core offers rather than keeps:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(code: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;never&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It takes no link name where the four platform externs in &lt;a href=&quot;/library/sys/&quot;&gt;&lt;code&gt;sysl.sys&lt;/code&gt;&lt;/a&gt; all take one,
because it is not a platform detail — it is the hosted exit, the thing &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;unwrap&lt;/code&gt; stop
with, and a program stopping itself writes exactly the same call.&lt;/p&gt;
&lt;h2 id=&quot;rendering-to-standard-output&quot;&gt;Rendering to standard output&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;print(a, b, c)&lt;/code&gt; is &lt;strong&gt;a desugaring, not a variadic function&lt;/strong&gt;. Each argument is looked at
individually, its static type chooses a one-argument renderer, and the call becomes that sequence of
calls with a space between and a newline at the end.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;static type&lt;/th&gt;&lt;th&gt;renderer&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;prints&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the bytes, as they are&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;any signed integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;printi&lt;/code&gt;&lt;/td&gt;&lt;td&gt;through &lt;code&gt;snprintf&lt;/code&gt;‘s &lt;code&gt;%lld&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;any unsigned integer&lt;/td&gt;&lt;td&gt;&lt;code&gt;printu&lt;/code&gt;&lt;/td&gt;&lt;td&gt;through &lt;code&gt;snprintf&lt;/code&gt;‘s &lt;code&gt;%llu&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;real&lt;/code&gt;, &lt;code&gt;f32&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;printr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;through &lt;code&gt;snprintf&lt;/code&gt;‘s &lt;code&gt;%g&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;printb&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;printc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;UTF-8 encoded in sysl, not by C&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;anything else&lt;/td&gt;&lt;td&gt;its &lt;code&gt;Display&lt;/code&gt;&lt;/td&gt;&lt;td&gt;via &lt;code&gt;str&lt;/code&gt;, which renders into a buffer&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3.5&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 3.5 true é text 7
0.333333
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;0.333333&lt;/code&gt; rather than &lt;code&gt;0.3333333333333333&lt;/code&gt; because &lt;code&gt;%g&lt;/code&gt; is six significant digits by default —
which is C’s default and stays C’s, since the whole of &lt;code&gt;printr&lt;/code&gt; is one &lt;code&gt;snprintf&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;The renderers are ordinary functions and a program may call them directly. Nothing separates them,
so this is where the space between &lt;code&gt;print&lt;/code&gt;‘s arguments visibly comes from — there isn’t one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;printi&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;printr&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;printb&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;printc&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;printu&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|end&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;-7|2.5|false|é|9|end
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;everything-goes-through-one-sink-and-that-is-not-incidental&quot;&gt;Everything goes through one sink, and that is not incidental&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;putbytes&lt;/code&gt; is the bottom of the whole surface. Every function above writes through it, including the
ones that went to &lt;code&gt;snprintf&lt;/code&gt; for their digits — they format into a stack buffer and then hand the
bytes here.&lt;/p&gt;
&lt;p&gt;Two mechanisms would mean two buffers, and output emerging in an order the program did not write.
That is the entire reason for the shape.&lt;/p&gt;
&lt;p&gt;It also writes &lt;strong&gt;a byte at a time&lt;/strong&gt;, which looks like a mistake and is not. A sysl &lt;code&gt;string&lt;/code&gt; may hold
an interior NUL, and every shortcut through C stops at one: &lt;code&gt;puts&lt;/code&gt;, &lt;code&gt;%s&lt;/code&gt;, even &lt;code&gt;%.*s&lt;/code&gt;. A string that
printed correctly right up until it contained a zero byte is a worse bug than a loop that costs a
call per byte, and the loop is what a target with a real &lt;code&gt;write&lt;/code&gt; replaces anyway.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(b: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; i &amp;lt; b.len
        &lt;span class=&quot;hl-function&quot;&gt;sysl_putchar&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(b[i]))
        i += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; putbytes&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;putbytes&lt;/code&gt; is one of exactly two functions a freestanding target has to replace.&lt;/strong&gt; Swap its body
for a &lt;code&gt;write&lt;/code&gt; syscall and &lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;FdReader.read&lt;/code&gt;&lt;/a&gt;‘s for a &lt;code&gt;read&lt;/code&gt; one, and the entire surface
above both is unchanged — every renderer, every &lt;code&gt;Display&lt;/code&gt;, every &lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt; in the program.&lt;/p&gt;
&lt;h3 id=&quot;encode-utf8-a-character-s-bytes-without-printing-them&quot;&gt;&lt;code&gt;encode_utf8&lt;/code&gt; — a character’s bytes, without printing them&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;encode_utf8&lt;/span&gt;(ch: &lt;span class=&quot;hl-type&quot;&gt;char&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;printc&lt;/code&gt; encodes rather than handing the character to &lt;code&gt;snprintf&lt;/code&gt;, which has no conversion that takes
a code point — and what it uses is this, which any program may call. It writes into storage the
caller owns and answers how many bytes it wrote. No character needs more than four, so a &lt;code&gt;[4]u8&lt;/code&gt; is
always enough and always on the stack, which is what keeps it usable where there is no allocator.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;encode_utf8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;A&apos;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;encode_utf8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;encode_utf8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;☃&apos;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-function&quot;&gt;encode_utf8&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 3
195 169 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is here in &lt;code&gt;sysl&lt;/code&gt; rather than beside &lt;code&gt;from_utf8&lt;/code&gt; in &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt;, and that
placement is forced.&lt;/strong&gt; A submodule may name the standard module freely and the standard module may
not name back, so an encoder over there would be one &lt;code&gt;printc&lt;/code&gt; could not call — and the second encoder
that would then be written for it is exactly the hand-rolled copy this function exists to prevent.
The library carried four of them before it had this one.&lt;/p&gt;
&lt;p&gt;A slice shorter than four bytes is a mistake in the program rather than a truncation, and the bounds
check says so: how many bytes are needed is not known until the character has been looked at, so
there is no honest answer to “it did not fit” that is cheaper than having room.&lt;/p&gt;
&lt;h3 id=&quot;the-other-stream&quot;&gt;The other stream&lt;/h3&gt;
&lt;p&gt;A program’s &lt;em&gt;answer&lt;/em&gt; and its &lt;em&gt;complaints&lt;/em&gt; go to different places, so that a run whose output is being
captured does not have the complaint land in the middle of the answer, and a redirect that keeps the
answer still lets a person see what went wrong. &lt;code&gt;eprints&lt;/code&gt; writes a string to standard error, and
&lt;code&gt;stderr()&lt;/code&gt; is the same destination as a &lt;code&gt;Writer&lt;/code&gt;, for a value rendering itself through its own
&lt;code&gt;Display&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the answer&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;eprints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;something to say about it&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the answer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The page shows only the first line because only the first line went to standard output — which is the
whole point of the distinction, and is what &lt;a href=&quot;/library/args/&quot;&gt;&lt;code&gt;sysl.args&lt;/code&gt;&lt;/a&gt; relies on when it puts a
usage error on one stream and its &lt;code&gt;--help&lt;/code&gt; on the other.&lt;/p&gt;
&lt;p&gt;This half goes through &lt;code&gt;write&lt;/code&gt; directly rather than a byte at a time, because there is no buffer
between it and the descriptor: a diagnostic written just before a program stops has to have left
before it does, which is the same reason C leaves standard error unbuffered. A short write is looped
over, since a signal may cut one anywhere.&lt;/p&gt;
&lt;h2 id=&quot;rendering-to-a-sink&quot;&gt;Rendering to a sink&lt;/h2&gt;
&lt;p&gt;Standard output is one destination. A value that knows how to render itself renders into a
&lt;strong&gt;&lt;code&gt;Writer&lt;/code&gt;&lt;/strong&gt; instead, and that is what &lt;code&gt;Display&lt;/code&gt; is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;
    width: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    prec: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    left: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, bytes: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three decisions are packed into those six lines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A value writes rather than returns.&lt;/strong&gt; &lt;code&gt;display&lt;/code&gt; produces no &lt;code&gt;string&lt;/code&gt;, so rendering costs no
allocation and a module under &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;no alloc&lt;/code&gt;&lt;/a&gt; can still log. &lt;code&gt;str(x)&lt;/code&gt; is then not a
separate mechanism — it is this same rendering aimed at a buffer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The sink is &lt;code&gt;*Writer&lt;/code&gt;, a trait object.&lt;/strong&gt; So a rendering is written once against any sink, and a
kernel that has a UART and no standard output supplies one with an ordinary &lt;code&gt;impl&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Standard output itself is one of those ordinary impls, and the library declares it — &lt;code&gt;Stdout&lt;/code&gt;, a
struct with no fields, because a destination fixed at compile time keeps nothing. &lt;code&gt;stdout()&lt;/code&gt; hands
one out, and it is what &lt;code&gt;print&lt;/code&gt; writes a value’s own rendering into:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, fmt)
        &lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n), out, fmt)
        &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, fmt)

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, m: &lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;)
    m.&lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
    &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; mine = &lt;span class=&quot;hl-type&quot;&gt;Stdout&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;stdout&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;mine, &lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Marked&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;&amp;lt;1&amp;gt;
&amp;lt;2&amp;gt;
&amp;lt;3&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That the destination is a &lt;strong&gt;value&lt;/strong&gt; rather than a fixed global is what lets &lt;code&gt;show&lt;/code&gt; take it as a
parameter. Nothing above is privileged: a program pointing &lt;code&gt;show&lt;/code&gt; at a UART writes another
&lt;code&gt;impl Writer&lt;/code&gt; and passes that instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Writer&lt;/code&gt; requires &lt;code&gt;Fallible&lt;/code&gt;&lt;/strong&gt; rather than declaring a &lt;code&gt;failed&lt;/code&gt; of its own, because
&lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;Reader&lt;/code&gt;&lt;/a&gt; needs the same question answered and an open file is both. Two traits may
each declare a member of one name — a call says which by naming the trait — but &lt;code&gt;failed&lt;/code&gt; takes no
arguments, so at a call on a file there would be nothing to say which was meant. One required trait
makes the question go away rather than move it. &lt;code&gt;Fallible&lt;/code&gt; is on &lt;a href=&quot;/reference/errors/&quot;&gt;errors and
contracts&lt;/a&gt;, with the reason a stream &lt;strong&gt;latches&lt;/strong&gt; instead of returning.&lt;/p&gt;
&lt;h3 id=&quot;the-display-family&quot;&gt;The &lt;code&gt;display_*&lt;/code&gt; family&lt;/h3&gt;
&lt;p&gt;Every rendering the language does ends up in this family, one function per shape:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;function&lt;/th&gt;&lt;th&gt;renders&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_str&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;code&gt;string&lt;/code&gt;; precision &lt;strong&gt;truncates&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_int&lt;/code&gt;, &lt;code&gt;display_uint&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an integer a caller already holds at &lt;strong&gt;64 bits&lt;/strong&gt;; precision is a &lt;strong&gt;minimum digit count&lt;/strong&gt;, zero-filled&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_real&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a float; precision is &lt;strong&gt;significant digits&lt;/strong&gt;, defaulting to 6 and capped at 40&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_bool&lt;/code&gt;, &lt;code&gt;display_char&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt;/&lt;code&gt;false&lt;/code&gt;, and a code point encoded to UTF-8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_digits&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;where a number ends up&lt;/strong&gt; — reads a sign off the front, zero-fills to the precision, then pads&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_pad&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;where the rest end up&lt;/strong&gt; — puts finished bytes in the field the spec asked for&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;display_fill&lt;/code&gt;&lt;/td&gt;&lt;td&gt;writes one byte &lt;em&gt;n&lt;/em&gt; times, in 16-byte runs off a stack buffer&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Every built-in reaches its own through an &lt;code&gt;impl&lt;/code&gt;, and the two halves get there differently.&lt;/strong&gt;
&lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;char&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;real&lt;/code&gt; and &lt;code&gt;f32&lt;/code&gt; are five types, so each has an ordinary &lt;code&gt;impl Display&lt;/code&gt; in
the library forwarding to the function above. The &lt;code&gt;iN&lt;/code&gt;/&lt;code&gt;uN&lt;/code&gt; families are open — &lt;code&gt;i5&lt;/code&gt; and &lt;code&gt;u24&lt;/code&gt; are
types you may write — so no finite list of blocks reaches them; what reaches them is a single
&lt;strong&gt;blanket&lt;/strong&gt; block, &lt;code&gt;impl[T: Integer] Display for T&lt;/code&gt;, whose buffer is measured from the width it is
instantiated at.&lt;/p&gt;
&lt;p&gt;Either way they are &lt;code&gt;Display&lt;/code&gt; exactly the way your own struct is, and &lt;strong&gt;a &lt;code&gt;*Display&lt;/code&gt; can carry any
of them&lt;/strong&gt;. That is what the blanket bought: a &lt;code&gt;[]*Display&lt;/code&gt; holding an &lt;code&gt;int&lt;/code&gt;, a &lt;code&gt;u8&lt;/code&gt;, a &lt;code&gt;string&lt;/code&gt; and
a float is ordinary code, where an integer used to be the one thing a method table could not hold.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Integer&lt;/code&gt; is a trait you can write a bound over — &lt;code&gt;f[T: Integer](x: T)&lt;/code&gt; accepts every width and
nothing else — but not one you can implement. It names which types the compiler settles a family as,
so there is nothing for a block to supply.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;display_int&lt;/code&gt; and &lt;code&gt;display_uint&lt;/code&gt; remain for a caller who already has a &lt;code&gt;long&lt;/code&gt; in hand. Nothing in
the library routes through them any more.&lt;/p&gt;
&lt;p&gt;A scalar reaches its own through a method call, so a &lt;code&gt;Display&lt;/code&gt; written for a struct can render its
fields without leaving the allocation-free path:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.byte_sink

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sink = &lt;span class=&quot;hl-function&quot;&gt;byte_sink&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sink

&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(sink.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;    42x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;FormatSpec(6, -1, false)&lt;/code&gt; is a width of six, &lt;strong&gt;no precision&lt;/strong&gt; — which is what &lt;code&gt;-1&lt;/code&gt; means throughout
the family — and padding on the left. The neutral spec, which is what a plain &lt;code&gt;print&lt;/code&gt; passes, is
&lt;code&gt;FormatSpec(0, -1, false)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The allocation-free path reaches every width.&lt;/strong&gt; A rendering works its digits out against a
frame-local buffer and hands the sink a slice of it, which is safe because a &lt;code&gt;Writer&lt;/code&gt; borrows the
bytes it is given rather than keeping them — so a module declaring &lt;code&gt;@no_alloc&lt;/code&gt; can render anything,
a &lt;code&gt;u256&lt;/code&gt; included.&lt;/p&gt;
&lt;p&gt;It did not always. The buffer has to be sized for the width, and until an array’s length could be
written in terms of a type parameter — &lt;code&gt;[sizeof(T) * 3 + 2]u8&lt;/code&gt;, three decimal digits per byte being
the bound at every width — the widest values fell back through &lt;code&gt;str&lt;/code&gt;, which is heap storage. So the
values needing the most care were the ones a module without an allocator could not print.&lt;/p&gt;
&lt;h3 id=&quot;one-padder-and-why&quot;&gt;One padder, and why&lt;/h3&gt;
&lt;p&gt;Every renderer finishes by handing its bytes to &lt;code&gt;display_pad&lt;/code&gt;. Six renderers each growing their own
padding would be six chances for &lt;code&gt;%8s&lt;/code&gt; to mean something slightly different, and the drift would be
invisible until someone lined two columns up.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.byte_sink

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sink = &lt;span class=&quot;hl-function&quot;&gt;byte_sink&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sink

&lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;héllo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_real&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt; / &lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_bool&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_char&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;é&apos;&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_uint&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(sink.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;      42|-00042|h|0.333|true    |  é|007
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read that line slowly, because four rules are visible in it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Precision means a different thing per renderer, and matches printf’s meaning under the
corresponding conversion.&lt;/strong&gt; &lt;code&gt;-00042&lt;/code&gt; is &lt;code&gt;%.5d&lt;/code&gt;: five digits minimum, zero-filled, and the sign is
written &lt;em&gt;before&lt;/em&gt; the zeros rather than being counted among them. &lt;code&gt;0.333&lt;/code&gt; is &lt;code&gt;%.3g&lt;/code&gt;: three
significant digits. &lt;code&gt;007&lt;/code&gt; is the unsigned form of the first. &lt;code&gt;h&lt;/code&gt; is &lt;code&gt;%.2s&lt;/code&gt;: truncation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Width and precision count bytes, exactly as C’s do.&lt;/strong&gt; &lt;code&gt;display_str(&amp;quot;héllo&amp;quot;, …)&lt;/code&gt; with a precision of
2 was asked for two &lt;em&gt;bytes&lt;/em&gt;, and &lt;code&gt;é&lt;/code&gt; is two bytes of which only the first fits — so the answer is
&lt;code&gt;h&lt;/code&gt;. It backs off to a character boundary rather than handing the sink half of a code point, which is
the one place this family refines C rather than copying it: &lt;code&gt;%.2s&lt;/code&gt; in C would emit the lone lead
byte.&lt;/p&gt;
&lt;p&gt;The same byte-counting is why &lt;code&gt;é&lt;/code&gt; in a field of four came out with &lt;strong&gt;two&lt;/strong&gt; spaces and not three. A
column-aligned table of non-ASCII text is therefore not something &lt;code&gt;width&lt;/code&gt; gives you for free —
counting display columns is a different problem (combining marks, wide CJK cells) and the library
does not pretend to solve it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;left&lt;/code&gt; is the whole of justification.&lt;/strong&gt; There is no centring, and no fill character other than a
space for the field or a zero for the digits.&lt;/p&gt;
&lt;h3 id=&quot;writing-display-for-your-own-type&quot;&gt;Writing &lt;code&gt;Display&lt;/code&gt; for your own type&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    y: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) =
        &lt;span class=&quot;hl-function&quot;&gt;display_pad&lt;/span&gt;((&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.x) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.y) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;).bytes, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%10s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%-10s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;(3, 4)
[    (3, 4)]
[(3, 4)    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The parts are gathered before anything is padded, and that is the rule rather than the style.&lt;/strong&gt; A
specifier describes the field the &lt;em&gt;whole value&lt;/em&gt; occupies — so &lt;code&gt;%10s&lt;/code&gt; on a point pads the point, not
its first number. An implementation that rendered parts and forwarded &lt;code&gt;fmt&lt;/code&gt; down to each of them
would pad the &lt;code&gt;3&lt;/code&gt; to ten columns and then the &lt;code&gt;4&lt;/code&gt;, which is not what anybody asking for &lt;code&gt;%10s&lt;/code&gt; meant.&lt;/p&gt;
&lt;p&gt;Forwarding &lt;code&gt;fmt&lt;/code&gt; straight down is right in exactly one case: when the part being rendered &lt;strong&gt;is&lt;/strong&gt; the
whole rendering, as for a wrapper around a single field.&lt;/p&gt;
&lt;p&gt;A type with no &lt;code&gt;Display&lt;/code&gt; cannot be printed, and the diagnostic says what to write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;
    k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;cannot print a Scale value — write an &apos;impl sysl.Display for Scale&apos; to say how it renders
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-slice-or-an-array-of-anything-printable&quot;&gt;A slice or an array of anything printable&lt;/h3&gt;
&lt;p&gt;One &lt;code&gt;impl[T: Display] Display for []T&lt;/code&gt; covers every slice, so the element type only has to render
itself. A slice of a type you wrote works the moment that type does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a rect&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ns = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; rs = [&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(ns)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(rs[..])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;ns[..]&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%14s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[1, 2, 3]
[a rect, a rect]
[     [1, 2, 3]]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A fixed-size array renders too&lt;/strong&gt;, and by one block rather than one per length:
&lt;code&gt;impl[const N: usize, T: Display] Display for [N]T&lt;/code&gt;. A length is a &lt;em&gt;value parameter&lt;/em&gt;, so it is an
argument to the array shape rather than part of it, and one implementation covers every array there
is. It delegates to the block above, so an array and its &lt;code&gt;[..]&lt;/code&gt; view render identically — which is
why &lt;code&gt;print(ns)&lt;/code&gt; and &lt;code&gt;print(ns[..])&lt;/code&gt; are the same line of output.&lt;/p&gt;
&lt;p&gt;Before value generics a length was part of a type’s shape: &lt;code&gt;[2]T&lt;/code&gt; and &lt;code&gt;[3]T&lt;/code&gt; were two shapes with no
way to be generic over the difference, so printing a fixed array meant taking the view by hand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The elements are written as they are met&lt;/strong&gt;, never gathered. Gathering would need a growable buffer,
&lt;code&gt;sysl.buf&lt;/code&gt; is built &lt;em&gt;on&lt;/em&gt; this module rather than under it, and an allocation on the printing path is
the one thing printing does not have — so a slice prints under &lt;code&gt;@no_alloc&lt;/code&gt; exactly as a number does.&lt;/p&gt;
&lt;p&gt;That leaves the width, which has to be known before the first byte goes out. It is learned by
rendering once into a sink that adds up what it is given and keeps none of it, so the cost of a
padded slice is a second pass rather than a buffer, and an unpadded one is a single pass.&lt;/p&gt;
&lt;h3 id=&quot;saying-how-a-slice-of-your-type-renders&quot;&gt;Saying how a slice of &lt;em&gt;your&lt;/em&gt; type renders&lt;/h3&gt;
&lt;p&gt;The block above covers every slice, which would ordinarily be the end of the matter: two
implementations for one type are refused, and a program writing &lt;code&gt;impl Display for []Rect&lt;/code&gt; would be
told the library got there first. Say &lt;strong&gt;&lt;code&gt;override&lt;/code&gt;&lt;/strong&gt; and it is yours:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) = &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a rect&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; []&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;) =
        &lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.len) + &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; rects&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, fmt)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; rs = [&lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(rs[..])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(rs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 rects
a rect
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The keyword goes on the &lt;strong&gt;overriding&lt;/strong&gt; side, and that is the whole of it — nothing in the library
had to permit this in advance. A more specific implementation is found first, so &lt;code&gt;[]Rect&lt;/code&gt; reaches
yours and every other slice still reaches the library’s.&lt;/p&gt;
&lt;p&gt;Two things it deliberately does not do. It does not let you replace an implementation for a type that
is not yours — &lt;code&gt;override impl Display for []int&lt;/code&gt; is refused, because &lt;code&gt;[]int&lt;/code&gt; names nothing of your
program’s and &lt;a href=&quot;/reference/traits/&quot;&gt;coherence&lt;/a&gt; puts that block in the library or nowhere. And it does
not silence the ordinary duplicate: leave the keyword off and the second implementation is refused
exactly as it always was, which is how a block written twice by accident still gets found.&lt;/p&gt;
&lt;h2 id=&quot;hashing&quot;&gt;Hashing&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Hash&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;u64&lt;/code&gt; rather than a &lt;code&gt;usize&lt;/code&gt;&lt;/strong&gt;, so a hash means the same thing on every target — a table moved
between a 32-bit and a 64-bit machine does not rebucket because the word size changed.&lt;/p&gt;
&lt;p&gt;As with rendering, the built-ins reach a named mixer — through written &lt;code&gt;impl&lt;/code&gt;s, one per closed type
and a single blanket over the integers, which is what makes a built-in erasable to a &lt;code&gt;&amp;amp;Hash&lt;/code&gt; rather
than merely usable under a &lt;code&gt;Hash&lt;/code&gt; bound. Those mixers are public, which is what lets a &lt;code&gt;Hash&lt;/code&gt; written
for a struct mix its own fields:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;mixer&lt;/th&gt;&lt;th&gt;for&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hash_u64&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every integer up to 64 bits&lt;/td&gt;&lt;td&gt;splitmix64’s finalizer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hash_u128&lt;/code&gt;&lt;/td&gt;&lt;td&gt;every integer above 64 bits&lt;/td&gt;&lt;td&gt;the two halves mixed separately, then combined&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hash_bool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;bool&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;hash_u64&lt;/code&gt; of 1 or 0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hash_str&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;FNV-1a over the bytes&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A value wider than 128 bits is truncated to 128 before it reaches &lt;code&gt;hash_u128&lt;/code&gt;.&lt;/strong&gt; That keeps the law
a hash owes — equal values hash equal — and gives up only collision resistance among values that
agree in their low 128 bits. If something ever keys a table on values that wide, mixing in 128-bit
chunks is the fix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hash_u64&lt;/code&gt; is a finalizer and not the identity for a reason.&lt;/strong&gt; Consecutive integers are the input a
hash table actually meets — loop counters, row ids, sizes — and an identity hash makes them collide
in a row rather than spreading them. A mixer costs three multiplies and turns a counter into
something a table can bucket on.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;bool&lt;/code&gt; gets its own mixer because one bit does not widen to a number in this language; a &lt;code&gt;string&lt;/code&gt;
gets FNV-1a over its bytes because a &lt;code&gt;string&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; a validated &lt;code&gt;[]u8&lt;/code&gt;, so there is nothing to
decode and every byte counts once.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Key&lt;/span&gt;
    name: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Hash&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Key&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;hash_u64&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hash_str&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.name) * &lt;span class=&quot;hl-number&quot;&gt;0x100000001b3&lt;/span&gt; ^ &lt;span class=&quot;hl-function&quot;&gt;hash_u64&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n)))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Key&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;() != &lt;span class=&quot;hl-type&quot;&gt;Key&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The multiply-then-xor is the shape to copy: &lt;code&gt;0x100000001b3&lt;/code&gt; is FNV’s prime, and mixing with it before
the xor is what makes &lt;strong&gt;order&lt;/strong&gt; matter. A plain xor of the field hashes would give &lt;code&gt;Key(&amp;quot;a&amp;quot;, 1)&lt;/code&gt; and
a hypothetical &lt;code&gt;Key&lt;/code&gt; with the fields swapped the same bucket.&lt;/p&gt;
&lt;p&gt;Because the memberships are &lt;code&gt;impl&lt;/code&gt;s, a built-in can be &lt;strong&gt;erased&lt;/strong&gt; to a trait object — a method table
holds function pointers, and an &lt;code&gt;impl&lt;/code&gt; is what supplies one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; xs: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&amp;amp;&lt;span class=&quot;hl-type&quot;&gt;Hash&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; h &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(h.&lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;() != &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The widening is the law rather than an implementation detail: &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; are the same number,
they compare equal across widths, and so they hash equal — each becomes the same &lt;code&gt;u64&lt;/code&gt; before it
reaches the mixer.&lt;/p&gt;
&lt;h2 id=&quot;subscripting-a-type-of-your-own&quot;&gt;Subscripting a type of your own&lt;/h2&gt;
&lt;p&gt;A built-in array or slice is indexed by walking to an address, and that is the compiler’s business.
These two traits are what &lt;code&gt;b[i]&lt;/code&gt; means when the receiver is a type somebody wrote:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Index&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;I&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;I&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IndexSet&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;I&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;index_set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;I&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reading and writing are &lt;strong&gt;separate traits&lt;/strong&gt; because a type may offer one without the other — a view
that computes its elements has an &lt;code&gt;Index&lt;/code&gt; and no &lt;code&gt;IndexSet&lt;/code&gt; to give.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    cells: [&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Index&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cells[i]

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IndexSet&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;index_set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cells[i] = v

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g: &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;

g[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], g[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The difference from a built-in subscript is not cosmetic: reading through &lt;code&gt;Index&lt;/code&gt; is a call, so it
yields a &lt;em&gt;value&lt;/em&gt; rather than a place.&lt;/strong&gt; That is why compound assignment through one is refused rather
than quietly expanding:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    cells: [&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Index&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cells[i]

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;IndexSet&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;index_set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.cells[i] = v

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; g: &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;

g[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+=&apos; on an element read through &apos;sysl.Index&apos; would evaluate the receiver and the index twice — write it out as &apos;b[i] = b[i] + …&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The expansion would be &lt;code&gt;g.index_set(0, g.index(0) + 1)&lt;/code&gt;, which evaluates &lt;code&gt;g&lt;/code&gt; twice and the index
expression twice. For a &lt;code&gt;Grid&lt;/code&gt; that is merely wasteful; for a receiver that is a function call, or an
index that advances a cursor, it is wrong. The refusal makes you write the version whose cost you can
see.&lt;/p&gt;
&lt;p&gt;This is the &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;sysl.buf&lt;/code&gt;&lt;/a&gt; &lt;code&gt;Buf[T]&lt;/code&gt; arrangement too, and there it earns something
specific: subscripting reaches the bounds-checked members rather than the storage, so &lt;code&gt;b[i]&lt;/code&gt; cannot
read a slot past the count that the backing slice still has.&lt;/p&gt;
&lt;h2 id=&quot;walking-a-type-of-your-own&quot;&gt;Walking a type of your own&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Iterate&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;E&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what a &lt;code&gt;for&lt;/code&gt; asks of what it walks, when what it walks is not a range, an array or a slice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;next&lt;/code&gt; answers with an &lt;code&gt;Option&lt;/code&gt;&lt;/strong&gt;, so ending and yielding are one question with one answer. A
separate &lt;code&gt;has_next&lt;/code&gt; would be two, and two questions can disagree — the classic iterator bug is a
&lt;code&gt;has_next&lt;/code&gt; that says yes and a &lt;code&gt;next&lt;/code&gt; that then has nothing.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Iterate&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
2
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The cursor is advanced through &lt;code&gt;*self&lt;/code&gt;, and a loop iterates a copy of what it was given.&lt;/strong&gt; &lt;code&gt;c&lt;/code&gt; above
is untouched by the walk. That matters for a cursor meaning to report something &lt;em&gt;after&lt;/em&gt; the walk — a
reader’s failure latch, say — which is why such a cursor has to borrow what it reports on rather than
own it. &lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;sysl.io&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;lines()&lt;/code&gt; is built that way for exactly this reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;for&lt;/code&gt; also walks an erased cursor&lt;/strong&gt;, since &lt;code&gt;next&lt;/code&gt; takes &lt;code&gt;*self&lt;/code&gt; and mentions no &lt;code&gt;Self&lt;/code&gt; elsewhere
— so &lt;code&gt;Iterate&lt;/code&gt; has an object, and the loop calls its member through the table. The element type is
whatever the object was erased to, which is why there is nothing to annotate:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Iterate&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;]
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; it: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Iterate&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Countdown&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; it &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
2
1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the same rule that lets a trait object satisfy a bound — a &lt;code&gt;for&lt;/code&gt; asks what may be &lt;em&gt;called&lt;/em&gt; on
the value, and a table is an answer to that. It means a function may hand back a cursor without
saying which one it built.&lt;/p&gt;
&lt;h2 id=&quot;calling-a-value&quot;&gt;Calling a value&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fn0&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fn1&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, a: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;trait&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fn2&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, a: &lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;B&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;R&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;…and &lt;code&gt;Fn3&lt;/code&gt;, &lt;code&gt;Fn4&lt;/code&gt;. &lt;strong&gt;One trait per arity&lt;/strong&gt;, because a call’s argument types are part of what it
promises and there is no way to write that variadically.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;call&lt;/code&gt; takes &lt;code&gt;*self&lt;/code&gt; so a callable may carry mutable state, which is what makes a counter writable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fn0&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c.&lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(), c.&lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(), c.&lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A function type &lt;code&gt;A -&amp;gt; R&lt;/code&gt; is &lt;code&gt;Fn1[A, R]&lt;/code&gt; at the use&lt;/strong&gt;, so a hand-written callable goes wherever a
closure goes — the parameter does not know or care which it got:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;
    k: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fn1&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;call&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a * &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.k

&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(x)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-type&quot;&gt;Scale&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(s, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(n -&amp;gt; n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;15 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is worth knowing when a closure is not enough: a struct can have several members, be printed,
be compared, and still be passed as the function.&lt;/p&gt;
&lt;h2 id=&quot;tuples&quot;&gt;Tuples&lt;/h2&gt;
&lt;p&gt;A tuple is comparable, hashable and printable &lt;strong&gt;exactly when its parts are&lt;/strong&gt;. The memberships are
structural, so nothing has to be written per tuple type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) &amp;lt; (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) == (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;() != (&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;hash&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%10s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;(1, 2) (1, 2, 3)
true true true
[    (3, 4)]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every arity, not a list of them.&lt;/strong&gt; The four rows are written over a
&lt;a href=&quot;/reference/generics/#a-parameter-may-stand-for-a-list-of-types&quot;&gt;type pack&lt;/a&gt;, so one block each
covers a tuple of any width:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Eq&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; (..&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;eq&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, rhs: &lt;span class=&quot;hl-type&quot;&gt;Self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-type&quot;&gt;A&lt;/span&gt;.len
            &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.i != rhs.i &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;

        &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; eq&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the library’s own source, quoted for its shape, and it is worth reading as what a pack is
for: &lt;code&gt;..A&lt;/code&gt; stands for the parts, the bound on it is asked of every one of them, and &lt;code&gt;for const&lt;/code&gt; is
unrolled so &lt;code&gt;self.i&lt;/code&gt; is an ordinary field selection at whatever type that part has.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2.5&lt;/span&gt;, &lt;span class=&quot;hl-string&quot;&gt;&apos;z&apos;&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;) == (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;), (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;) &amp;lt; (&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;(1, a, true, 2.5, z)
true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Ord&lt;/code&gt; on a tuple is lexicographic, and each position runs a ladder rather than a single &lt;code&gt;&amp;lt;&lt;/code&gt;, because
deciding a position takes &lt;strong&gt;two&lt;/strong&gt; comparisons: this one is less, or it is greater, or the two agree
and the next position decides. Every position agreeing is not-less, which is where the loop ends.&lt;/p&gt;
&lt;p&gt;A wide tuple is still usually worse code than a struct with field names — &lt;code&gt;.3&lt;/code&gt; says nothing and
&lt;code&gt;.hue&lt;/code&gt; says everything. What has changed is that the language is no longer the thing telling you so.&lt;/p&gt;
&lt;h2 id=&quot;operators-are-here-and-are-documented-elsewhere&quot;&gt;Operators are here, and are documented elsewhere&lt;/h2&gt;
&lt;p&gt;The fourteen operator traits — &lt;code&gt;Add&lt;/code&gt; through &lt;code&gt;Ord&lt;/code&gt; — are declared in this module and are covered in
full under &lt;a href=&quot;/reference/expressions/&quot;&gt;operator dispatch&lt;/a&gt;, because which trait a &lt;code&gt;+&lt;/code&gt; reaches is a rule
about the &lt;em&gt;operator&lt;/em&gt; rather than about the trait.&lt;/p&gt;
&lt;p&gt;Two things about them belong here, where the declarations are:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Each trait requires exactly one method.&lt;/strong&gt; Implementing comparison means writing &lt;code&gt;lt&lt;/code&gt; and nothing
else — &lt;code&gt;a &amp;gt; b&lt;/code&gt; is &lt;code&gt;lt(b, a)&lt;/code&gt;, &lt;code&gt;a &amp;lt;= b&lt;/code&gt; is &lt;code&gt;!lt(b, a)&lt;/code&gt; — so there is no way for four functions to
disagree with each other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; are independent, not a hierarchy.&lt;/strong&gt; That is the scalar law lifted intact: &lt;code&gt;bool&lt;/code&gt; and
the pointer modes have &lt;code&gt;==&lt;/code&gt; and no &lt;code&gt;&amp;lt;&lt;/code&gt;. Implementing one does not give you the other:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;
    v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ord&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;lt&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, rhs: &lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.v &amp;lt; rhs.v

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &amp;lt; &lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) == &lt;span class=&quot;hl-type&quot;&gt;M&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;==&apos; is not defined for M
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;everything-else-is-an-import-away&quot;&gt;Everything else is an import away&lt;/h2&gt;
&lt;p&gt;A name that is &lt;em&gt;not&lt;/em&gt; in the core is not in scope, and the diagnostic is the ordinary one for an
undefined function rather than anything that hints at a module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;byte_sink&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;undefined function &apos;byte_sink&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the auto-import rule doing its job in the direction that matters. Only the standard module
arrives unasked-for; a submodule is an offer, and taking it up is written down where a reader can see
it.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/text/&quot;&gt;&lt;code&gt;sysl.text&lt;/code&gt;&lt;/a&gt; — bytes to text, and back.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Control flow</title>
    <link href="https://sysl.sh/tour/control-flow/"/>
    <id>https://sysl.sh/tour/control-flow/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Everything yields a value — including the loops, which is less strange than it sounds.</summary>
    <content type="html">&lt;h2 id=&quot;if-yields-a-value&quot;&gt;&lt;code&gt;if&lt;/code&gt; yields a value&lt;/h2&gt;
&lt;p&gt;There is no ternary operator, because there is no need for one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;55&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; label = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;even&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;odd&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, label)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;55 is odd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written across several lines it uses &lt;code&gt;elif&lt;/code&gt; and reads as ordinary control flow. It is the same
expression either way — the value is simply unused when nothing wants it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(score: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; score &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;excellent&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; score &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;70&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;fine&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; score &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scraped it&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;91&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;72&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;12&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;excellent fine scraped it no
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;if&lt;/code&gt; being &lt;em&gt;used&lt;/em&gt; for its value needs an &lt;code&gt;else&lt;/code&gt;. Without one the open branch has no value to
give, and the compiler says so rather than inventing a zero.&lt;/p&gt;
&lt;h2 id=&quot;match-picks-an-arm&quot;&gt;&lt;code&gt;match&lt;/code&gt; picks an arm&lt;/h2&gt;
&lt;p&gt;Arms match a literal, a &lt;code&gt;|&lt;/code&gt;-separated set of alternatives, a range, or fall through to &lt;code&gt;else&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; | &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;small&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;medium&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;large&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;55&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;size&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1000&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;empty small medium large
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;match&lt;/code&gt; used for a value has to be &lt;strong&gt;exhaustive&lt;/strong&gt;. That is what the &lt;code&gt;else&lt;/code&gt; is doing above: &lt;code&gt;int&lt;/code&gt;
has more values than the arms name, so without it there would be inputs with no answer. Where the
arms genuinely cover everything — the variants of an enum, say — no &lt;code&gt;else&lt;/code&gt; is needed and adding one
is a mistake, because it is the thing that would stop the compiler telling you about a variant you
forgot when you add it later.&lt;/p&gt;
&lt;h2 id=&quot;loops&quot;&gt;Loops&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;while&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt; are the ordinary ones. A range is written &lt;code&gt;a..b&lt;/code&gt; for inclusive and &lt;code&gt;a..&amp;lt;b&lt;/code&gt; for
exclusive, which are the same two operators used everywhere else in the language:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sum = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; sum = sum + i

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; doubled = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; doubled += i * &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sum:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, sum, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;doubled:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, doubled)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;sum: 55 doubled: 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;do&lt;/code&gt; puts the body on the same line. Indent it instead and the &lt;code&gt;do&lt;/code&gt; goes away:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; countdown = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; countdown &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;t minus&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, countdown)
    countdown -= &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;go&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;t minus 3
t minus 2
t minus 1
go
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the body has to run before anything is asked, put the test at the foot with &lt;code&gt;do … while&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; rest = n
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt;
        s = &lt;span class=&quot;hl-function&quot;&gt;str&lt;/span&gt;(rest % &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;) + s
        rest /= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; rest &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    s

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;digits&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4071&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 4071
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Written as a &lt;code&gt;while&lt;/code&gt;, that prints nothing at all for &lt;code&gt;0&lt;/code&gt;, and the usual patch is a special case
above the loop. The test at the foot is the fix. The one-line form is &lt;code&gt;do rest /= 10 while rest &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;continue&lt;/code&gt; in a &lt;code&gt;do … while&lt;/code&gt; runs the &lt;strong&gt;test&lt;/strong&gt;, which is why the loop is worth having rather than
writing &lt;code&gt;loop&lt;/code&gt; with &lt;code&gt;if !cond then break&lt;/code&gt; at the bottom: that shape has no test for a &lt;code&gt;continue&lt;/code&gt; to
reach, so the first one added to it skips the exit and the loop never finishes.&lt;/p&gt;
&lt;p&gt;A loop with nothing to test is written &lt;code&gt;loop&lt;/code&gt;, which is what &lt;code&gt;while true&lt;/code&gt; was always being used to
say:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
    n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;stopped at&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;stopped at 4
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;loops-yield-values-too&quot;&gt;Loops yield values too&lt;/h2&gt;
&lt;p&gt;This is the part worth slowing down for, because it replaces a pattern that is otherwise written
with a flag variable. &lt;code&gt;break&lt;/code&gt; carries a value out, and an &lt;code&gt;else&lt;/code&gt; block — after the body, as in
Python — supplies the value when the loop finishes &lt;em&gt;without&lt;/em&gt; breaking:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first_multiple&lt;/span&gt;(of: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, upto: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..upto
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; i % of == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt; i
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;first_multiple&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;first_multiple&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;23&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 -1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Read the &lt;code&gt;else&lt;/code&gt; as “and if it ran out”. Every &lt;code&gt;break&lt;/code&gt; value and the &lt;code&gt;else&lt;/code&gt; value share one type,
which becomes the loop’s type. Without an &lt;code&gt;else&lt;/code&gt;, finishing normally yields nothing — so a
value-carrying &lt;code&gt;break&lt;/code&gt; needs one, and the compiler will tell you if it is missing.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;loop&lt;/code&gt; takes no &lt;code&gt;else&lt;/code&gt;, because it has no normal completion to have one for. That has a
consequence worth knowing: a &lt;code&gt;loop&lt;/code&gt; that nothing breaks out of never finishes, so it can stand as
the last thing a function owing a value does, with nothing after it to supply that value. &lt;code&gt;while true&lt;/code&gt; cannot say this — a condition is an expression the compiler does not evaluate, so a loop
written that way looks like one that might finish and the code after it looks reachable.&lt;/p&gt;
&lt;h2 id=&quot;iterating-over-things&quot;&gt;Iterating over things&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;for&lt;/code&gt; walks a collection directly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; primes = [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; p &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; primes &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += p

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, primes.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;total:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;count: 5 total: 28
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when the stepping is something a range cannot describe, the three-clause form is there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;; i *= &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;doublings under 100:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;doublings under 100: 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;;&lt;/code&gt; in that header is the only place in the language it appears. It is deliberately not a
statement terminator — a line ends a statement, and a token that could also end one would give the
language two answers to the same question.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/functions/&quot;&gt;functions&lt;/a&gt;, which have been quietly appearing in every example so far.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Contracts and constrained types</title>
    <link href="https://sysl.sh/tour/contracts/"/>
    <id>https://sysl.sh/tour/contracts/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>A type that carries a rule, a struct that keeps one, and a function that states what it requires.</summary>
    <content type="html">&lt;p&gt;Two features that are really one idea: &lt;strong&gt;write the rule down where the thing is declared, and let the
compiler put the check in.&lt;/strong&gt; A constrained type narrows what values a scalar may hold; a struct
invariant says what has to stay true of a value’s fields; a contract says what a function requires and
what it promises.&lt;/p&gt;
&lt;h2 id=&quot;one-declaration-form-three-independent-parts&quot;&gt;One declaration form, three independent parts&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;type Name = [new] Base [within lo..hi] [where predicate]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;new&lt;/code&gt;, &lt;code&gt;within&lt;/code&gt; and &lt;code&gt;where&lt;/code&gt; are contextual keywords — ordinary identifiers everywhere else, so a
field may still be called &lt;code&gt;where&lt;/code&gt;. Each of the three parts may be left out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt;   = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;      = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Even&lt;/span&gt;     = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;where&lt;/span&gt; value % &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;     = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; e: &lt;span class=&quot;hl-type&quot;&gt;Even&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5.5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, e, &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(m))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 8 5.5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value the predicate is about is named &lt;code&gt;value&lt;/code&gt;, and it is bound only inside the predicate.&lt;/p&gt;
&lt;p&gt;The base is a &lt;strong&gt;scalar&lt;/strong&gt; — an integer, a float or a &lt;code&gt;char&lt;/code&gt;. A constraint here is a check on a value,
and the two ways to narrow an aggregate are the struct invariant below and, for an enum, having fewer
variants.&lt;/p&gt;
&lt;p&gt;One combination is rejected: &lt;code&gt;type Alias = int&lt;/code&gt;, with no &lt;code&gt;new&lt;/code&gt; and no constraint. It neither narrows
the values nor makes a new type, so it declares nothing at all — there is no &lt;code&gt;typedef&lt;/code&gt; to write by
hand, and the diagnostic says so at the declaration. The one declaration of that shape is the one the
compiler writes for you, when a &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c type&lt;/code&gt;&lt;/a&gt; asks the C compiler what a typedef in a
header actually is.&lt;/p&gt;
&lt;h2 id=&quot;new-is-what-makes-it-a-type&quot;&gt;&lt;code&gt;new&lt;/code&gt; is what makes it a type&lt;/h2&gt;
&lt;p&gt;Without &lt;code&gt;new&lt;/code&gt;, a constrained type &lt;strong&gt;is&lt;/strong&gt; its base with a checked range. &lt;code&gt;Age&lt;/code&gt; and &lt;code&gt;int&lt;/code&gt; are the same
type, values flow between them freely, and what the declaration buys is the check:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;birthday&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = a + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;birthday&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;41&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Being its base means its &lt;strong&gt;name converts what the base’s name converts&lt;/strong&gt;. &lt;code&gt;Age(n)&lt;/code&gt; on a &lt;code&gt;usize&lt;/code&gt; is
the &lt;code&gt;int(n)&lt;/code&gt; you would otherwise write, and the range is checked on the value that arrives — so the
conversion is a conversion rather than a way past the constraint:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f: &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;7.9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;(n), &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;(f))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That matters most where the base cannot be &lt;em&gt;named&lt;/em&gt;. A &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c type&lt;/code&gt;&lt;/a&gt; is a transparent
subtype of a width the C compiler measured for the target being built for, so &lt;code&gt;u32(n)&lt;/code&gt; would be one
machine’s answer written into the source, and the type’s own name is the only portable way in.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;new&lt;/code&gt; it is a &lt;strong&gt;distinct nominal type&lt;/strong&gt;, and that is a large difference. Two derived types over
one base do not mix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Feet&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Meters&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; f = &lt;span class=&quot;hl-type&quot;&gt;Feet&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt;(m + f))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+&apos; needs matching types, got Meters and Feet
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A derived type does not mix with its &lt;strong&gt;base&lt;/strong&gt; either, and going in either direction is a written
conversion: &lt;code&gt;Meters(x)&lt;/code&gt; wraps and &lt;code&gt;f64(m)&lt;/code&gt; unwraps, and the wrap is where the constraint is checked.
The wrap takes a value that is already at the base — &lt;code&gt;Meters(3.0)&lt;/code&gt; and not &lt;code&gt;Meters(3)&lt;/code&gt; — which is the
one place the two kinds differ in call position, and it follows from &lt;code&gt;new&lt;/code&gt; making the type distinct.&lt;/p&gt;
&lt;p&gt;The payoff is a specific bug. A table-driven program has several small integers that index different
things — a task number, a lock number, a priority level — and the mistake such a program actually
makes is passing one where another was wanted. Three &lt;code&gt;new u8&lt;/code&gt;s with three ranges make that a compile
error instead of a plausible-looking wrong answer. It is an argument about &lt;strong&gt;types&lt;/strong&gt;, not about
checking.&lt;/p&gt;
&lt;h3 id=&quot;a-derivation-inherits-its-base-s-behaviour-and-may-replace-none-of-it&quot;&gt;A derivation inherits its base’s behaviour and may replace none of it&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;new&lt;/code&gt; type over a scalar arrives with everything the scalar could do — &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt; and the
rest — working at itself and producing itself. And almost no &lt;code&gt;impl&lt;/code&gt; may replace or extend any of it.&lt;/p&gt;
&lt;p&gt;Inheriting is right because a derivation does not change what the values &lt;em&gt;are&lt;/em&gt;: a &lt;code&gt;Slot&lt;/code&gt; is some of
the &lt;code&gt;u8&lt;/code&gt;s, not a different set of things stored in a byte. Refusing to replace is the harder call. If
&lt;code&gt;Stamp&lt;/code&gt; could redefine &lt;code&gt;&amp;lt;&lt;/code&gt;, then &lt;code&gt;Stamp&lt;/code&gt; would be a set of &lt;code&gt;i64&lt;/code&gt;s that do not order the way &lt;code&gt;i64&lt;/code&gt;s
order, and every fact the base guarantees would hold only until somebody looked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rendering is the exception, and the reason says where the line is.&lt;/strong&gt; How a value prints is not a
fact the base guarantees about the value — a &lt;code&gt;Stamp&lt;/code&gt; printing as &lt;code&gt;#7&lt;/code&gt; is the same &lt;code&gt;i64&lt;/code&gt; it was — so a
derivation may take that one row back with an
&lt;a href=&quot;/reference/errors/#except-rendering-which-a-derivation-may-take-back&quot;&gt;&lt;code&gt;override impl Display&lt;/code&gt;&lt;/a&gt;.
Ordering and arithmetic it may not.&lt;/p&gt;
&lt;p&gt;So the answer to “I want my own &lt;code&gt;+&lt;/code&gt;“ is that you do not want a derivation, you want a &lt;strong&gt;struct&lt;/strong&gt;:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;a &lt;code&gt;new&lt;/code&gt; derivation&lt;/th&gt;&lt;th&gt;a one-field struct&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;distinct type&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;td&gt;yes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;the base’s catalogue&lt;/td&gt;&lt;td&gt;free; only &lt;code&gt;Display&lt;/code&gt; is replaceable&lt;/td&gt;&lt;td&gt;nothing, write it all&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an operation the base does not have&lt;/td&gt;&lt;td&gt;impossible&lt;/td&gt;&lt;td&gt;ordinary&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;an operation the base has that is now nonsense&lt;/td&gt;&lt;td&gt;present anyway&lt;/td&gt;&lt;td&gt;absent&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;rendering as something other than the base&lt;/td&gt;&lt;td&gt;&lt;code&gt;override impl Display&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ordinary&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Use a derivation for an &lt;strong&gt;identity&lt;/strong&gt; — a slot number, a handle, a unit-tagged measurement. Use a
struct for a &lt;strong&gt;quantity with an algebra of its own&lt;/strong&gt;: an instant plus a duration is an instant, an
instant plus an instant is nonsense, and no derived scalar can be told the difference.&lt;/p&gt;
&lt;h2 id=&quot;where-a-constraint-is-checked&quot;&gt;Where a constraint is checked&lt;/h2&gt;
&lt;p&gt;At every point a value of the type is &lt;strong&gt;produced&lt;/strong&gt;, and nowhere else. That is not a list of syntactic
forms to memorize — a value comes to have the type wherever it flows into a slot the type is written
on: an initializer, an assignment, an argument, a returned value, a cast, a struct field, an array
element, an enum payload, an item entering a generic container instantiated at the type.&lt;/p&gt;
&lt;p&gt;A value that already has the type is not re-checked when it is merely read, passed along or copied.
It could not have got there unchecked.&lt;/p&gt;
&lt;p&gt;One site is closed by not existing. A constrained subtype has &lt;strong&gt;no zero value&lt;/strong&gt;, whether or not its
range contains zero:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;Age has no zero value, so &apos;a&apos; needs an initial value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Making that the &lt;em&gt;type’s&lt;/em&gt; rule rather than the range’s means widening a range never silently changes
whether a declaration compiles somewhere else.&lt;/p&gt;
&lt;p&gt;A violated check &lt;strong&gt;traps&lt;/strong&gt;. It is not an error value and it is not catchable, and there is
deliberately no &lt;code&gt;try&lt;/code&gt; form returning an &lt;code&gt;Option&lt;/code&gt;: a constrained type states something its values are,
so a value that is not one of them is a bug in the code that made it rather than a condition to
handle.&lt;/p&gt;
&lt;h2 id=&quot;asking-instead-of-trapping&quot;&gt;Asking instead of trapping&lt;/h2&gt;
&lt;p&gt;Which is what the type’s own name is for. A constrained type answers a small closed set of
&lt;strong&gt;attributes&lt;/strong&gt;, written with &lt;code&gt;::&lt;/code&gt; so they stay out of the member namespace and no &lt;code&gt;impl&lt;/code&gt; can shadow
one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Last&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Valid&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Valid&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Slot&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Range&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(s))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sum of every slot:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, total)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 7 true false
sum of every slot: 28
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;First&lt;/code&gt; and &lt;code&gt;Last&lt;/code&gt; are the bounds — note &lt;code&gt;Last&lt;/code&gt; is 7, one below the written exclusive bound. &lt;code&gt;Succ&lt;/code&gt;
and &lt;code&gt;Pred&lt;/code&gt; step, and &lt;strong&gt;trap&lt;/strong&gt; at the ends rather than saturating or wrapping, on the same argument as
the produce sites. &lt;code&gt;Range&lt;/code&gt; is the whole range as a &lt;code&gt;for&lt;/code&gt; loop’s iterable.&lt;/p&gt;
&lt;p&gt;Every attribute but one speaks the subtype: a bound of &lt;code&gt;T&lt;/code&gt; is a value of &lt;code&gt;T&lt;/code&gt;, and the values &lt;code&gt;Range&lt;/code&gt;
walks are &lt;code&gt;T&lt;/code&gt;s. That is invisible on a transparent subtype and it is the point on a derived one, which
would otherwise be the only kind of type whose own attributes had to be cast back into it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Valid&lt;/code&gt; is the exception, and the asymmetry is its job: it takes the &lt;strong&gt;base&lt;/strong&gt;, because asking whether
a value is a &lt;code&gt;T&lt;/code&gt; is only a question about something that is not one yet. It is total — it never traps
— which is what makes it the question form, and a cast after a &lt;code&gt;Valid&lt;/code&gt; that answered true is the
ordinary way in.&lt;/p&gt;
&lt;h2 id=&quot;struct-invariants&quot;&gt;Struct invariants&lt;/h2&gt;
&lt;p&gt;A struct body may carry &lt;code&gt;invariant&lt;/code&gt; clauses among its fields, each an expression over the struct’s own
fields, in scope by name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;
    lo: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    hi: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; lo &amp;lt;= hi
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; hi - lo &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;4096&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w = &lt;span class=&quot;hl-type&quot;&gt;Window&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)

w.hi += &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.lo, w.hi, w.hi - w.lo)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 15 13
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Several clauses all have to hold, and each is checked independently so the diagnostic names the one
that failed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Checked at every write, not only at construction&lt;/strong&gt; — that is the part worth stating, because the
cheap implementation checks the constructor and calls it done. Assigning a single field counts,
including a compound assignment and an increment. So does a field written through a pointer, a field
written into an array element, and a field written &lt;em&gt;inside&lt;/em&gt; one of those.&lt;/p&gt;
&lt;p&gt;The consequence is the intended one: a sequence of writes that ends in a valid state but passes
through an invalid one &lt;strong&gt;traps at the step that broke it&lt;/strong&gt;. There is no “I am mid-update” mode.&lt;/p&gt;
&lt;p&gt;When a struct cannot be updated one field at a time, there are three answers and the order matters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Look for an order in which no intermediate state is illegal&lt;/strong&gt;, and often there is one. A
&lt;code&gt;count &amp;lt;= high&lt;/code&gt; watermark is updated by raising the ceiling before the floor. That the same clause
accepts one order and refuses the other is the whole of the answer here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ask whether the clause is pointing at a redundant field.&lt;/strong&gt; An invariant relating two fields is a
claim about the &lt;em&gt;representation&lt;/em&gt;, and the trap is often the compiler observing that the struct
carries one fact twice. A ring buffer keeping &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;tail&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; cannot move any two of
them one at a time; one keeping &lt;code&gt;head&lt;/code&gt; and &lt;code&gt;count&lt;/code&gt; and computing the end has no clause to break.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Otherwise assign the whole struct&lt;/strong&gt;, and know the price — restating the whole value to move two
bytes makes a container’s own update cost the size of the container.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;contracts-on-a-function&quot;&gt;Contracts on a function&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;require&lt;/span&gt; x &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a half of a negative is not what this means&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; result &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    x / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;half&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both kinds form &lt;strong&gt;one block at the top of the body&lt;/strong&gt;. A clause after an ordinary statement is
rejected: a precondition that runs after some of the work is not a precondition, and a postcondition
is written up there because that is where a reader looks for what the function promises — not because
that is when it runs.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;require&lt;/code&gt; is checked on entry. &lt;code&gt;ensure&lt;/code&gt; is checked before &lt;strong&gt;every&lt;/strong&gt; return, including early ones. Both
take an optional message.&lt;/p&gt;
&lt;p&gt;Two names exist only inside a contract. &lt;code&gt;result&lt;/code&gt; is the value being returned, available in an &lt;code&gt;ensure&lt;/code&gt;
only. &lt;code&gt;old(expr)&lt;/code&gt; is &lt;code&gt;expr&lt;/code&gt; evaluated on entry — which is what lets a postcondition talk about what a
mutating function &lt;em&gt;changed&lt;/em&gt; rather than only about what it left behind:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n &amp;gt; &lt;span class=&quot;hl-function&quot;&gt;old&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n)

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

c.&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()
c.&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, c.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;n: 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is contracts at their most useful — on a mutating method, saying the thing the method is &lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Contracts are checked in &lt;strong&gt;every&lt;/strong&gt; build. There is no release mode that drops them, and adding one
would make a program’s meaning depend on how it was compiled.&lt;/p&gt;
&lt;h2 id=&quot;what-this-is-and-where-the-rest-of-it-is&quot;&gt;What this is, and where the rest of it is&lt;/h2&gt;
&lt;p&gt;Nothing on this page is proved while compiling: a &lt;code&gt;require&lt;/code&gt; is a branch and a trap, an invariant is a
call to a synthesized predicate, a &lt;code&gt;within&lt;/code&gt; is two comparisons. What the feature buys is that the
rule is written &lt;strong&gt;once, where the thing is declared&lt;/strong&gt;, instead of being re-checked by hand at every
call — and that when it is broken, the program stops at the write that broke it rather than somewhere
downstream where the wrong value finally mattered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The proving is a page of its own.&lt;/strong&gt; &lt;a href=&quot;/reference/verification/&quot;&gt;Verification&lt;/a&gt; adds the vocabulary a
specification needs — quantifiers, loop invariants, termination measures, &lt;code&gt;@pure&lt;/code&gt; and &lt;code&gt;@ghost&lt;/code&gt; — and
&lt;code&gt;sysl prove&lt;/code&gt;, which discharges the obligations with Why3. The two fit together the way they do
because &lt;strong&gt;a clause means one thing&lt;/strong&gt;: the prover and the running program read the same sentence, and
a check the prover proves redundant is still compiled. So nothing above changes when you start
proving, which is the point.&lt;/p&gt;
&lt;h2 id=&quot;tests-live-beside-the-code&quot;&gt;Tests live beside the code&lt;/h2&gt;
&lt;p&gt;The third checking tool, and the one that runs on examples rather than on rules. A &lt;code&gt;@test&lt;/code&gt; annotation
on an ordinary function marks it as a test, and &lt;code&gt;assert&lt;/code&gt; is what a test uses to state what it
expects:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, lo: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, hi: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &amp;lt; lo &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; lo
    &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; n &amp;gt; hi &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; hi
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; n

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;clamps_both_ends&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;above the ceiling&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;below the floor&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a value already inside is left alone&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;leaves_the_middle&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;untouched&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program prints &lt;code&gt;3 1&lt;/code&gt; and runs &lt;strong&gt;neither&lt;/strong&gt; test, which is the whole arrangement: &lt;code&gt;sysl run&lt;/code&gt;
builds the program and the tests are not part of it. They have a caller nothing else has:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sysl test clamp.sysl
running 2 tests

clamp.sysl
  ok    clamps_both_ends                      2561ms
  ok    a value already inside is left alone  3ms

2 passed, 0 failed — 2564ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A test is an ordinary function with &lt;strong&gt;no parameters, no result, and no type parameters&lt;/strong&gt; — all three
being the same requirement seen from different sides, since the runner calls it with nothing and
reads the answer off whether it returned. Each is checked at the annotation rather than at the
function, because the function is a perfectly good function and it is &lt;code&gt;@test&lt;/code&gt; that made a promise
about it.&lt;/p&gt;
&lt;p&gt;The annotation has four forms. Bare &lt;code&gt;@test&lt;/code&gt; names the test after the function; &lt;code&gt;@test(&amp;quot;a sentence&amp;quot;)&lt;/code&gt;
names it by the sentence, which is what the second one above does and why the runner prints prose
for it. The other two are for the channel this chapter has been about: &lt;code&gt;@test(should_trap)&lt;/code&gt; &lt;strong&gt;passes
by stopping the program&lt;/strong&gt;, and &lt;code&gt;@test(should_trap: &amp;quot;past the end&amp;quot;)&lt;/code&gt; additionally requires that text
in what the run printed. That is how a trap gets tested at all — there is no catching it, so the
runner is the thing that survives it.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;assert(cond)&lt;/code&gt; traps when the condition is false, and names the file and line it failed on: its
&lt;code&gt;file&lt;/code&gt; and &lt;code&gt;line&lt;/code&gt; parameters default to the &lt;a href=&quot;/reference/lexical/&quot;&gt;reserved identifiers&lt;/a&gt; &lt;code&gt;__FILE__&lt;/code&gt;
and &lt;code&gt;__LINE__&lt;/code&gt;, and a default is evaluated at the call, so they report your line rather than the
library’s.&lt;/p&gt;
&lt;p&gt;The message is &lt;strong&gt;optional&lt;/strong&gt;, and worth writing where it says something the condition does not — as
&lt;code&gt;&amp;quot;above the ceiling&amp;quot;&lt;/code&gt; does above, naming the case rather than restating the comparison. There is
still no stringizer, so nothing reconstructs the expression that failed; what changed is that a
failure carrying no message is now a location instead of the bare words “assertion failed”.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/capstone/&quot;&gt;a program that reads its input&lt;/a&gt; — putting the whole tour to work.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The complex module</title>
    <link href="https://sysl.sh/library/complex/"/>
    <id>https://sysl.sh/library/complex/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.math.complex` — `Complex[F: Float]`, generic over both float widths: the operators at two argument lists each, the transcendental set, and the branch cuts written down.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.math.complex&lt;/code&gt; is one type. It is a &lt;strong&gt;submodule&lt;/strong&gt; rather than part of
&lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;sysl.math&lt;/code&gt;&lt;/a&gt; because &lt;code&gt;Complex&lt;/code&gt; is not a name every numeric program wants in scope,
and because &lt;code&gt;sysl.math&lt;/code&gt; is mathematics &lt;em&gt;on&lt;/em&gt; the floating-point types — which is not a sentence a type
belongs in.&lt;/p&gt;
&lt;p&gt;It requires no capability, so a freestanding target has it. &lt;strong&gt;The arithmetic is reachable under
&lt;code&gt;no alloc&lt;/code&gt;; rendering one is not&lt;/strong&gt; — a specifier describes the field the &lt;em&gt;whole&lt;/em&gt; value lands in, so
the three pieces have to be gathered before the padding is applied, and gathering means a string. An
allocator-free program computes with a &lt;code&gt;Complex&lt;/code&gt; and prints its parts.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, a.&lt;span class=&quot;hl-function&quot;&gt;conj&lt;/span&gt;(), -a)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;norm_sqr&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;arg&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a + b, a - b, a * b, a / b)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a * &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, a / &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, a + &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3+4i 3-4i -3-4i
5 25 0.927295
4+2i 2+6i 11-2i -1+2i
6+8i 1.5+2i 4+4i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Importing the type is the whole of what a program does.&lt;/strong&gt; Every operator above is a conditional
conformance whose condition names &lt;code&gt;Float&lt;/code&gt; — the library’s import, not yours.&lt;/p&gt;
&lt;h2 id=&quot;generic-over-the-width-and-why-that-is-not-a-flourish&quot;&gt;Generic over the width, and why that is not a flourish&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// A rotation, written once for both widths.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;rotate&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;](z: &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;], theta: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;] = z * &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;expi&lt;/span&gt;(theta)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; wide = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; narrow = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0f32&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0f32&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;rotate&lt;/span&gt;(wide, &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;pi&lt;/span&gt;() / &lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;rotate&lt;/span&gt;(narrow, &lt;span class=&quot;hl-type&quot;&gt;f32&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;pi&lt;/span&gt;() / &lt;span class=&quot;hl-number&quot;&gt;2.0f32&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6.12323e-17+1i
-4.37114e-08+1i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Complex[F: Float]&lt;/code&gt; is generic over the &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;Float&lt;/code&gt;&lt;/a&gt; trait, so it is a &lt;code&gt;Complex[real]&lt;/code&gt;
or a &lt;code&gt;Complex[f32]&lt;/code&gt; and never a widening of one into the other. The two are ordinary structs of two
fields laid out at their own widths, with no dispatch between them — the parameter costs nothing at
run time.&lt;/p&gt;
&lt;p&gt;The library had already paid for this: &lt;code&gt;sysl.math&lt;/code&gt; made the one-trait-two-widths investment so that
&lt;code&gt;x.sqrt()&lt;/code&gt; is the same three words whichever width &lt;code&gt;x&lt;/code&gt; is. A complex type fixed at &lt;code&gt;real&lt;/code&gt; would have
been the first thing in the library to ignore it, and anyone working in binary32 would have had to
write their own.&lt;/p&gt;
&lt;p&gt;The two answers above differ in their real part because a quarter turn is not exactly representable
in binary and &lt;code&gt;f32&lt;/code&gt; has seven digits where &lt;code&gt;real&lt;/code&gt; has sixteen. That is the ordinary floating-point
fact, and the page shows it rather than choosing an example that hides it.&lt;/p&gt;
&lt;h2 id=&quot;the-surface&quot;&gt;The surface&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;]
    re: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;
    im: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// Values that need no receiver.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;one&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;i&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;from_real&lt;/span&gt;(x: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;from_polar&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;, theta: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;expi&lt;/span&gt;(theta: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]

    &lt;span class=&quot;hl-comment&quot;&gt;// What a value is.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;conj&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;norm_sqr&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;arg&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;to_polar&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; (&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;unit&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;recip&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]

    &lt;span class=&quot;hl-comment&quot;&gt;// Questions with a yes or a no.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_zero&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_real&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_imaginary&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_nan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_infinite&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_finite&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;near&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, rhs: &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;], eps: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

    &lt;span class=&quot;hl-comment&quot;&gt;// Exponentials, logarithms and roots.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;exp&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, base: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;log2&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;log10&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;powc&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, w: &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;powf&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, x: &lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;powi&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]

    &lt;span class=&quot;hl-comment&quot;&gt;// Trigonometry, circular and hyperbolic, each with its inverse.&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;sin&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;cos&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;tan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;asin&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;acos&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;atan&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;sinh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;cosh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;tanh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;asinh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;acosh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;F&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Complex&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Plus &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;Sub&lt;/code&gt;, &lt;code&gt;Mul&lt;/code&gt;, &lt;code&gt;Div&lt;/code&gt;, &lt;code&gt;Neg&lt;/code&gt;, &lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Display&lt;/code&gt; — with &lt;code&gt;Add&lt;/code&gt;, &lt;code&gt;Sub&lt;/code&gt;, &lt;code&gt;Mul&lt;/code&gt; and &lt;code&gt;Div&lt;/code&gt;
written &lt;strong&gt;twice each&lt;/strong&gt;, once for another complex number and once for a real on the right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scaling is &lt;code&gt;Mul&lt;/code&gt; at a second argument list rather than a second trait.&lt;/strong&gt; The complex numbers are a
vector space over the reals, and scaling is the operation a transform performs most often: every
sample of an inverse, every window function, every spectrum read in decibels. &lt;code&gt;z * k&lt;/code&gt; is the same
answer as &lt;code&gt;z * Complex(k, 0)&lt;/code&gt; and costs a quarter as much, and
&lt;a href=&quot;/reference/expressions/&quot;&gt;which of the two a &lt;code&gt;*&lt;/code&gt; means&lt;/a&gt; is settled by the type of its right operand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;Ord&lt;/code&gt;&lt;/strong&gt;, because the complex numbers are not ordered — no order on them is compatible
with the arithmetic:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;) &amp;lt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;&amp;lt;&apos; is not defined for sysl.math.complex.Complex[real]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;sysl keeps &lt;code&gt;Eq&lt;/code&gt; and &lt;code&gt;Ord&lt;/code&gt; independent traits precisely so a type can have the one without the other.
There is nothing to opt out of.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no scalar on the left.&lt;/strong&gt; &lt;code&gt;2.0 * z&lt;/code&gt; would need an &lt;code&gt;impl Mul[Complex[F]] for F&lt;/code&gt;, which is an
implementation of a library trait for a built-in written by a module that owns neither — and it could
not be one generic block, since &lt;code&gt;F&lt;/code&gt; is a parameter rather than a type an &lt;code&gt;impl&lt;/code&gt; can be written for.
&lt;code&gt;z * 2.0&lt;/code&gt; is the same product.&lt;/p&gt;
&lt;h2 id=&quot;constructing-one&quot;&gt;Constructing one&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;] = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;i&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i, i * i)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;from_real&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;from_polar&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;expi&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;))

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = a.&lt;span class=&quot;hl-function&quot;&gt;to_polar&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, p.&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, a.&lt;span class=&quot;hl-type&quot;&gt;unit&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;recip&lt;/span&gt;() * a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0+1i -1+0i
2+0i 2+0i 1+0i
5 0.927295 1 1+0i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;zero()&lt;/code&gt;, &lt;code&gt;one()&lt;/code&gt; and &lt;code&gt;i()&lt;/code&gt; take an annotation, and the ones beside them do not.&lt;/strong&gt; They are
&lt;a href=&quot;/reference/generics/&quot;&gt;associated functions&lt;/a&gt; of a generic type, so their width comes from what the
context expects — and there is nothing to read it off in the middle of an expression. Everything else
here is inferred from an argument: &lt;code&gt;Complex.from_real(2.0)&lt;/code&gt; is a &lt;code&gt;Complex[real]&lt;/code&gt; because &lt;code&gt;2.0&lt;/code&gt; is a
&lt;code&gt;real&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;expi(theta)&lt;/code&gt; is &lt;code&gt;from_polar&lt;/code&gt; at radius one, and it has a name because that is how it is reached — a
Fourier transform’s twiddle factor, a rotation, a phasor.&lt;/p&gt;
&lt;h2 id=&quot;exponentials-logarithms-and-trigonometry&quot;&gt;Exponentials, logarithms and trigonometry&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;exp&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;log2&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;log10&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;log&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;powi&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;), a.&lt;span class=&quot;hl-function&quot;&gt;powf&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.5&lt;/span&gt;), a.&lt;span class=&quot;hl-function&quot;&gt;powc&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;sin&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;cos&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;tan&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;sinh&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;cosh&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;tanh&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;asin&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;acos&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;atan&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a.&lt;span class=&quot;hl-function&quot;&gt;asinh&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;acosh&lt;/span&gt;(), a.&lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;-13.1288-15.2008i 1.60944+0.927295i 2+1i
2.32193+1.3378i 0.69897+0.402719i 2.32193+1.3378i
-7+24i 2+1i -0.0152837+0.395327i
3.85374-27.0168i -27.0349-3.85115i -0.000187346+0.999356i
-6.54812-7.61923i -6.58066-7.58155i 1.00071+0.00490826i
0.633984+2.30551i 0.936812-2.30551i 1.44831+0.158997i
2.29991+0.917617i 2.30551+0.936812i 0.117501+1.40992i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Three powers, because they are not the same function.&lt;/strong&gt; &lt;code&gt;powi&lt;/code&gt; is repeated squaring and is the only
one that is &lt;em&gt;exact&lt;/em&gt; — &lt;code&gt;powi(2)&lt;/code&gt; of &lt;code&gt;3+4i&lt;/code&gt; is &lt;code&gt;-7+24i&lt;/code&gt; and not something an ulp away from it. &lt;code&gt;powf&lt;/code&gt;
raises the magnitude and multiplies the angle. &lt;code&gt;powc&lt;/code&gt; goes through the logarithm, and so carries its
branch cut.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ln&lt;/code&gt; is the natural logarithm and is spelled for what it is&lt;/strong&gt;, rather than as C’s bare &lt;code&gt;log&lt;/code&gt; — which
reads as though it were the general one and is the single most common way to get a base wrong.
&lt;code&gt;log(base)&lt;/code&gt; is the general one, and it takes a &lt;em&gt;real&lt;/em&gt; base.&lt;/p&gt;
&lt;h2 id=&quot;the-operands-a-textbook-formula-does-not-survive&quot;&gt;The operands a textbook formula does not survive&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; huge = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0e200&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.0e200&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tiny = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0e-200&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1.0e-200&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(huge.&lt;span class=&quot;hl-function&quot;&gt;abs&lt;/span&gt;(), huge.&lt;span class=&quot;hl-function&quot;&gt;norm_sqr&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(huge / huge, tiny / tiny)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1.41421e+200 inf
1+0i 1+0i
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is why the module exists rather than the four-line struct a program would write for itself. Both
lines are ordinary operands whose obvious formula answers nonsense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;abs&lt;/code&gt; goes through &lt;a href=&quot;/library/math/&quot;&gt;&lt;code&gt;hypot&lt;/code&gt;&lt;/a&gt;, never &lt;code&gt;norm_sqr().sqrt()&lt;/code&gt;.&lt;/strong&gt; The magnitude of
&lt;code&gt;1e200 + 1e200i&lt;/code&gt; is about &lt;code&gt;1.4e200&lt;/code&gt; and is perfectly representable; its &lt;em&gt;squared&lt;/em&gt; magnitude is not,
and squaring first would have thrown the answer away before taking the root. &lt;code&gt;norm_sqr&lt;/code&gt; overflowing is
not a defect — that number really is out of range, and it is printed above so the contrast is on the
page.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Division uses Smith’s algorithm&lt;/strong&gt;, not &lt;code&gt;(ac + bd) / (c² + d²)&lt;/code&gt;. The textbook quotient forms the
divisor’s squared magnitude, so both divisions above would be a NaN: an infinity over an infinity at
the top of the range and a zero over a zero at the bottom. Dividing the smaller part of the divisor by
the larger first keeps every intermediate within a factor of two of the answer’s own scale, which is
the whole of the trick and costs one comparison.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A zero divisor is a NaN and not an infinity.&lt;/strong&gt; It is the one place the complex quotient does not
follow the real one: among the reals &lt;code&gt;1/0&lt;/code&gt; runs off in the only direction there is, while a complex
quotient has an argument as well as a magnitude and a zero divisor fixes neither. &lt;code&gt;is_zero&lt;/code&gt; is the
test a caller with a direction in mind writes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;norm_sqr&lt;/code&gt; is never spelled &lt;code&gt;norm&lt;/code&gt;.&lt;/strong&gt; C++’s &lt;code&gt;std::norm(z)&lt;/code&gt; is the squared magnitude and Rust’s
&lt;code&gt;num-complex&lt;/code&gt; &lt;code&gt;.norm()&lt;/code&gt; is the magnitude — the two precedents disagree, so the bare word would read as
the wrong one to half of its readers and neither meaning is given it.&lt;/p&gt;
&lt;h2 id=&quot;the-branch-cuts&quot;&gt;The branch cuts&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.complex.&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.math.&lt;span class=&quot;hl-type&quot;&gt;Float&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; above = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; below = &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(above.&lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;(), below.&lt;span class=&quot;hl-function&quot;&gt;ln&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;4.0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;sqrt&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;asin&lt;/span&gt;(), &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0.5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;asin&lt;/span&gt;().re)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;().re, &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(-&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;).&lt;span class=&quot;hl-function&quot;&gt;atanh&lt;/span&gt;().re)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0+3.14159i 0-3.14159i
0+2i 0-2i
1.5708-1.31696i 0.523599
inf -inf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The third line’s second value is printed as its real part alone, and deliberately. &lt;code&gt;asin&lt;/code&gt; of a point
&lt;em&gt;inside&lt;/em&gt; &lt;code&gt;[-1, 1]&lt;/code&gt; is real, so the imaginary part is zero — but it is zero by cancellation, and which
zero a platform’s libm lands on is its own business: this machine answers &lt;code&gt;1.11022e-16&lt;/code&gt; and glibc
answers &lt;code&gt;-0&lt;/code&gt;. Both are zero to within an ulp and neither is wrong. Pinning the digits would make the
page a record of one C library rather than of sysl.&lt;/p&gt;
&lt;p&gt;A function that is many-valued over the complex numbers is made single-valued by choosing where to
cut, and &lt;strong&gt;which cut a library chose is the one thing a caller cannot work out from a signature&lt;/strong&gt;. So
they are written down here, and each is pinned by a test at the boundary itself rather than near it.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;function&lt;/th&gt;&lt;th&gt;cut&lt;/th&gt;&lt;th&gt;principal value&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ln&lt;/code&gt;, &lt;code&gt;log&lt;/code&gt;, &lt;code&gt;log2&lt;/code&gt;, &lt;code&gt;log10&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the negative real axis&lt;/td&gt;&lt;td&gt;&lt;code&gt;arg&lt;/code&gt; in &lt;code&gt;(-pi, pi]&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sqrt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the negative real axis&lt;/td&gt;&lt;td&gt;non-negative real part&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;powc&lt;/code&gt;&lt;/td&gt;&lt;td&gt;inherits &lt;code&gt;ln&lt;/code&gt;‘s&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;asin&lt;/code&gt;, &lt;code&gt;acos&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the real axis outside &lt;code&gt;[-1, 1]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;atan&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the imaginary axis outside &lt;code&gt;[-i, i]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;asinh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the imaginary axis outside &lt;code&gt;[-i, i]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;acosh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the real axis to the left of &lt;code&gt;1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;non-negative real part&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;atanh&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the real axis outside &lt;code&gt;[-1, 1]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;—&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A negative zero says which side of a cut a value is on.&lt;/strong&gt; &lt;code&gt;arg&lt;/code&gt; puts &lt;code&gt;pi&lt;/code&gt; itself on the cut, so
&lt;code&gt;-1 + 0i&lt;/code&gt; reads &lt;code&gt;pi&lt;/code&gt; and &lt;code&gt;-1 - 0i&lt;/code&gt; reads &lt;code&gt;-pi&lt;/code&gt; — which is how a value that arrived at the axis from
below keeps its side of it. The first two lines above are that, twice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;atanh&lt;/code&gt; has a pole at each end of its cut and runs off to an infinity of the right sign at both. It is
written as a difference of two logarithms rather than one logarithm of a quotient for exactly that
reason: the quotient form divides by zero at one pole and reaches &lt;code&gt;ln(0)&lt;/code&gt; at the other, and would
report the same singularity two different ways.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The command line</title>
    <link href="https://sysl.sh/getting-started/cli/"/>
    <id>https://sysl.sh/getting-started/cli/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The subcommands, the flags they share, and what each one leaves as an exit status.</summary>
    <content type="html">&lt;p&gt;Every subcommand takes a &lt;strong&gt;path&lt;/strong&gt;, and a path is either a project root or a single file. That is not
two modes bolted together — a module is a directory and its name is that directory’s path relative
to the root, so naming a directory compiles the whole tree under it, one module per directory, and
naming a file compiles that file alone. The &lt;a href=&quot;/reference/modules/&quot;&gt;modules reference&lt;/a&gt; has the rule
the path is standing on.&lt;/p&gt;
&lt;h2 id=&quot;the-subcommands&quot;&gt;The subcommands&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;what it does&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl run &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;compile and execute&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl build &amp;lt;path&amp;gt; -o &amp;lt;exe&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;compile to a native executable&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl build-lib &amp;lt;path&amp;gt; -o &amp;lt;artifact&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;compile a library to a linkable artifact&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl build-c &amp;lt;path&amp;gt; -o &amp;lt;archive&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;compile to a static archive and a C header, for a C project&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl test &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;run the &lt;code&gt;@test&lt;/code&gt; functions&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl emit-llvm &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;print the generated LLVM IR&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl emit-header &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;print the C header for what a module exports&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl weave &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;render a literate source as an HTML document&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl tangle &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;print the program a literate source holds&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;sysl targets&lt;/code&gt;&lt;/td&gt;&lt;td&gt;list the machines sysl can build for&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;sysl prove&lt;/code&gt; is an eleventh, and it has a page of its own — see
&lt;a href=&quot;/reference/verification/#sysl-prove&quot;&gt;verification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A subcommand is required; sysl with none exits 2 and prints its usage.&lt;/p&gt;
&lt;h3 id=&quot;run&quot;&gt;&lt;code&gt;run&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl run hello.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Four things in a row: the source is parsed and checked, textual LLVM IR is emitted, &lt;code&gt;clang&lt;/code&gt;
assembles and links it, and the binary runs. The executable goes to a temporary file and is removed
afterwards — &lt;code&gt;run&lt;/code&gt; leaves nothing behind.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everything after a bare &lt;code&gt;--&lt;/code&gt; belongs to the program&lt;/strong&gt;, not to sysl:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl run report.sysl -- --verbose report.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The split is made &lt;em&gt;before&lt;/em&gt; sysl’s own options are parsed, which is the point: &lt;code&gt;--verbose&lt;/code&gt; really is
one of sysl’s own options, so without the &lt;code&gt;--&lt;/code&gt; sysl would have taken it — after it, it belongs to the
program, and neither side has to know what the other’s flags are called. What arrives at
&lt;a href=&quot;/library/args/&quot;&gt;&lt;code&gt;main(args: []string)&lt;/code&gt;&lt;/a&gt; is the executable’s own path followed by those two words,
so &lt;code&gt;args.len&lt;/code&gt; is 3 — &lt;code&gt;args[0]&lt;/code&gt; is the program, exactly as C’s &lt;code&gt;argv[0]&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;run&lt;/code&gt; exits with the status the program exited with.&lt;/strong&gt; It is running your program, so its status
is your program’s — a compilation that failed is what exits 1 on sysl’s own behalf.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The program’s input is sysl’s input&lt;/strong&gt;, so a program that reads works under &lt;code&gt;run&lt;/code&gt; exactly as the
built binary does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;printf &apos;one\ntwo\n&apos; | sysl run count.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the program writes comes out as it writes it rather than all at once when it finishes, which is
what makes a program that prompts usable here at all.&lt;/p&gt;
&lt;h3 id=&quot;build&quot;&gt;&lt;code&gt;build&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build hello.sysl -o hello
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same compilation, stopping at the executable instead of running it. &lt;code&gt;wrote hello&lt;/code&gt; goes to
stderr so that stdout stays whatever the build was for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;-o&lt;/code&gt; is optional, and where it writes depends on what you named.&lt;/strong&gt; Given a &lt;strong&gt;file&lt;/strong&gt;, the name is
that file’s, with its extension dropped, in the current directory: &lt;code&gt;src/tools/fmt.sysl&lt;/code&gt; becomes
&lt;code&gt;fmt&lt;/code&gt; beside you.&lt;/p&gt;
&lt;p&gt;Given a &lt;strong&gt;directory&lt;/strong&gt;, the executable goes &lt;em&gt;inside&lt;/em&gt; it, named after it. &lt;code&gt;sysl build .&lt;/code&gt;,
&lt;code&gt;sysl build fmt&lt;/code&gt; and &lt;code&gt;sysl build ../fmt&lt;/code&gt; are three ways of naming one project, and all three write
&lt;code&gt;fmt/fmt&lt;/code&gt; — so the answer does not depend on where you were standing when you asked. &lt;code&gt;build-lib&lt;/code&gt;
follows the same rule, writing &lt;code&gt;fmt/fmt.syslib&lt;/code&gt; into the root it was built from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A project whose &lt;code&gt;package.hocon&lt;/code&gt; names dependencies gets them fetched here&lt;/strong&gt;, if this machine has
not got them already — see &lt;a href=&quot;/reference/packages/&quot;&gt;packages&lt;/a&gt;. &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; do the same; there is
no separate step to remember, and a project with no dependencies does none of it.&lt;/p&gt;
&lt;h3 id=&quot;build-lib&quot;&gt;&lt;code&gt;build-lib&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build-lib mylib -o mylib.syslib
sysl run prog.sysl --lib mylib.syslib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A library compiled once into the two halves a program links against. See
&lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt; for what an artifact holds and why the generic half of it travels as
trees rather than as object code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A library may itself be built on another one&lt;/strong&gt;, and &lt;code&gt;--lib&lt;/code&gt; is what says so — it takes an artifact
or a source root here exactly as it does for a compilation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build-lib sdl3 -o sdl3.syslib
sysl build-lib sdl3-ttf --lib sdl3.syslib -o sdl3-ttf.syslib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Unlike &lt;code&gt;build&lt;/code&gt;, &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;, this does not fetch.&lt;/strong&gt; A package with a &lt;code&gt;dependencies&lt;/code&gt; block is
refused rather than resolved over the network, and the message names the dependency and points at
&lt;code&gt;--lib&lt;/code&gt;. A command whose whole job is to compile one tree into an artifact for one machine should not
be the thing that goes looking; the cost is that such a package writes its dependency down twice.&lt;/p&gt;
&lt;p&gt;Building one needs an &lt;code&gt;llvm-ar&lt;/code&gt; as well as a &lt;code&gt;clang&lt;/code&gt;, because a &lt;code&gt;.syslib&lt;/code&gt; &lt;strong&gt;is&lt;/strong&gt; an &lt;code&gt;ar&lt;/code&gt; archive —
&lt;a href=&quot;/getting-started/installation/&quot;&gt;installation&lt;/a&gt; has the note about which &lt;code&gt;ar&lt;/code&gt; and why the platform
one will not do.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It compiles the package’s C, so it asks what that C needs.&lt;/strong&gt; A package that declares its
&lt;a href=&quot;/reference/packages/#headers-a-package-needs-and-does-not-carry&quot;&gt;header requirements&lt;/a&gt;
is refused here without &lt;code&gt;--include-path &amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt;, exactly as it is for a &lt;code&gt;build&lt;/code&gt; — this being
the command a package is &lt;em&gt;published&lt;/em&gt; by rather than merely built by. It is asked for the package’s
own manifest and nothing else: the C of a &lt;code&gt;--lib&lt;/code&gt; source root is not compiled here, so that root’s
declaration is not charged to a library built against it.&lt;/p&gt;
&lt;h3 id=&quot;build-c&quot;&gt;&lt;code&gt;build-c&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl build-c mylib -o libmylib.a
sysl build-c mylib -o libmylib.a --header include/mylib.h
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;build-lib&lt;/code&gt;‘s shape with a different destination: a &lt;strong&gt;static archive&lt;/strong&gt; an existing C project links,
and a &lt;strong&gt;C header&lt;/strong&gt; declaring whatever the module marked &lt;code&gt;@export&lt;/code&gt;. The compilation is the ordinary
one rather than a library build — what is wanted is a module lowered for this target with its calls
resolved — and what differs from &lt;code&gt;build&lt;/code&gt; is that no entry point is emitted, since the C side supplies
its own &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The header goes beside the archive with &lt;code&gt;.h&lt;/code&gt; appended unless &lt;code&gt;--header&lt;/code&gt; names somewhere else. Both
paths are announced on stderr, along with the archives the C project’s own link line will still need
— an unresolved sysl symbol over there reads as a missing definition rather than as a missing
archive, so it is worth being told before you meet it. &lt;code&gt;--no-std-lib&lt;/code&gt; folds the standard library into
the object and the archive then stands alone.&lt;/p&gt;
&lt;p&gt;Like &lt;code&gt;build-lib&lt;/code&gt;, this needs an &lt;code&gt;llvm-ar&lt;/code&gt; as well as a &lt;code&gt;clang&lt;/code&gt;. &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI&lt;/a&gt; has &lt;code&gt;@export&lt;/code&gt;
itself — what may be exported, what a symbol is named, and why a computed module &lt;code&gt;val&lt;/code&gt; cannot be
reached from one.&lt;/p&gt;
&lt;h3 id=&quot;emit-header&quot;&gt;&lt;code&gt;emit-header&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl emit-header mylib
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same header &lt;code&gt;build-c&lt;/code&gt; writes, on stdout and with nothing built, for a project that generates its
headers as a build step.&lt;/p&gt;
&lt;h3 id=&quot;test&quot;&gt;&lt;code&gt;test&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl test &amp;lt;path&amp;gt;
sysl test &amp;lt;path&amp;gt; --filter &amp;lt;text&amp;gt;
sysl test &amp;lt;path&amp;gt; --fail-fast
sysl test &amp;lt;path&amp;gt; --std
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The tree is compiled once, into a binary that runs one named test per process, and the runner starts
it once per test. &lt;a href=&quot;/reference/attributes/&quot;&gt;Attributes&lt;/a&gt; has &lt;code&gt;@test&lt;/code&gt; itself — what a test may be, what
every other build does with one, and why the process per test is the mechanism rather than a cost.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It takes the search-path flags too&lt;/strong&gt; — &lt;code&gt;--link-path&lt;/code&gt;, &lt;code&gt;--include-path&lt;/code&gt; and &lt;code&gt;-D&lt;/code&gt;, exactly as &lt;code&gt;build&lt;/code&gt;
does, and it needs them for the same reasons. A tree whose C includes a header the toolchain does not
already know about, or whose constants come from a &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c const&lt;/code&gt;&lt;/a&gt; block over one, is a
tree whose &lt;em&gt;tests&lt;/em&gt; have to compile that C as much as its programs do. A package binding a system
library is the ordinary case rather than a corner of one, so a &lt;code&gt;test&lt;/code&gt; that could not be given those
directories would be a &lt;code&gt;test&lt;/code&gt; most packages could not run.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--std&lt;/code&gt; says the tree &lt;strong&gt;is&lt;/strong&gt; the standard module, which is how sysl’s own library is tested. The
compiler supplies &lt;code&gt;sysl&lt;/code&gt; to every compilation, so without it the library arrives twice — once as the
tree being compiled and once as the copy handed over — and every declaration is already declared.
Nothing infers it: a program with a &lt;code&gt;sysl&lt;/code&gt; directory of its own is nearly always a mistake, and a
build that guessed would turn that refusal into a collision at the link.&lt;/p&gt;
&lt;p&gt;The report groups by the file each test was written in, keeps source order inside a file, and shows
a test’s output &lt;strong&gt;only&lt;/strong&gt; where it failed:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;running 4 tests

clamp.sysl
  ok    clamps below the low bound   6ms
  ok    clamps above the high bound  5ms
  FAIL  leaves a value in range      5ms
        did not return — exit status 1
        at clamp.sysl:31
        &amp;gt; panic: clamp(4, 1, 3) should be 3
  ok    is idempotent                5ms

3 passed, 1 failed — 21ms
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A failure’s own line is one of three sentences and never more: &lt;strong&gt;&lt;code&gt;did not return — exit status n&lt;/code&gt;&lt;/strong&gt;,
which is what a failed &lt;code&gt;assert&lt;/code&gt; looks like since &lt;code&gt;assert&lt;/code&gt; prints and exits; &lt;strong&gt;&lt;code&gt;returned, and was expected to trap&lt;/code&gt;&lt;/strong&gt;; and &lt;strong&gt;&lt;code&gt;trapped, but printed nothing holding &amp;quot;…&amp;quot;&lt;/code&gt;&lt;/strong&gt;, for a
&lt;code&gt;@test(should_trap: &amp;quot;…&amp;quot;)&lt;/code&gt; whose run trapped without saying it. Everything the run printed follows
underneath, prefixed &lt;code&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;--filter&lt;/code&gt; keeps the tests whose name &lt;strong&gt;or module&lt;/strong&gt; holds the text, and the header says how many of
how many are running. &lt;code&gt;--fail-fast&lt;/code&gt; stops the loop rather than the report: what ran is still
reported and what never ran is simply absent, because “skipped” would be a third verdict for
something that is not a verdict.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exit status is 0 if and only if every test that ran passed.&lt;/strong&gt; A tree with no tests at all, and a
filter that matched none of the tests there are, both exit 0 — neither is a failure, and each says
which of the two happened rather than leaving one empty report to mean both.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;None of that mechanism exists on a microcontroller.&lt;/strong&gt; A process per test, a name in &lt;code&gt;argv&lt;/code&gt;, a
verdict in an exit status: a board has none of the three, so &lt;code&gt;sysl test&lt;/code&gt; cannot follow the code onto
one. &lt;a href=&quot;/library/harness/&quot;&gt;&lt;code&gt;sysl.harness&lt;/code&gt;&lt;/a&gt; is the other half — a framework linked &lt;em&gt;into&lt;/em&gt; the image,
which names its tests, locates a failure and prints a tally through a writer you hand it. Use this
command for everything that runs on the machine you are typing on, and that for the checks that only
exist on the target.&lt;/p&gt;
&lt;h3 id=&quot;emit-llvm&quot;&gt;&lt;code&gt;emit-llvm&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl emit-llvm hello.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The IR to stdout, the same text &lt;code&gt;run&lt;/code&gt; and &lt;code&gt;build&lt;/code&gt; hand to clang. Nothing is assembled and no
toolchain is needed for it.&lt;/p&gt;
&lt;h3 id=&quot;weave&quot;&gt;&lt;code&gt;weave&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl weave guide/lisp/lisp.lsysl -o lisp.html
sysl weave library/sysl/regex -o documents/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;literate&lt;/strong&gt; source rendered as an HTML document. A &lt;code&gt;.lsysl&lt;/code&gt; file is a Markdown document whose
four-column-indented part is the program, which is what makes one readable with nothing rendering it
— and an indented code block carries no &lt;em&gt;language&lt;/em&gt;, so nothing can highlight it. &lt;code&gt;weave&lt;/code&gt; tells the
renderer that an indented block is sysl, which is the whole of the transformation: the source reaches
the renderer exactly as written, and prose, tables, illustrations and heading levels are its own
business.&lt;/p&gt;
&lt;p&gt;What comes out is one file that opens by itself. It carries its own styling, in a light and a dark
palette; its code is coloured by the same grammar this site highlights with; and its mathematics is
set by KaTeX, which the page links. That last is the one thing a woven document needs the network
for — the prose and the code are markup in the file, so a document read offline loses its equations
to TeX source and nothing else.&lt;/p&gt;
&lt;p&gt;The output goes to standard output, or to what &lt;code&gt;-o&lt;/code&gt; names. &lt;strong&gt;A path holding several literate sources
writes one document each&lt;/strong&gt;, and &lt;code&gt;-o&lt;/code&gt; then names a directory: a woven document is something somebody
opens, so the unit is the file that was written rather than the tree. The ordinary &lt;code&gt;.sysl&lt;/code&gt; files
alongside are passed over, and a tree with no literate source at all is refused rather than producing
an empty page.&lt;/p&gt;
&lt;p&gt;It is a &lt;strong&gt;source-level&lt;/strong&gt; command: no target, no standard module, no libraries. A package’s prose is
worth reading on a machine that could not build it. What it does share with a compilation is the
reading, so a file the compiler would refuse — a tab in an indent, a fence that is never closed — is
refused here too, with the same message.&lt;/p&gt;
&lt;p&gt;This is not an API reference generated from declarations. sysl has no documentation comment yet, so
there is nothing for such a thing to read, and &lt;code&gt;doc&lt;/code&gt; is left unclaimed for the day there is.&lt;/p&gt;
&lt;h3 id=&quot;tangle&quot;&gt;&lt;code&gt;tangle&lt;/code&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl tangle guide/lisp/lisp.lsysl
sysl tangle guide/lisp/lisp.lsysl -o lisp.sysl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The other half of a literate system: the program, with the prose stripped. A build tangles anyway —
that is how a &lt;code&gt;.lsysl&lt;/code&gt; file compiles at all — so what this adds is a way to &lt;strong&gt;see&lt;/strong&gt; it.&lt;/p&gt;
&lt;p&gt;That is worth having when a literate file misbehaves. A block indented that should not have been, a
fence that swallowed a function: the question is always what the compiler actually read, and this is
how to ask. It also hands the program to anything that does not know the format — a tool, a paste, a
bug report.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The prose is replaced by blank lines rather than removed&lt;/strong&gt;, so line 100 of the output is line 100
of the source. That is what lets a diagnostic about the program point into the document it was
written in, and it is why the output is not as short as the program looks.&lt;/p&gt;
&lt;h3 id=&quot;targets&quot;&gt;&lt;code&gt;targets&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The registry, one line per machine — the name to write after &lt;code&gt;--target&lt;/code&gt;, the LLVM triple it stands
for, and, for a target sysl knows and cannot build for, why not:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;aarch64-macos                arm64-apple-macosx
x86_64-macos                 x86_64-apple-macosx
aarch64-linux                aarch64-unknown-linux-gnu
x86_64-linux                 x86_64-unknown-linux-gnu
riscv64-linux                riscv64-unknown-linux-gnu
x86_64-windows               x86_64-pc-windows-msvc
aarch64-freestanding         aarch64-none-elf
x86_64-freestanding          x86_64-unknown-none-elf
riscv64-freestanding         riscv64-unknown-elf
thumb-freestanding           thumbv8m.main-none-eabihf
thumb-freestanding-softfp    thumbv8m.main-none-eabi
thumb-freestanding-soft      thumbv8m.main-none-eabi
thumbv6m-freestanding        thumbv6m-none-eabi
thumbv7m-freestanding        thumbv7m-none-eabi
thumbv7em-freestanding       thumbv7em-none-eabihf
thumbv7em-freestanding-soft  thumbv7em-none-eabi
riscv32-freestanding         riscv32-unknown-elf
wasm32-freestanding          wasm32-unknown-unknown
craft-freestanding           craft
x86-linux                    i386-unknown-linux-gnu  (no C calling convention has been measured for x86)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The line for the machine you are on is marked &lt;code&gt;(this machine)&lt;/code&gt;, and a last line repeats what that
machine’s own runtime called itself. That last line is there for the case the rest of the list
cannot help with: on a machine sysl has no entry for, it is the only place to read what the machine
actually said.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Eight of the freestanding rows are 32-bit microcontrollers.&lt;/strong&gt; The RP2350 — the Pico
2 — boots either a pair of Cortex-M33s or a pair of RV32IMAC cores; the RP2040, the original Pico, has
a pair of Cortex-M0+; the Armv7E-M rows are ST’s parts; and Armv7-M is the Cortex-M3. All are here
because a microcontroller is what &lt;em&gt;freestanding&lt;/em&gt; is mostly for: the three 64-bit freestanding rows
reach kernels and hypervisors, which is a different audience. &lt;code&gt;thumb&lt;/code&gt; rather than &lt;code&gt;arm&lt;/code&gt; names the Arm
ones because a Cortex-M executes Thumb only, so an arm written for A32 would assemble for a machine
that cannot run it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Cortex-M33 has three rows, because neither the float ABI nor the FPU’s presence is sysl’s to
pick.&lt;/strong&gt; &lt;code&gt;thumb-freestanding&lt;/code&gt; passes floating-point arguments in VFP registers, which is what &lt;code&gt;eabihf&lt;/code&gt;
selects; &lt;code&gt;thumb-freestanding-softfp&lt;/code&gt; passes them in core registers, which is what
&lt;code&gt;-mfloat-abi=softfp&lt;/code&gt; means and what pico-sdk builds by default. The two
cannot be mixed — GNU ld refuses the link outright, saying one object &lt;em&gt;“uses VFP register arguments”&lt;/em&gt;
and the other &lt;em&gt;“does not”&lt;/em&gt; — so a sysl archive joining a C build has to agree with that build, and
offering only the first row meant the C had to be rebuilt to follow sysl. Pick the one your project
already uses; if you do not know, &lt;code&gt;softfp&lt;/code&gt; is the pico-sdk default.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Both of those rows use the M33’s own unit, which is single precision.&lt;/strong&gt; &lt;code&gt;f32&lt;/code&gt; arithmetic is
instructions and &lt;code&gt;f64&lt;/code&gt; arithmetic is a call into the board’s runtime — &lt;code&gt;__aeabi_dmul&lt;/code&gt; and its family
— because an &lt;code&gt;fpv5-sp-d16&lt;/code&gt; has no double-precision instructions to select. That is the part rather
than a setting, and it is worth knowing before a &lt;code&gt;f64&lt;/code&gt; goes into an inner loop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;thumb-freestanding-soft&lt;/code&gt; is the third, and it is for a board with no unit at all.&lt;/strong&gt; &lt;code&gt;softfp&lt;/code&gt; is not
&lt;code&gt;soft&lt;/code&gt;: &lt;code&gt;-mfloat-abi=soft&lt;/code&gt; means no FPU instructions whatever, while &lt;code&gt;softfp&lt;/code&gt; uses the &lt;code&gt;fpv5-sp-d16&lt;/code&gt;
this core has and changes only the calling convention. That distinction is not something a triple can
carry — both rows are &lt;code&gt;thumbv8m.main-none-eabi&lt;/code&gt; — so sysl says which it is on every clang command
line, with the convention beside it: &lt;code&gt;-mfloat-abi=soft -mfpu=none&lt;/code&gt; for the &lt;code&gt;soft&lt;/code&gt; row,
&lt;code&gt;-mfloat-abi=softfp -mfpu=fpv5-sp-d16&lt;/code&gt; for &lt;code&gt;softfp&lt;/code&gt;, and &lt;code&gt;-mfloat-abi=hard -mfpu=fpv5-sp-d16&lt;/code&gt; for the
first. None of that is left to the compiler’s default, because the default is not the same one twice:
the same triple reports a floating-point unit under some clangs and none under others, so a row that
said nothing would mean a different machine depending on which was installed. &lt;strong&gt;Reach for it when your board’s headers say the FPU is off&lt;/strong&gt;, which is
where the difference announces itself: CMSIS refuses the build with &lt;em&gt;“Compiler generates FPU
instructions for a device without an FPU (check &lt;code&gt;__FPU_PRESENT&lt;/code&gt;)”&lt;/em&gt;, and every Zephyr MPS2 board is
configured that way. Getting it wrong the other way is worse than a refusal — the image links, boots,
and takes a fault at whatever arithmetic reached a VFP instruction first.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;thumbv7em-freestanding&lt;/code&gt; and &lt;code&gt;thumbv7em-freestanding-soft&lt;/code&gt; are that same pair for Armv7E-M — an
STM32 F4 or H7 with the FPU on, and one with it off.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;thumbv6m-freestanding&lt;/code&gt; and &lt;code&gt;thumbv7m-freestanding&lt;/code&gt; are different architectures, not further
conventions.&lt;/strong&gt; The first is the RP2040’s Cortex-M0+ — Armv6-M, which came before Armv8-M rather than
being a subset of its options — and the second is the Cortex-M3. Build an original Pico’s program for
&lt;code&gt;thumbv6m&lt;/code&gt;; building it for a &lt;code&gt;thumb-&lt;/code&gt; row produces instructions the core cannot execute, and the
failure is a fault at whatever ran first rather than a refusal at the link. Neither core has a
floating-point unit in the architecture, so neither needs a &lt;code&gt;-soft&lt;/code&gt; sibling: there was never a second
answer to give.&lt;/p&gt;
&lt;p&gt;Build a Cortex-M3’s program for &lt;code&gt;thumbv7m&lt;/code&gt; rather than for &lt;code&gt;thumbv6m&lt;/code&gt;, even though Armv6-M code runs
on an M3. What does not survive the substitution is the &lt;em&gt;headers&lt;/em&gt;: a real project reads its own
configuration, so it takes &lt;code&gt;CONFIG_CPU_CORTEX_M3&lt;/code&gt; to mean Armv7-M and reaches for &lt;code&gt;BASEPRI&lt;/code&gt;, while
CMSIS reading an Armv6-M triple hands it an intrinsic set that has none.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One thing needs the board’s help on that target, and only one.&lt;/strong&gt; Armv6-M has no atomic
instructions, so a program using &lt;code&gt;&amp;amp;sync&lt;/code&gt; — the shared counted reference — compiles to calls the
toolchain does not supply, and the link fails naming &lt;code&gt;__atomic_fetch_add_4&lt;/code&gt;. Every other program is
unaffected, because those calls are emitted only for a program that holds a &lt;code&gt;&amp;amp;sync&lt;/code&gt;. The
&lt;a href=&quot;https://github.com/sysl-lang/pico&quot;&gt;&lt;code&gt;pico&lt;/code&gt;&lt;/a&gt; package supplies them over one of the chip’s hardware
spinlocks, which is what a dual-core part needs — masking interrupts is per-core and would leave the
other core free to lose the update.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;wasm32-freestanding&lt;/code&gt; is the odd row: 32-bit, freestanding, and not a board at all.&lt;/strong&gt; It is
WebAssembly — a browser, &lt;code&gt;wasmtime&lt;/code&gt;, or whatever else embeds a module — and &lt;code&gt;unknown-unknown&lt;/code&gt; in the
triple is the literal truth, so it comes with no libc, no loader and nothing that runs before an
exported function is called. Sysl links it with &lt;code&gt;-nostdlib&lt;/code&gt; and names &lt;code&gt;main&lt;/code&gt; as the module’s entry,
which is what makes &lt;code&gt;main&lt;/code&gt; reachable and exports it under that name; a program that does not print
comes out as a couple of hundred bytes of &lt;code&gt;.wasm&lt;/code&gt; that &lt;code&gt;wasmtime&lt;/code&gt; will run, and a program that does
print fails at the link naming &lt;code&gt;putchar&lt;/code&gt;, exactly as on any other bare target.&lt;/p&gt;
&lt;p&gt;It needs a clang with the WebAssembly back end. Apple’s has eleven back ends and this is not among
them, so on a Mac sysl reaches for Homebrew’s LLVM by itself — the same fallback it already makes for
the RISC-V rows — and says so if it cannot find one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;craft-freestanding&lt;/code&gt; is 16-bit, and it is the one row sysl will not drive a build for.&lt;/strong&gt; It is
CRAFT — a teaching ISA with eight registers, a 64 KiB virtual address space and a
software-managed TLB — whose LLVM back end lives out of tree, so what exists is an &lt;code&gt;llc&lt;/code&gt; rather than
a compiler driver. The machine has no libc, no object format and &lt;strong&gt;no linker&lt;/strong&gt;: its assembler reads
one file and resolves every label inside it. So sysl writes the LLVM and stops, and the rest is two
commands of your own:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl emit-llvm hello.sysl --target craft-freestanding &amp;gt; hello.ll
llc -march=craft hello.ll -o hello.s
craft as hello.s
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every other subcommand refuses this target and says that. It is not a target sysl cannot &lt;em&gt;lower&lt;/em&gt;
for — &lt;code&gt;emit-llvm&lt;/code&gt; produces an ordinary module — it is one with nothing for a driver to call.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sixteen bits is the part that shows up in your code.&lt;/strong&gt; &lt;code&gt;usize&lt;/code&gt; is pointer-width by definition, so
a slice’s length is a &lt;code&gt;u16&lt;/code&gt; and the address space is the bound on everything. An &lt;code&gt;int&lt;/code&gt; is still 32
bits and a &lt;code&gt;long&lt;/code&gt; still 64, because a width is the language’s answer rather than the machine’s — so
ordinary arithmetic here is multi-word, and the back end expands it, exactly as every 32-bit target
already expands a &lt;code&gt;long&lt;/code&gt;. Indexing with an &lt;code&gt;int&lt;/code&gt; needs no conversion for it: an index wider than an
address is checked against what an address can name and then narrowed, so &lt;code&gt;for i in 0..&amp;lt;4 do b[i] …&lt;/code&gt;
means what it means everywhere else.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;x86-linux&lt;/code&gt; is listed &lt;em&gt;because&lt;/em&gt; it cannot be built for. The limit is the compiler’s rather than the
machine’s, and &lt;strong&gt;it is no longer the width&lt;/strong&gt; — this page said so until the 32-bit rows above arrived.
What is missing is a C calling convention measured against clang, which is the only way a target’s
answers are allowed to be arrived at. A reader who names it is better told that than told the name is
unknown.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Freestanding does not mean self-contained.&lt;/strong&gt; A program built for a bare board still names C symbols
its runtime has to define — &lt;code&gt;putchar&lt;/code&gt; wherever anything prints, &lt;code&gt;free&lt;/code&gt; wherever a reference count can
reach zero, &lt;code&gt;memcpy&lt;/code&gt; and &lt;code&gt;memset&lt;/code&gt; for a structure assignment you never wrote — and on a 32-bit
machine it names a 64-bit division helper as well, because a &lt;code&gt;long&lt;/code&gt; is sixty-four bits everywhere and
neither RP2350 core has the instruction. None of that is a sysl dependency the compiler could warn
about: it is what any C compiler emits for the same code, and a real project never meets it because
its SDK has linked &lt;code&gt;libgcc&lt;/code&gt; or compiler-rt already. Meeting it looks like &lt;code&gt;undefined symbol: __aeabi_ldivmod&lt;/code&gt; at the link, which is the one place anybody will come looking for this paragraph.&lt;/p&gt;
&lt;h2 id=&quot;flags-every-subcommand-takes&quot;&gt;Flags every subcommand takes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--target &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the machine to build for; defaults to this one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--lib &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a library to compile against; may be given more than once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--std-lib &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a prebuilt standard module&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--no-std-lib&lt;/code&gt;&lt;/td&gt;&lt;td&gt;compile the standard module from source rather than linking a prebuilt one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--ar &amp;lt;path&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the &lt;code&gt;llvm-ar&lt;/code&gt; to build a library with&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--link-path &amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;where to look for a library a &lt;code&gt;link&lt;/code&gt; directive named; may be given more than once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-path &amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;where to look for a header the C beside a module includes; may be given more than once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--include-path &amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same, and it answers the header requirement a package declared under that name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-D NAME&lt;/code&gt; or &lt;code&gt;-D NAME=value&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a macro the C beside a module is compiled with; may be given more than once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-O &amp;lt;level&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the optimization level handed to clang&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;-v&lt;/code&gt;, &lt;code&gt;--verbose&lt;/code&gt;&lt;/td&gt;&lt;td&gt;report what the build decided — the standard module, the files read, the command lines, and where &lt;code&gt;build-lib&lt;/code&gt; staged&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--explain-escapes&lt;/code&gt;&lt;/td&gt;&lt;td&gt;report every local array promoted to the heap&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The standard-module flags and &lt;code&gt;-O&lt;/code&gt; are covered in
&lt;a href=&quot;/getting-started/installation/&quot;&gt;installation&lt;/a&gt;, including why the default is &lt;code&gt;-O1&lt;/code&gt; and not off.&lt;/p&gt;
&lt;h3 id=&quot;link-path-include-path-and-d-are-three-steps-of-one-thing&quot;&gt;&lt;code&gt;--link-path&lt;/code&gt;, &lt;code&gt;--include-path&lt;/code&gt; and &lt;code&gt;-D&lt;/code&gt; are three steps of one thing&lt;/h3&gt;
&lt;p&gt;A module that binds a C library carries C of its own, and that C has to be found, compiled and
linked. The three flags answer the three ways it fails, in the order it fails them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--include-path&lt;/code&gt;&lt;/strong&gt; — the shim &lt;code&gt;#include&lt;/code&gt;s the library’s header and cannot find it. This is the
first failure and the one that surprises, because it happens before anything reaches a linker.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-D&lt;/code&gt;&lt;/strong&gt; — the header is found and refuses, because a C project of any size configures its own
headers with macros and has not been asked. pico-sdk’s &lt;code&gt;pico/cyw43_arch.h&lt;/code&gt; &lt;code&gt;#error&lt;/code&gt;s rather than
guessing which architecture variant is meant, which is the shape to expect.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--link-path&lt;/code&gt;&lt;/strong&gt; — everything compiled and the archive is not where the linker looks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nothing is guessed at and nothing is defaulted. sysl does not add &lt;code&gt;/opt/homebrew/lib&lt;/code&gt;, and it does
not invent a macro: a compiler that ruled on where a platform keeps its libraries, or on how a
project configures its headers, would be wrong on a machine nobody here has — and being wrong there
costs a build that fails somewhere its author cannot reach. What a project defines is the project’s.&lt;/p&gt;
&lt;p&gt;A build system that already knows these will have them: reading them out of CMake is a matter of
asking the target for its &lt;code&gt;INCLUDE_DIRECTORIES&lt;/code&gt; and &lt;code&gt;COMPILE_DEFINITIONS&lt;/code&gt; and handing each along.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;package&lt;/strong&gt; whose C includes headers it does not carry can say so, and then the first failure above
stops being a surprise: written &lt;code&gt;--include-path &amp;lt;name&amp;gt;=&amp;lt;dir&amp;gt;&lt;/code&gt;, the flag answers a requirement the
package declared, and a build that is missing one is refused by name before clang runs. See
&lt;a href=&quot;/reference/packages/#headers-a-package-needs-and-does-not-carry&quot;&gt;packages&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;lib-takes-either-a-source-tree-or-an-artifact&quot;&gt;&lt;code&gt;--lib&lt;/code&gt; takes either a source tree or an artifact&lt;/h3&gt;
&lt;p&gt;Which one a path names is read off the name: a &lt;code&gt;.syslib&lt;/code&gt; is decoded, anything else is walked as
source. That is deliberate — how a library was shipped is the shipper’s business, and a program
depending on one should not have to write down which it got. &lt;code&gt;build-lib&lt;/code&gt; is what turns the first
into the second, and the only difference downstream is what the compilation &lt;em&gt;cost&lt;/em&gt;: an artifact is a
linear decode where source is a parse.&lt;/p&gt;
&lt;h3 id=&quot;target-and-the-one-thing-run-will-not-do&quot;&gt;&lt;code&gt;--target&lt;/code&gt;, and the one thing &lt;code&gt;run&lt;/code&gt; will not do&lt;/h3&gt;
&lt;p&gt;Given no &lt;code&gt;--target&lt;/code&gt;, a build is for the machine it is running on. If that is a machine sysl has no
entry for, it says so and stops rather than guessing, because a wrong guess produces a module that
looks right and is not.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;run&lt;/code&gt; executes what it builds, and only this machine can do that, so a cross target is refused
before the build rather than after it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl: error: &apos;run&apos; executes what it builds, and &apos;x86_64-linux&apos; is not this machine — use &apos;sysl build --target x86_64-linux&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A name the registry does not have is answered with the names it does:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl: error: unknown target &apos;arm-linux&apos; — sysl knows aarch64-macos, x86_64-macos, aarch64-linux, x86_64-linux, riscv64-linux, x86_64-windows, aarch64-freestanding, x86_64-freestanding, riscv64-freestanding, thumb-freestanding, thumb-freestanding-softfp, thumb-freestanding-soft, thumbv6m-freestanding, thumbv7m-freestanding, thumbv7em-freestanding, thumbv7em-freestanding-soft, riscv32-freestanding, wasm32-freestanding, craft-freestanding, x86-linux
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;v-verbose&quot;&gt;&lt;code&gt;-v&lt;/code&gt;, &lt;code&gt;--verbose&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;What the build decided, on stderr — which is where &lt;code&gt;wrote &amp;lt;exe&amp;gt;&lt;/code&gt; goes, so stdout stays whatever the
build was for:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl: 1 source file(s) under hello
sysl:   read hello/hello.sysl
sysl: standard module linked from ~/Library/Caches/sysl/&amp;lt;version&amp;gt;-…/std.syslib
sysl: link: clang --target=arm64-apple-macosx -Wno-override-module -O1 …
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things, and they are the three that have actually been the answer to a question: &lt;strong&gt;which
standard module&lt;/strong&gt; the compilation got and whether it was linked or compiled from source, the &lt;strong&gt;files
it read&lt;/strong&gt;, and the &lt;strong&gt;command lines&lt;/strong&gt; handed to clang together with the &lt;code&gt;--lib&lt;/code&gt;, &lt;code&gt;--link-path&lt;/code&gt; and
&lt;code&gt;--include-path&lt;/code&gt; searches behind them. There are no phase timings: a build that is slow is diagnosed
by asking what it &lt;em&gt;did&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;build-lib&lt;/code&gt; adds a fourth, because it is the one command that writes anywhere but the artifact it
was asked for:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl: members staged in /var/folders/…/sysl-lib-1729384756
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The members are archived under names of their own rather than under whatever a temporary file was
called, which is what the directory is for, and it is removed whether the build succeeded or gave up
partway. The line is there for the run that is interrupted in between: what is left behind is a
directory nothing else would have named.&lt;/p&gt;
&lt;h3 id=&quot;explain-escapes&quot;&gt;&lt;code&gt;--explain-escapes&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;On stderr, one line per local array the compiler moved to the heap, and the view that forced the
move:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sysl build --explain-escapes tty.sysl
tty.sysl:31:12: &apos;buf&apos; is promoted to the heap, because this view of it is returned
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The position is the &lt;strong&gt;view&lt;/strong&gt;, not the declaration, because that is the half a reader cannot work out
for themselves. Where nothing was promoted it says so, in as many words, rather than printing
nothing and leaving you to wonder whether the flag took. &lt;a href=&quot;/reference/memory/&quot;&gt;Memory&lt;/a&gt; has what
promotion is and when it happens instead.&lt;/p&gt;
&lt;h3 id=&quot;o2-is-written-the-way-clang-writes-it&quot;&gt;&lt;code&gt;-O2&lt;/code&gt; is written the way clang writes it&lt;/h3&gt;
&lt;p&gt;A short option normally takes its value as the next argument, and clang’s optimization flag has been
written joined since cc. So &lt;code&gt;-O2&lt;/code&gt; is rewritten into &lt;code&gt;-O 2&lt;/code&gt; before the options are parsed — only that
letter, and only where something follows it, so a bare &lt;code&gt;-O&lt;/code&gt; still takes the next argument and
&lt;code&gt;--optimize&lt;/code&gt; is untouched. Nothing in that rewrite can reach the program’s own arguments, which were
already split off at the &lt;code&gt;--&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;two-combinations-that-are-refused&quot;&gt;Two combinations that are refused&lt;/h2&gt;
&lt;p&gt;Neither is resolved by precedence, because whichever precedence were chosen would silently discard
half of what was asked for:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sysl: error: --core-lib compiles against the standard module, and &apos;build-lib --core&apos; is what builds it
sysl: error: --no-core-lib and --core-lib ask for different standard modules
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first is &lt;code&gt;build-lib --core --core-lib x&lt;/code&gt;, which cannot mean anything: the declarations being
compiled are the ones the artifact holds. The second is the pair of near-identical spellings that a
typo produces.&lt;/p&gt;
&lt;h2 id=&quot;exit-statuses&quot;&gt;Exit statuses&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;it worked — and for &lt;code&gt;test&lt;/code&gt;, every test that ran passed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;a compiler diagnostic, a driver error, or a failing test&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;the command line did not parse&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;em&gt;the program’s&lt;/em&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;run&lt;/code&gt; only, once the program has started&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;A compiler diagnostic is printed exactly as the compiler wrote it, with its location and a caret
under the offending column. A driver error — something that went wrong &lt;em&gt;around&lt;/em&gt; the compilation
rather than inside it — is prefixed &lt;code&gt;sysl: error:&lt;/code&gt;, which is why every message quoted on this page
carries it and none of the ones on the language pages do.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: the &lt;a href=&quot;/tour/&quot;&gt;tour&lt;/a&gt;, which uses &lt;code&gt;run&lt;/code&gt; throughout.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>A program that reads its input</title>
    <link href="https://sysl.sh/tour/capstone/"/>
    <id>https://sysl.sh/tour/capstone/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The whole tour at once — a trait implemented, a cursor walked, and one line to swap the source.</summary>
    <content type="html">&lt;p&gt;Here is everything the tour has covered, doing one job: count the lines, words and bytes of some
text, and report the longest line.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;, lines}

&lt;span class=&quot;hl-comment&quot;&gt;// A source of bytes over storage the program already has.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;SliceReader&lt;/span&gt;
    src: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    at: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

&lt;span class=&quot;hl-comment&quot;&gt;// `Reader` requires `Fallible`, whose one member has a default — so this line&lt;/span&gt;
&lt;span class=&quot;hl-comment&quot;&gt;// is the whole of the implementation, and it says &amp;quot;reading this cannot fail&amp;quot;.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;SliceReader&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;SliceReader&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, into: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; left = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src.len - &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; left &amp;lt; into.len &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; left &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; into.len

        &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; into[i] = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.src[&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at + i]

        &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.at += n
        into[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n]

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Stats&lt;/span&gt;
    lines: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    words: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    bytes: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    longest: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;invariant&lt;/span&gt; lines &amp;gt;= &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;words_in&lt;/span&gt;(s: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; inside = &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; s.bytes
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; b == &lt;span class=&quot;hl-number&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; inside = &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;elif&lt;/span&gt; !inside
            n += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
            inside = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;

    n

&lt;span class=&quot;hl-function&quot;&gt;tally&lt;/span&gt;(src: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reader&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Stats&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; st = &lt;span class=&quot;hl-type&quot;&gt;Stats&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; line &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lines&lt;/span&gt;(src)
        st.lines += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        st.words += &lt;span class=&quot;hl-function&quot;&gt;words_in&lt;/span&gt;(line)
        st.bytes += &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(line.len) + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; line.len &amp;gt; st.longest.len &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; st.longest = line

    st
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; tally&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sample = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    the quick brown fox&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    jumps over&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    the lazy dog&lt;/span&gt;
&lt;span class=&quot;hl-string&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r = &lt;span class=&quot;hl-type&quot;&gt;SliceReader&lt;/span&gt;(sample.bytes, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; st = &lt;span class=&quot;hl-function&quot;&gt;tally&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;r)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;lines:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.lines, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;words:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.words, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bytes:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.bytes)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;longest:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.longest)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;lines: 3 words: 9 bytes: 44
longest: the quick brown fox
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sixty lines, and almost every chapter of the tour is in there. Worth walking through what each part is
leaning on.&lt;/p&gt;
&lt;h2 id=&quot;the-reader-is-a-trait-implementation&quot;&gt;The reader is a trait implementation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Reader&lt;/code&gt; asks for one method — hand me a buffer, tell me what you put in it — and &lt;code&gt;SliceReader&lt;/code&gt;
answers it over bytes the program already has. Nothing about the rest of the program knows which kind
of source it got.&lt;/p&gt;
&lt;p&gt;Notice the return type. &lt;code&gt;read&lt;/code&gt; hands back a &lt;strong&gt;view of the caller’s own buffer&lt;/strong&gt;, not a count, and
that is the shape rather than an accident: a &lt;code&gt;[]const u8&lt;/code&gt; already &lt;em&gt;is&lt;/em&gt; a count and a pointer, so there
is no way to be handed one and forget to apply it to the other. An empty result means the input
ended.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;into[0..&amp;lt;n]&lt;/code&gt; is a &lt;code&gt;[]u8&lt;/code&gt; flowing into a &lt;code&gt;[]const u8&lt;/code&gt; return type, which is the widening the arrays
chapter described — giving up the ability to write is a promise the callee can always make.&lt;/p&gt;
&lt;p&gt;The bare &lt;code&gt;impl Fallible for SliceReader&lt;/code&gt; line is a &lt;strong&gt;required trait&lt;/strong&gt; at work. &lt;code&gt;Reader&lt;/code&gt; requires
&lt;code&gt;Fallible&lt;/code&gt;, so implementing one obliges the other; and because &lt;code&gt;Fallible&lt;/code&gt;‘s single member has a
default, there is nothing left to write and the block is empty. Whether a stream &lt;em&gt;ended&lt;/em&gt; and whether
it ended &lt;em&gt;badly&lt;/em&gt; are separate questions — the first is answered by an empty result, the second by
&lt;code&gt;failed&lt;/code&gt;, and a source that cannot go wrong should not have to write down that it cannot.&lt;/p&gt;
&lt;h2 id=&quot;the-tally-takes-a-trait-object&quot;&gt;The tally takes a trait object&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;tally(src: *Reader)&lt;/code&gt; is the dynamic side of the trait: one copy of the code, dispatching through the
table, so it works over any source at all. &lt;code&gt;&amp;amp;r&lt;/code&gt; at the call site erases the &lt;code&gt;SliceReader&lt;/code&gt; into a
&lt;code&gt;*Reader&lt;/code&gt;, which is a two-word fat pointer and costs no allocation — which is why a kernel can use
this shape.&lt;/p&gt;
&lt;p&gt;A bound would have worked too. &lt;code&gt;tally[R: Reader](src: *R)&lt;/code&gt; would monomorphize, giving a direct call
per source type. The trait object is the right choice here because the point of the program is that
the source is interchangeable.&lt;/p&gt;
&lt;h2 id=&quot;the-loop-walks-a-cursor&quot;&gt;The loop walks a cursor&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;lines(src)&lt;/code&gt; hands back a cursor implementing &lt;code&gt;Iterate[string]&lt;/code&gt;, and &lt;code&gt;for&lt;/code&gt; walks anything that does.
That means the loop reads a line at a time out of a 4 KiB chunk, rather than pulling the whole input
into memory — and it looks exactly like the &lt;code&gt;for x in xs&lt;/code&gt; that walks an array.&lt;/p&gt;
&lt;p&gt;Each &lt;code&gt;line&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt;, so it is guaranteed well-formed UTF-8 and &lt;code&gt;line.len&lt;/code&gt; is its byte length.
&lt;code&gt;st.longest = line&lt;/code&gt; costs no copy: a string is three words sharing its bytes, so keeping the longest
line means retaining the chunk it came out of and nothing more.&lt;/p&gt;
&lt;h2 id=&quot;the-struct-keeps-a-rule&quot;&gt;The struct keeps a rule&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;invariant lines &amp;gt;= 0&lt;/code&gt; is checked at construction &lt;strong&gt;and at every field write&lt;/strong&gt; — including
&lt;code&gt;st.lines += 1&lt;/code&gt;, which is a compound assignment and owed the same re-check. If some later edit made
the count go backwards, the program would stop at the write that broke it rather than somewhere
downstream where a negative line count finally mattered.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;words_in&lt;/code&gt; is the only piece doing real byte work, and it does it over &lt;code&gt;s.bytes&lt;/code&gt; — the string’s
storage as a read-only view. No allocation, no decoding, no copy.&lt;/p&gt;
&lt;h2 id=&quot;swapping-the-source&quot;&gt;Swapping the source&lt;/h2&gt;
&lt;p&gt;The point of writing it against a trait is this diff, which is the entire change needed to read the
program’s actual input:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.io.{stdin, lines}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; src = &lt;span class=&quot;hl-function&quot;&gt;stdin&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; st = &lt;span class=&quot;hl-function&quot;&gt;tally&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;src)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;lines:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.lines, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;words:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.words, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;bytes:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, st.bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;stdin()&lt;/code&gt; gives an &lt;code&gt;FdReader&lt;/code&gt;, which implements the same &lt;code&gt;Reader&lt;/code&gt; over a file descriptor. &lt;code&gt;tally&lt;/code&gt; is
untouched, and so is everything under it. A freestanding target that has no file descriptors
substitutes one body — a &lt;code&gt;read&lt;/code&gt; syscall — and the whole surface above it is unchanged.&lt;/p&gt;
&lt;p&gt;That is the shape the standard library is built in, and it is worth taking away from the tour more
than any single feature: the seam is a trait with one method, the thing on either side of it is
ordinary sysl, and nothing in the middle had to be told which.&lt;/p&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to go from here&lt;/h2&gt;
&lt;p&gt;You have seen the whole language. What is left is depth:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The &lt;a href=&quot;/reference/&quot;&gt;reference&lt;/a&gt;&lt;/strong&gt; is this same material in the other shape: every construct written
down once, in its own place, with the rules complete rather than the beginner’s subset. The tour
teaches in the order things make sense to learn; the reference answers a lookup — what may follow
&lt;code&gt;for&lt;/code&gt;, what &lt;code&gt;?&lt;/code&gt; does to a &lt;code&gt;&amp;amp;T&lt;/code&gt; payload, which slice forms exist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;a href=&quot;/library/&quot;&gt;library&lt;/a&gt;&lt;/strong&gt; documents each module the table in
&lt;a href=&quot;/tour/modules/&quot;&gt;modules&lt;/a&gt; named, one page each, down to what a &lt;code&gt;no alloc&lt;/code&gt; program may reach.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The design chapters&lt;/strong&gt; in the compiler’s &lt;code&gt;design/&lt;/code&gt; are the specification — every rule in this tour is stated
there with the argument for it, including the alternatives that were rejected and why.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;a href=&quot;/guides/&quot;&gt;guide programs&lt;/a&gt;&lt;/strong&gt; are fourteen complete programs at the size where the choices
start to matter — a JSON parser, a scheduler, SHA-2, a slab allocator, a ring buffer, a datetime
library, a Lisp — each written to force a language decision rather than to demonstrate a finished
one. The
pages say what each found, which is most of the reason the language is shaped the way it is.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The standard library’s own source&lt;/strong&gt; is the best worked example there is. &lt;code&gt;Buf&lt;/code&gt;, &lt;code&gt;StrBuilder&lt;/code&gt; and
the &lt;code&gt;Reader&lt;/code&gt; above are ordinary sysl over the same features this tour covered — there is no
privileged layer underneath them.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>bytecode</title>
    <link href="https://sysl.sh/guides/bytecode/"/>
    <id>https://sysl.sh/guides/bytecode/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>The module system, and the set&apos;s one end-to-end assertion — source in, bytecode out, run it, compare what it printed.</summary>
    <content type="html">&lt;p&gt;A compiler for a small language and a machine that runs what it emits, over one shared instruction
set.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The axis: the module system&lt;/strong&gt;, and this is the only program in the set with an &lt;strong&gt;end-to-end
assertion&lt;/strong&gt;. Source text goes in, the compiler emits bytecode, the machine runs it, and what it
printed is compared against what the program should print. No golden file stands in the middle, and
the one place an intermediate form is inspected is the section that is &lt;em&gt;about&lt;/em&gt; the intermediate form.&lt;/p&gt;
&lt;p&gt;Three modules, and their shape is the point. &lt;code&gt;isa&lt;/code&gt; is what the other two agree on — the opcodes, the
buffer a program is emitted into, and how to read one back. &lt;code&gt;compiler&lt;/code&gt; and &lt;code&gt;vm&lt;/code&gt; each depend on it and
neither depends on the other, which is a DAG rather than a rule anybody had to remember. &lt;code&gt;compiler&lt;/code&gt;
is two files because it grew to two, and nothing about either says so: they name each other’s
declarations with no ordering and no forward declaration, which is what &lt;a href=&quot;/reference/modules/&quot;&gt;a module being a
directory&lt;/a&gt; buys.&lt;/p&gt;
&lt;p&gt;It is also the program that carries a &lt;a href=&quot;/reference/modules/&quot;&gt;capability clause&lt;/a&gt; — &lt;code&gt;no alloc&lt;/code&gt; on the VM
half — which is the declaration &lt;code&gt;guide/slab&lt;/code&gt; and &lt;code&gt;guide/kernel&lt;/code&gt; both wanted and neither could use,
because a capability is a property of the whole directory.&lt;/p&gt;
&lt;h2 id=&quot;what-it-found&quot;&gt;What it found&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A simple enum narrower than &lt;code&gt;int&lt;/code&gt; could not be matched at all.&lt;/strong&gt; &lt;code&gt;enum Op: u8&lt;/code&gt; is the natural way
to write an instruction set — the opcode &lt;em&gt;is&lt;/em&gt; a byte — and every &lt;code&gt;match&lt;/code&gt; on one emitted a comparison
at the wrong width, which the assembler refused. A &lt;strong&gt;compiler bug&lt;/strong&gt; rather than a language one, found
by the first program that wanted a narrow enum for the reason narrow enums exist, fixed at the source,
and now covered by tests at &lt;code&gt;i8&lt;/code&gt;, &lt;code&gt;u8&lt;/code&gt; and &lt;code&gt;u16&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Result[unit, E]&lt;/code&gt; could not be written&lt;/strong&gt;, and a compiler front end is &lt;em&gt;all&lt;/em&gt; valueless fallible
steps. Every parse step here emits code and yields nothing, so every one used to say
&lt;code&gt;Result[bool, Fault]&lt;/code&gt; with a &lt;code&gt;bool&lt;/code&gt; that meant nothing — a placeholder payload keeping &lt;code&gt;?&lt;/code&gt; working.&lt;/p&gt;
&lt;p&gt;Answered by making &lt;code&gt;unit&lt;/code&gt; a &lt;strong&gt;zero-sized type&lt;/strong&gt;: it has a layout, the empty one, so a field or a
parameter of it is skipped rather than refused. Every one of those signatures now says what it means,
and &lt;code&gt;Ok(())&lt;/code&gt; costs a &lt;code&gt;getelementptr&lt;/code&gt; fewer than &lt;code&gt;Ok(true)&lt;/code&gt; did. The finding earned its own entry
because two unrelated programs paid for it — see &lt;a href=&quot;/guides/png/&quot;&gt;png&lt;/a&gt;, which has nothing in common
with a parser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An assignment is an expression, so a two-branch &lt;code&gt;if&lt;/code&gt; whose branches each end in one was checked as
though those were its result.&lt;/strong&gt; The &lt;code&gt;unit&lt;/code&gt;-branch rule saved the case where one side was a statement
and saved nothing where both sides assigned: &lt;code&gt;full = true&lt;/code&gt; against &lt;code&gt;len += 1&lt;/code&gt; is a &lt;code&gt;bool&lt;/code&gt; against a
&lt;code&gt;usize&lt;/code&gt;. That sharpened what &lt;a href=&quot;/guides/hashmap/&quot;&gt;hashmap&lt;/a&gt; had found about &lt;code&gt;match&lt;/code&gt; — the trouble was
never that &lt;code&gt;match&lt;/code&gt; lacked a rule &lt;code&gt;if&lt;/code&gt; had, it was that assignment is an expression and &lt;em&gt;any&lt;/em&gt;
two-armed form inherited it. Answered by taking the &lt;strong&gt;position&lt;/strong&gt; instead: a block whose own value is
unused has none.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A line could not be continued.&lt;/strong&gt; There was no trailing-operator continuation, so a condition that
outgrew its line had to become a sequence of early returns. Answered — and the rule that landed
carries &lt;a href=&quot;/reference/lexical/&quot;&gt;four exclusions&lt;/a&gt;, because an operator at the end of a line is not
always a promise that the expression goes on.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/sysl-lang/sysl/tree/dev/guide/bytecode&quot;&gt;Source&lt;/a&gt; ·
Next: &lt;a href=&quot;/guides/png/&quot;&gt;png&lt;/a&gt; — somebody else’s format, byte by byte.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>The buf module</title>
    <link href="https://sysl.sh/library/buf/"/>
    <id>https://sysl.sh/library/buf/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`sysl.buf` — `Buf[T]`, the growable sequence written in ordinary sysl, and `ByteSink`, the one `Writer` the library supplies.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.buf&lt;/code&gt; holds two types and three functions, and the interesting thing about the larger of them is
what it is &lt;em&gt;not&lt;/em&gt;: &lt;strong&gt;&lt;code&gt;Buf[T]&lt;/code&gt; is not a type the compiler knows.&lt;/strong&gt; It is a &lt;code&gt;[]T&lt;/code&gt; field for the storage,
a &lt;code&gt;usize&lt;/code&gt; for how much of it is live, and a dozen members — ordinary sysl, in a file a program could
have written.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), b.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;(), b.&lt;span class=&quot;hl-function&quot;&gt;is_empty&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))

b[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;().len, b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 8 false
1 3
3 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in the language reaches it. An array literal makes a &lt;code&gt;[]T&lt;/code&gt;, a &lt;code&gt;for&lt;/code&gt; walks whatever implements
&lt;code&gt;Iterate&lt;/code&gt;, and neither of those is a growable sequence — so a program that wants one asks, and the
&lt;code&gt;import&lt;/code&gt; is where it asked. That is the &lt;a href=&quot;/library/core/&quot;&gt;core module’s&lt;/a&gt; rule applied from the other
side: what a program cannot avoid needing arrives free, and what it has to ask for it asks for.&lt;/p&gt;
&lt;h2 id=&quot;why-it-can-be-written-at-all&quot;&gt;Why it can be written at all&lt;/h2&gt;
&lt;p&gt;A container that sizes its own storage needs three things, and sysl’s design notes once recorded all
three as reasons this could not be a library type: &lt;code&gt;sizeof&lt;/code&gt; over a type parameter, a cast to reach
the elements through it, and above all a &lt;strong&gt;destructor&lt;/strong&gt;, since the language had exactly one and no
way to write another.&lt;/p&gt;
&lt;p&gt;All three were the wrong answer, and none of the three is an absence now — a
&lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; is writable. &lt;strong&gt;A container does not need one if its storage is a
value that already has one&lt;/strong&gt; — the &lt;code&gt;[]T&lt;/code&gt; field is an ARC-owned buffer, so when a &lt;code&gt;Buf&lt;/code&gt; goes, its storage
goes with it, and nothing in the container has to say so. The one thing genuinely missing was the
ability to ask for storage at a length worked out while running, and once a &lt;code&gt;[]T&lt;/code&gt; could be sized that
way, &lt;code&gt;Buf[T]&lt;/code&gt; was a hundred lines with no unsafe primitive in them.&lt;/p&gt;
&lt;p&gt;A second apparent blocker dissolved the same way. A generic container cannot make its own storage,
because an array is built by &lt;em&gt;repeating a value&lt;/em&gt; and no bound promises that &lt;code&gt;T&lt;/code&gt; has one. But &lt;strong&gt;a
&lt;code&gt;push&lt;/code&gt; arrives holding one&lt;/strong&gt; — the value being pushed seeds the new storage, and the question never
comes up.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    elems: []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    count: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_empty&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;extend&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;pop&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;Option&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]

    &lt;span class=&quot;hl-function&quot;&gt;insert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;truncate&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;clear&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is generic over anything, including counted types — a &lt;code&gt;Buf[string]&lt;/code&gt; retains and releases its
elements like any other slice of them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; names: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

names.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
names.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;grace&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(names.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), names[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 grace
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;bounds-a-panic-here-an-option-there&quot;&gt;Bounds: a panic here, an &lt;code&gt;Option&lt;/code&gt; there&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;at&lt;/code&gt; and &lt;code&gt;set&lt;/code&gt; &lt;strong&gt;panic&lt;/strong&gt; on an index past the end. &lt;code&gt;pop&lt;/code&gt; returns an &lt;code&gt;Option&lt;/code&gt;. That looks like two
minds about the same question and is not:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An index past the end is a &lt;strong&gt;mistake in the program&lt;/strong&gt;, not a value it meant to handle. Taking from
an empty sequence is a question a caller asks &lt;strong&gt;on purpose&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It is the same bargain &lt;a href=&quot;/reference/errors/&quot;&gt;&lt;code&gt;unwrap&lt;/code&gt;&lt;/a&gt; makes. A &lt;code&gt;pop&lt;/code&gt; that returned &lt;code&gt;T&lt;/code&gt; and panicked
would make every drain loop write a length test it could have got from the answer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;pop&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;unwrap&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())

b.&lt;span class=&quot;hl-function&quot;&gt;truncate&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), b.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;(), b.&lt;span class=&quot;hl-function&quot;&gt;is_empty&lt;/span&gt;())

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; e: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e.&lt;span class=&quot;hl-function&quot;&gt;pop&lt;/span&gt;().&lt;span class=&quot;hl-function&quot;&gt;is_none&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
1
2 1
0 8 true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;truncate&lt;/code&gt;, &lt;code&gt;clear&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; are one operation seen three ways.&lt;/strong&gt; &lt;code&gt;truncate(n)&lt;/code&gt; lowers the
count, and does nothing where &lt;code&gt;n&lt;/code&gt; is a length the buffer does not have — a length past the end names
no element, so unlike an index there is nothing for it to read and nothing to stop the program about.
&lt;code&gt;clear()&lt;/code&gt; is &lt;code&gt;truncate(0)&lt;/code&gt;. &lt;code&gt;remove(i)&lt;/code&gt; shifts the survivors down over element &lt;code&gt;i&lt;/code&gt;, hands that element
back, and ends at &lt;code&gt;truncate&lt;/code&gt;; an &lt;code&gt;i&lt;/code&gt; that names no element is &lt;code&gt;at&lt;/code&gt;‘s panic, for &lt;code&gt;at&lt;/code&gt;‘s reason.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;insert(i, v)&lt;/code&gt; is &lt;code&gt;remove&lt;/code&gt;‘s other half&lt;/strong&gt;, putting an element at &lt;code&gt;i&lt;/code&gt; and moving everything from
there on up one. Inserting at &lt;code&gt;len&lt;/code&gt; is a &lt;code&gt;push&lt;/code&gt; and is allowed for that reason — a loop inserting at
a cursor reaches the end on its last step, and refusing there would make every caller write the case
this one already handles. Anything past &lt;code&gt;len&lt;/code&gt; is a gap, which a sequence cannot represent, and panics
the way any other index past the end does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;extend&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])
b.&lt;span class=&quot;hl-function&quot;&gt;insert&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;insert&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hand-rolling it is a shift written &lt;em&gt;backwards&lt;/em&gt; — a loop walking up overwrites the element it is about
to read — and that is where the off-by-one lives.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What none of &lt;code&gt;truncate&lt;/code&gt;, &lt;code&gt;clear&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; does is give storage back.&lt;/strong&gt; The &lt;code&gt;cap()&lt;/code&gt; of &lt;code&gt;8&lt;/code&gt;
survives the &lt;code&gt;truncate&lt;/code&gt;
above. The elements above the count are still values in a &lt;code&gt;[]T&lt;/code&gt; that ARC owns — which is also why a
&lt;strong&gt;copy&lt;/strong&gt; of a &lt;code&gt;Buf&lt;/code&gt; taken before a removal reads the shifted elements at the length it was copied at.&lt;/p&gt;
&lt;h2 id=&quot;subscripting-goes-through-the-checked-members&quot;&gt;Subscripting goes through the checked members&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;Index&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;index&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(i)

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-type&quot;&gt;IndexSet&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;index_set&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, i: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hl-function&quot;&gt;set&lt;/span&gt;(i, v)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;b[i]&lt;/code&gt; on a &lt;code&gt;Buf&lt;/code&gt; means &lt;code&gt;b.at(i)&lt;/code&gt;, and that is worth more than the syntax. The backing slice is
longer than the count — subscripting the &lt;em&gt;storage&lt;/em&gt; would happily read a slot the buffer does not
consider live, and every bounds check in the language would pass. Routing &lt;code&gt;[]&lt;/code&gt; through &lt;code&gt;at&lt;/code&gt; is what
makes &lt;code&gt;b[i]&lt;/code&gt; unable to see spare capacity.&lt;/p&gt;
&lt;p&gt;The cost is that reading through &lt;a href=&quot;/library/core/&quot;&gt;&lt;code&gt;Index&lt;/code&gt;&lt;/a&gt; is a &lt;strong&gt;call&lt;/strong&gt;, so it yields a value rather
than a place:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;+=&apos; on an element read through &apos;sysl.Index&apos; would evaluate the receiver and the index twice
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;b[0] = b[0] + 1&lt;/code&gt; is the spelling, and writing it out is the point: the expansion the compiler
declines to make would evaluate &lt;code&gt;b&lt;/code&gt; twice and the index twice, which for a receiver that is a call,
or an index that advances a cursor, is wrong rather than merely wasteful.&lt;/p&gt;
&lt;p&gt;Two other shapes a first program tries. &lt;code&gt;len&lt;/code&gt; is a &lt;strong&gt;method&lt;/strong&gt;, unlike &lt;code&gt;StrBuilder&lt;/code&gt;‘s property:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;len&apos; is a method of &apos;sysl.buf.Buf[int]&apos; — call it with &apos;len(…)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a &lt;code&gt;Buf&lt;/code&gt; is not itself iterable — it implements &lt;code&gt;Index&lt;/code&gt;, not &lt;code&gt;Iterate&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; b
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;for&apos; iterates an integer range, an array, a slice, or a type that implements &apos;sysl.Iterate&apos;, and sysl.buf.Buf[int] is none of those
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;for x in b.view()&lt;/code&gt; is how it is walked, and that is not a workaround — it names the thing being
iterated, which is &lt;em&gt;the live prefix at the moment the loop started&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;view-is-the-bulk-read-and-it-is-a-view&quot;&gt;&lt;code&gt;view&lt;/code&gt; is the bulk read, and it is a view&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.len, b.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;())

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.len, v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], v[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), b.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 8
2 1 2
9 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The seventh push overflowed a capacity of 8, so the elements moved to a new buffer of 16. &lt;strong&gt;&lt;code&gt;v&lt;/code&gt; is
unchanged and still valid&lt;/strong&gt; — that is the whole of what this shows.&lt;/p&gt;
&lt;p&gt;It does not dangle, because the storage it was made from is an ARC buffer like any other and the view
keeps it alive. Go’s version of this is the famous confusion: two slices that agree until one of them
grows, and afterwards agree about nothing. Here the guarantee is stronger and simpler — a program
with no &lt;code&gt;*T&lt;/code&gt; in it cannot fault, so the old storage stays until the last view of it goes.&lt;/p&gt;
&lt;p&gt;What &lt;code&gt;v&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; do is grow with the buffer. It is a view of some elements and it has the length it
was made with. Take it again to see more.&lt;/p&gt;
&lt;h2 id=&quot;how-a-push-is-seen-follows-from-how-the-buf-is-held&quot;&gt;How a push is seen follows from how the &lt;code&gt;Buf&lt;/code&gt; is held&lt;/h2&gt;
&lt;p&gt;sysl does not have to choose here, and that is the point:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q = p
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p

p.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(q.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), c.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;q&lt;/code&gt; is a second name for one buffer, so it sees the push. &lt;code&gt;c&lt;/code&gt; is a copy, because copying a struct is
what &lt;code&gt;*p&lt;/code&gt; means. Neither is a rule about growable sequences — both are the &lt;a href=&quot;/reference/memory/&quot;&gt;memory
modes&lt;/a&gt; doing exactly what they do for any struct, and the author wrote which one
they wanted.&lt;/p&gt;
&lt;h2 id=&quot;capacity-and-what-it-costs&quot;&gt;Capacity, and what it costs&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf_with_capacity}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf_with_capacity&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), w.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;())

w.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(w.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), w.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;(), w[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 100
1 100 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Growth is geometric — a full buffer doubles — and &lt;code&gt;buf_with_capacity&lt;/code&gt; skips the
reallocate-and-copy at each doubling on the way up to &lt;code&gt;n&lt;/code&gt;.&lt;/strong&gt; It is a guess and nothing depends on it:
too small and the buffer grows the way it always does, too large and the slack goes with the rest.
&lt;code&gt;extend&lt;/code&gt; sizes the same way rather than fitting exactly, so a loop of &lt;code&gt;extend&lt;/code&gt; calls stays amortized
constant per element instead of turning quadratic the way &lt;code&gt;+=&lt;/code&gt; on a string does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The fill is a parameter, and that is &lt;code&gt;T&lt;/code&gt; having no zero.&lt;/strong&gt; An array is made by repeating a value,
and nothing about a type parameter says what an unused slot should hold. Leaving it out is an
ordinary arity error:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf_with_capacity}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf_with_capacity&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;function &apos;sysl.buf.buf_with_capacity&apos; takes 2 arguments, but 1 argument was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;None of those slots is ever read — &lt;code&gt;count&lt;/code&gt; starts at zero, so every one of them is written before
anything can see it. But they are &lt;strong&gt;real values&lt;/strong&gt;, and that is the honest cost of a growable sequence
in this language: there is no way to have storage that is merely reserved. A &lt;code&gt;Buf[&amp;amp;T]&lt;/code&gt; grown to a
capacity of 1024 while holding one element is holding 1024 references to whatever seeded the growth,
and that object stays alive until the slots are overwritten. Capacity that is not yet values is a
known gap, not a solved problem.&lt;/p&gt;
&lt;h2 id=&quot;it-needs-an-allocator-and-says-so&quot;&gt;It needs an allocator, and says so&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;no_alloc&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this reaches &apos;sysl.buf.buf.int&apos;, which makes heap storage, and this module declared &apos;@no_alloc&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both &lt;code&gt;buf()&lt;/code&gt; and the &lt;code&gt;push&lt;/code&gt; are named, because &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;alloc&lt;/code&gt; is checked on what a module
&lt;em&gt;calls&lt;/em&gt;&lt;/a&gt;. There is no allocator-free &lt;code&gt;Buf&lt;/code&gt; and there cannot be one: growing is
the whole of what it does.&lt;/p&gt;
&lt;h2 id=&quot;bytesink&quot;&gt;&lt;code&gt;ByteSink&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;ByteSink&lt;/span&gt;
    bytes: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;]

    &lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Fallible&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;ByteSink&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;ByteSink&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, bytes: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.bytes.&lt;span class=&quot;hl-function&quot;&gt;extend&lt;/span&gt;(bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the entire type. It is &lt;strong&gt;one of the two &lt;code&gt;Writer&lt;/code&gt;s the library supplies&lt;/strong&gt; — the other is
&lt;a href=&quot;/reference/declarations/&quot;&gt;&lt;code&gt;Stdout&lt;/code&gt;&lt;/a&gt;, which stands for standard output, holds no state at all, and
is therefore a struct with no fields. The buffer &lt;code&gt;str&lt;/code&gt; and an &lt;code&gt;f&amp;quot;…&amp;quot;&lt;/code&gt; hole render into is still the
compiler’s, since a growable byte array is not something it can name at the layer it needs one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;impl Fallible for ByteSink&lt;/code&gt; has no block, and does not need one: every member of &lt;code&gt;Fallible&lt;/code&gt; has a
default, so implementing the latch on a buffer that has nothing to fail at is entirely a matter of
opting in.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.byte_sink

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sink = &lt;span class=&quot;hl-function&quot;&gt;byte_sink&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sink

&lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
out.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
&lt;span class=&quot;hl-function&quot;&gt;display_str&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, out, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;putbytes&lt;/span&gt;(sink.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(sink.&lt;span class=&quot;hl-function&quot;&gt;failed&lt;/span&gt;(), sink.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;().len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;    42|ok
false 9
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;why-it-is-in-the-library-rather-than-in-each-program&quot;&gt;Why it is in the library rather than in each program&lt;/h3&gt;
&lt;p&gt;Because &lt;strong&gt;an implementation that renders more than one part cannot honour its specifier without
one.&lt;/strong&gt; A format specifier describes the field the &lt;em&gt;whole value&lt;/em&gt; occupies, so a rendering of &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;+&lt;/code&gt;,
&lt;code&gt;2&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; has to pad what those four came to rather than each of them; padding needs the finished
bytes; and the finished bytes need somewhere to land.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.byte_sink

&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;
    re: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    im: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Display&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;display&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;, out: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt;, fmt: &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; sink = &lt;span class=&quot;hl-function&quot;&gt;byte_sink&lt;/span&gt;()
        &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; gather: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Writer&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sink

        &lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.re), gather, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
        gather.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)
        &lt;span class=&quot;hl-function&quot;&gt;display_int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;long&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.im), gather, &lt;span class=&quot;hl-type&quot;&gt;FormatSpec&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;))
        gather.&lt;span class=&quot;hl-function&quot;&gt;write&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;.bytes)

        &lt;span class=&quot;hl-function&quot;&gt;display_pad&lt;/span&gt;(sink.&lt;span class=&quot;hl-function&quot;&gt;text&lt;/span&gt;(), out, fmt)
    &lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; display&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%8s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Complex&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;%-8s&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1+2i
[    1+2i]
[1+2i    ]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Note the two specs.&lt;/strong&gt; The inner &lt;code&gt;FormatSpec(0, -1, false)&lt;/code&gt; is neutral — the parts are rendered
plainly — and only &lt;code&gt;display_pad&lt;/code&gt; at the end sees &lt;code&gt;fmt&lt;/code&gt;. An implementation that forwarded &lt;code&gt;fmt&lt;/code&gt; down
to each part would pad the &lt;code&gt;1&lt;/code&gt; to eight columns and then the &lt;code&gt;2&lt;/code&gt;, which is not what &lt;code&gt;%8s&lt;/code&gt; on a
complex number meant.&lt;/p&gt;
&lt;p&gt;Every such implementation would write the same dozen lines, which is the definition of something that
belongs in the library. What a program still writes for itself is an ordinary &lt;code&gt;impl Writer for MyThing&lt;/code&gt; — a counter, a device, a bounded buffer that latches — and that remains the case the trait
exists for.&lt;/p&gt;
&lt;h3 id=&quot;a-writer-may-not-keep-what-it-is-written&quot;&gt;A &lt;code&gt;Writer&lt;/code&gt; may not keep what it is written&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;write&lt;/code&gt; takes a &lt;code&gt;[]const u8&lt;/code&gt; that may be a view of the caller’s &lt;strong&gt;stack&lt;/strong&gt; — that is exactly what the
&lt;code&gt;display_*&lt;/code&gt; renderers hand it, and it is why they cost no allocation. Nothing in the type says the
bytes are borrowed, so it is &lt;em&gt;checked&lt;/em&gt;: escape analysis rejects an implementation whose &lt;code&gt;write&lt;/code&gt; lets
its parameter outlive the call. &lt;code&gt;ByteSink&lt;/code&gt; copies them into its &lt;code&gt;Buf&lt;/code&gt;, which is what &lt;code&gt;extend&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;That check is what licenses a renderer to pass a stack-backed slice through a trait object at all.&lt;/p&gt;
&lt;h2 id=&quot;type-errors-read-as-they-should&quot;&gt;Type errors read as they should&lt;/h2&gt;
&lt;p&gt;The generic is monomorphized, so a mismatch names the instantiation rather than the parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;v&apos; of &apos;sysl.buf$Buf.push.int&apos; is int, but string was given
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sysl.buf$Buf.push.int&lt;/code&gt; is the &lt;code&gt;push&lt;/code&gt; of a &lt;code&gt;Buf[int]&lt;/code&gt; — one function, emitted for that instantiation.
&lt;a href=&quot;/reference/generics/&quot;&gt;Generics&lt;/a&gt; has the rest of that story.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/io/&quot;&gt;&lt;code&gt;sysl.io&lt;/code&gt;&lt;/a&gt; — reading, and the &lt;code&gt;Lines&lt;/code&gt; cursor.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Attributes, annotations, and compile time</title>
    <link href="https://sysl.sh/reference/attributes/"/>
    <id>https://sysl.sh/reference/attributes/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>`::` attributes a type answers, the eight annotations a function takes, the three that lay out or place what they mark, the five a file&apos;s header takes, `@assert` which stands on its own, and the `#if` directive that gates lines before the lexer sees them.</summary>
    <content type="html">&lt;p&gt;Three kinds of form in sysl reach into the &lt;em&gt;compilation&lt;/em&gt; rather than into the running program. Each
has a name and a spelling of its own:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;th&gt;read by&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Attr&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;attribute&lt;/strong&gt; — a question a type’s own name answers&lt;/td&gt;&lt;td&gt;the analyzer, at the use&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@test&lt;/code&gt;, &lt;code&gt;@tailrec&lt;/code&gt;, &lt;code&gt;@pure&lt;/code&gt;, &lt;code&gt;@ghost&lt;/code&gt;, &lt;code&gt;@export&lt;/code&gt;, &lt;code&gt;@reads&lt;/code&gt;, &lt;code&gt;@writes&lt;/code&gt;, &lt;code&gt;@crossing&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;annotation&lt;/strong&gt; — a fact about the free function under it&lt;/td&gt;&lt;td&gt;the grammar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@packed&lt;/code&gt;, &lt;code&gt;@align(n)&lt;/code&gt;, &lt;code&gt;@section(&amp;quot;...&amp;quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;annotation&lt;/strong&gt; — where the declaration under it is laid out, or where it lands&lt;/td&gt;&lt;td&gt;the grammar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@export(&amp;quot;...&amp;quot;)&lt;/code&gt; on a &lt;code&gt;struct&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;annotation&lt;/strong&gt; — the name the type carries in a generated C header&lt;/td&gt;&lt;td&gt;the grammar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@no_alloc&lt;/code&gt;, &lt;code&gt;@requires&lt;/code&gt;, &lt;code&gt;@link&lt;/code&gt;, &lt;code&gt;@include&lt;/code&gt;, &lt;code&gt;@tests&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;annotation&lt;/strong&gt; — a fact about the whole file, in its header&lt;/td&gt;&lt;td&gt;the grammar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@assert&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an &lt;strong&gt;annotation&lt;/strong&gt; that describes nothing but itself — a condition settled while compiling&lt;/td&gt;&lt;td&gt;the analyzer, once&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;#if&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;directive&lt;/strong&gt; — a gate on lines&lt;/td&gt;&lt;td&gt;a pass before the lexer&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The last two are told apart by the sigil, and that is the whole rule.&lt;/strong&gt; An annotation is &lt;code&gt;@&lt;/code&gt; and
belongs to what it is written above — a declaration, or the file itself; a directive is &lt;code&gt;#&lt;/code&gt; and
gates lines. Nothing about
indentation is involved, which matters because a declaration at the margin — a &lt;code&gt;module&lt;/code&gt; header — has
its annotation at the margin too, so a rule about columns would have had the two forms competing for
one position.&lt;/p&gt;
&lt;p&gt;A directive is still written at column 1, and for its own reason: it is gone before anything counts a
column, so an indented one would look like it takes part in a block structure it has nothing to do
with. That is a rule about directives, not the thing that distinguishes them.&lt;/p&gt;
&lt;p&gt;Annotations come in groups, by what they attach to — and the last of them is the empty one, which is
as much a rule as the others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a function&lt;/strong&gt; there are eight, each written on its own line above the declaration. More than one
may be stacked, and writing the same one twice is refused. &lt;code&gt;@test&lt;/code&gt; and &lt;code&gt;@tailrec&lt;/code&gt; are below; &lt;code&gt;@pure&lt;/code&gt;,
&lt;code&gt;@ghost&lt;/code&gt;, &lt;code&gt;@reads&lt;/code&gt; and &lt;code&gt;@writes&lt;/code&gt; belong to the specification vocabulary and are on the
&lt;a href=&quot;/reference/verification/&quot;&gt;verification&lt;/a&gt; page; &lt;code&gt;@export&lt;/code&gt; makes the definition C-callable and is on
the &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI&lt;/a&gt; page, beside the &lt;code&gt;extern&lt;/code&gt; it is the mirror image of; &lt;code&gt;@crossing(...)&lt;/code&gt; says
a parameter hands a value to another concurrency domain and is on the
&lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt; page, beside the crossing rule it asks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a type, or on storage&lt;/strong&gt; there are four, and three of them are about &lt;em&gt;where&lt;/em&gt; rather than about
what the declaration does. &lt;code&gt;@packed&lt;/code&gt; and &lt;code&gt;@align(n)&lt;/code&gt; lay out a struct — no interior padding, and the
boundary the aggregate begins on — and &lt;code&gt;@align(n)&lt;/code&gt; marks one binding’s storage as well.
&lt;code&gt;@section(&amp;quot;...&amp;quot;)&lt;/code&gt; marks a binding &lt;strong&gt;or&lt;/strong&gt; a function, and says which linker section it lands in. All
three are below. The fourth is &lt;code&gt;@export&lt;/code&gt;, which on a struct names the type in a generated C header
rather than placing it, and is on the &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI&lt;/a&gt; page with the other half of itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On the file&lt;/strong&gt; there are five, in its header directly below &lt;code&gt;module&lt;/code&gt; and before everything else:
&lt;code&gt;@no_alloc&lt;/code&gt; and its siblings, &lt;code&gt;@requires(...)&lt;/code&gt;, &lt;code&gt;@link(&amp;quot;...&amp;quot;)&lt;/code&gt;, &lt;code&gt;@include(&amp;quot;...&amp;quot;)&lt;/code&gt;, and &lt;code&gt;@tests&lt;/code&gt;. The
first two say what the whole module may do; &lt;code&gt;@link&lt;/code&gt; says what its &lt;code&gt;extern&lt;/code&gt;s need at the linker and
&lt;code&gt;@include&lt;/code&gt; what its &lt;code&gt;c const&lt;/code&gt; and &lt;code&gt;c type&lt;/code&gt; blocks need at the C compiler; the last says it is scaffolding
for the module’s tests. All five attach to the file rather than to any declaration in it — and
writing one further down is refused with a message saying where it belongs. The first four are
covered under &lt;a href=&quot;/reference/modules/&quot;&gt;modules&lt;/a&gt; and &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI&lt;/a&gt;, where what they &lt;em&gt;mean&lt;/em&gt; is;
&lt;code&gt;@tests&lt;/code&gt; is below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On nothing at all&lt;/strong&gt; there is one: &lt;code&gt;@assert&lt;/code&gt;, which stands where a declaration stands and describes
only itself. It attaches to nothing, declares no name, and nothing can refer to one — two saying the
same thing are two checks rather than a duplicate. It is below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;On a member, none of them.&lt;/strong&gt; “A function” above means a &lt;em&gt;free&lt;/em&gt; function: a method, a property, an
associated function, a field and a variant take no annotation at all, and the refusal says so rather
than complaining about the indentation of the line:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

    &lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;is_zero&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = &lt;span class=&quot;hl-variable&quot;&gt;self&lt;/span&gt;.n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an annotation marks a function, and a member is not one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So what &lt;code&gt;sysl test&lt;/code&gt; runs is a free function that calls the member, and &lt;code&gt;@crossing(...)&lt;/code&gt; is written on
the wrapper a caller already goes through rather than on the method behind it — which is where the
call a program makes goes, and so where the complaint belongs. &lt;code&gt;@packed&lt;/code&gt; and &lt;code&gt;@align(n)&lt;/code&gt; are not the
exception they look like: they mark the &lt;strong&gt;struct&lt;/strong&gt;, written above &lt;code&gt;struct&lt;/code&gt; and not above a field.
&lt;code&gt;@assert&lt;/code&gt; inside a type’s body is refused too, and gets its own sentence, because it is not a claim
about the member under it — it goes beside the type, where &lt;code&gt;sizeof&lt;/code&gt; and &lt;code&gt;offsetof&lt;/code&gt; still name what it
is about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;#test&lt;/code&gt; above a member is answered by the same sentence&lt;/strong&gt;, with the sigil named at the end of it. A
directive is gone before the lexer counts a column, so an &lt;em&gt;indented&lt;/em&gt; &lt;code&gt;#&lt;/code&gt; never reaches the directive
pass at all and arrives at the member grammar instead — and being told only that an annotation is
written &lt;code&gt;@&lt;/code&gt; would send a reader to write &lt;code&gt;@test&lt;/code&gt;, which a member is refused just the same.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An annotation’s name is an ordinary identifier&lt;/strong&gt;, which is the point of writing these as
annotations at all: nothing here is reserved, so a program may still call something &lt;code&gt;test&lt;/code&gt;, &lt;code&gt;link&lt;/code&gt;,
&lt;code&gt;alloc&lt;/code&gt;, &lt;code&gt;no&lt;/code&gt; or &lt;code&gt;requires&lt;/code&gt;. &lt;code&gt;guide/slab&lt;/code&gt;‘s allocator calls its central function &lt;code&gt;alloc&lt;/code&gt; and threads
its free list through a field called &lt;code&gt;link&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;@&lt;/code&gt; is also read &lt;strong&gt;inside a pattern&lt;/strong&gt;, where it binds a name to what a sub-pattern matched
(&lt;a href=&quot;/reference/patterns/&quot;&gt;patterns&lt;/a&gt;). The two never compete: an annotation’s &lt;code&gt;@&lt;/code&gt; is a prefix at the
start of a line above a declaration, and a pattern’s is infix between a name and a pattern, in a
position no declaration may stand.&lt;/p&gt;
&lt;h2 id=&quot;what-a-type-s-own-name-answers&quot;&gt;&lt;code&gt;::&lt;/code&gt; — what a type’s own name answers&lt;/h2&gt;
&lt;p&gt;A type’s name is a type and not a value, so nothing is &lt;em&gt;read&lt;/em&gt; from it. What it answers are
&lt;strong&gt;attributes&lt;/strong&gt;, written with &lt;code&gt;::&lt;/code&gt; rather than &lt;code&gt;.&lt;/code&gt; so they stay out of the member namespace:
&lt;code&gt;Color::First&lt;/code&gt; cannot be confused with a variant, an associated function, or a member an &lt;code&gt;impl&lt;/code&gt;
added, and no &lt;code&gt;impl&lt;/code&gt; can shadow one by declaring a member of that name.&lt;/p&gt;
&lt;p&gt;Three kinds of type answer them, and each set is &lt;strong&gt;fixed and closed&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;a-simple-enum&quot;&gt;A simple enum&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Last&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Pos&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Val&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Succ&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;)), &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Pred&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Blue&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Image&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Value&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Blue&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)), &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Value&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Blue&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Red Blue
1 Blue
Green Green
Blue 9
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;is&lt;/th&gt;&lt;th&gt;traps&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::First&lt;/code&gt; / &lt;code&gt;T::Last&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the first and last variant&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Pos(v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a value’s &lt;strong&gt;0-based position&lt;/strong&gt; in the declaration&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Val(i)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the value at position &lt;code&gt;i&lt;/code&gt;&lt;/td&gt;&lt;td&gt;on a position past the last, or below zero&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Succ(v)&lt;/code&gt; / &lt;code&gt;T::Pred(v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the neighbouring value&lt;/td&gt;&lt;td&gt;at the last / at the first&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Image(v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the variant’s &lt;strong&gt;name&lt;/strong&gt;, as a &lt;code&gt;string&lt;/code&gt;&lt;/td&gt;&lt;td&gt;no&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T::Value(s)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the value a name stands for&lt;/td&gt;&lt;td&gt;on a name no variant has&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Position is not the discriminant, and that distinction is why &lt;code&gt;Pos&lt;/code&gt; and &lt;code&gt;Val&lt;/code&gt; exist.&lt;/strong&gt;
Discriminants may be explicit, non-contiguous and not zero-based — &lt;code&gt;Green&lt;/code&gt; above is position 1 and
discriminant 5 — so an ordinal has to be looked up rather than computed. &lt;code&gt;Pos&lt;/code&gt; and &lt;code&gt;Val&lt;/code&gt; are the two
directions of that lookup, and &lt;code&gt;Succ&lt;/code&gt;/&lt;code&gt;Pred&lt;/code&gt; walk the &lt;strong&gt;declaration order&lt;/strong&gt; rather than adding one.
Going the other way, to a value’s discriminant, is the ordinary conversion &lt;code&gt;int(c)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Image&lt;/code&gt; and &lt;code&gt;Value&lt;/code&gt; are the printed-name pair, and they are what makes a simple enum
observable.&lt;/strong&gt; The type carries no &lt;code&gt;==&lt;/code&gt; and no &lt;code&gt;Display&lt;/code&gt; of its own, which is why every line above
turns a value into a position or a name to look at it. A comparison is written on the discriminants,
&lt;code&gt;int(a) == int(b)&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;a-constrained-subtype&quot;&gt;A constrained subtype&lt;/h3&gt;
&lt;p&gt;The other set — &lt;code&gt;First&lt;/code&gt;, &lt;code&gt;Last&lt;/code&gt;, &lt;code&gt;Valid&lt;/code&gt;, &lt;code&gt;Succ&lt;/code&gt;, &lt;code&gt;Pred&lt;/code&gt;, &lt;code&gt;Range&lt;/code&gt; — belongs to a &lt;code&gt;within&lt;/code&gt;-ranged
integer subtype, and is on the &lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt; page beside the checking it
is the question form of.&lt;/p&gt;
&lt;p&gt;The two sets are spelled the same way for the same reason and overlap where the questions overlap,
but they are not one set: an enum has &lt;code&gt;Pos&lt;/code&gt;, &lt;code&gt;Val&lt;/code&gt;, &lt;code&gt;Image&lt;/code&gt; and &lt;code&gt;Value&lt;/code&gt; because its values are named
and unevenly spaced, and a subtype has &lt;code&gt;Valid&lt;/code&gt; and &lt;code&gt;Range&lt;/code&gt; because its values are a contiguous run of
integers.&lt;/p&gt;
&lt;h3 id=&quot;an-integer-type&quot;&gt;An integer type&lt;/h3&gt;
&lt;p&gt;The third set is two attributes wide — &lt;code&gt;Min&lt;/code&gt; and &lt;code&gt;Max&lt;/code&gt;, the extremes the type can hold. They belong
to every member of the &lt;code&gt;iN&lt;/code&gt;/&lt;code&gt;uN&lt;/code&gt; family, and to the named types that are members of it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;i8&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;i8&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;byte&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 255
-128 127
-2147483648 2147483647
0 255
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The open family is why these exist rather than being written out.&lt;/strong&gt; A program can spell &lt;code&gt;4294967295&lt;/code&gt;
for a &lt;code&gt;u32&lt;/code&gt; and lose nothing; the largest &lt;code&gt;u10000&lt;/code&gt; is 3,011 digits and cannot practically be written
at all, so for a wide member the attribute is the only way to name a value the type obviously has.
It is also why they cannot be a library table the way C’s &lt;code&gt;UINT8_MAX&lt;/code&gt; is — there is no finite set of
integer types to tabulate.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(u3::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, u3::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i5::&lt;span class=&quot;hl-type&quot;&gt;Min&lt;/span&gt;, i5::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 7
-16 15
18446744073709551615
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;They are constants taking no argument, so they fold.&lt;/strong&gt; That is what puts them where no call is
admitted — a &lt;code&gt;const&lt;/code&gt; initializer, an &lt;code&gt;@assert&lt;/code&gt; condition, an array bound:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;LIMIT&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;HALF&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt; / &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;LIMIT&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;HALF&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;65535 2147483647
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;usize&lt;/code&gt; answers only a floor across targets.&lt;/strong&gt; Its width is the pointer’s, so &lt;code&gt;usize::Min&lt;/code&gt; is 0
everywhere and &lt;code&gt;usize::Max&lt;/code&gt; is whatever the target makes it — a program that prints the latter is
reading a fact about the machine rather than about the language.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Min&lt;/code&gt;/&lt;code&gt;Max&lt;/code&gt; are not &lt;code&gt;First&lt;/code&gt;/&lt;code&gt;Last&lt;/code&gt; renamed&lt;/strong&gt;, and asking for the wrong pair is answered by name
rather than by a general refusal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;u8&apos; is an integer, not a declared sequence — its extremes are &apos;u8::Min&apos; and &apos;u8::Max&apos;. &apos;First&apos; and &apos;Last&apos; name the ends of an enum&apos;s variants or of a &apos;within&apos; range, which is a different question
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;First&lt;/code&gt; and &lt;code&gt;Last&lt;/code&gt; name the ends of a &lt;em&gt;declared sequence&lt;/em&gt; — an enum’s variants, a written range —
and an enum’s discriminants may be explicit and non-contiguous, so its first-declared variant need
not carry the smallest value. The two questions coincide on an integer and only there. &lt;strong&gt;A
&lt;code&gt;within&lt;/code&gt;-ranged subtype answers both&lt;/strong&gt;, since there they genuinely agree, and a reader who learned
&lt;code&gt;Min&lt;/code&gt; on &lt;code&gt;u32&lt;/code&gt; should not find it renamed on a subtype of &lt;code&gt;u32&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And a subtype that narrows nothing has its base’s&lt;/strong&gt;, because that is what it can hold. &lt;code&gt;First&lt;/code&gt; and
&lt;code&gt;Last&lt;/code&gt; still need a range, which is the same distinction one paragraph up — a declared sequence
against what the type can hold:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt; = &lt;span class=&quot;hl-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Handle&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;65535
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the case a &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;c type&lt;/code&gt;&lt;/a&gt; is always in: a measured typedef carries no range, so
asking a &lt;code&gt;size_t&lt;/code&gt; for its maximum is asking about the integer C said it is. A &lt;code&gt;where&lt;/code&gt; predicate is
the exception and is refused — it narrows the type without saying to what, so there is no extreme to
read off the declaration.&lt;/p&gt;
&lt;p&gt;Only integers have them: &lt;code&gt;f64::Max&lt;/code&gt; and &lt;code&gt;bool::Max&lt;/code&gt; are refused, the float because its extremes are
&lt;code&gt;sysl.math&lt;/code&gt;‘s business and the boolean because it is not that kind of type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A type parameter answers them too&lt;/strong&gt;, from whatever the instantiation bound it to — which is what
makes the bounds usable by a &lt;em&gt;library&lt;/em&gt; rather than only by a program. Bounded narrowing, integer
parsing, saturating arithmetic and a min/max reduction’s identity all want &lt;code&gt;T&lt;/code&gt;‘s extreme, and none of
them can name it any other way:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b: &lt;span class=&quot;hl-type&quot;&gt;u16&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;i8&lt;/span&gt;]())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;255 65535
127
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One body serves every width it is instantiated at, and the argument may be written at the call or
inferred from what the result is used as.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The parameter carries the type that was written&lt;/strong&gt;, so a &lt;code&gt;within&lt;/code&gt;-ranged subtype answers its own
bound rather than its base’s:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;within&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;Age&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;150
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the one place a transparent subtype and its base give different answers, which is why
&lt;a href=&quot;/reference/generics/#inference-is-bidirectional&quot;&gt;generics&lt;/a&gt; states the rule: everywhere a &lt;em&gt;value&lt;/em&gt;
flows the two are interchangeable, and a bound is the one thing either can produce that the other
cannot hold.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Min&lt;/code&gt; and &lt;code&gt;Max&lt;/code&gt; are the only two a parameter answers.&lt;/strong&gt; The rest stay on a written type name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;T&apos; is a type parameter, and the only attributes one answers are &apos;T::Min&apos; and &apos;T::Max&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The reason is the walk that checks a generic body &lt;strong&gt;once&lt;/strong&gt;, with &lt;code&gt;T&lt;/code&gt; standing for itself rather than
for any particular type. That walk has to hand back a typed value, and &lt;code&gt;Min&lt;/code&gt; and &lt;code&gt;Max&lt;/code&gt; both answer
&lt;em&gt;in &lt;code&gt;T&lt;/code&gt;&lt;/em&gt; — so one stand-in is right for both. &lt;code&gt;Valid&lt;/code&gt; answers a &lt;code&gt;bool&lt;/code&gt;, &lt;code&gt;Pos&lt;/code&gt; a &lt;code&gt;usize&lt;/code&gt; and &lt;code&gt;Image&lt;/code&gt; a
&lt;code&gt;string&lt;/code&gt;, so admitting those would mean restating each attribute’s result type a second time, in a
second place, where the two copies could drift apart.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing is asked of &lt;code&gt;T&lt;/code&gt; in the signature.&lt;/strong&gt; A parameter given a type with no extremes is reported
at the instantiation that gave it one, and the message names both:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt;
    x: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt; = &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Max&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a: &lt;span class=&quot;hl-type&quot;&gt;P&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;widest&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;T::Max&apos; needs an integer type, and &apos;T&apos; is P here
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the same deferral &lt;code&gt;sizeof(T)&lt;/code&gt; takes, and it is what keeps a bound from being something a
generic has to declare in order to measure.&lt;/p&gt;
&lt;h3 id=&quot;what-has-no-attributes&quot;&gt;What has no attributes&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A data enum&lt;/strong&gt;, because its value is a variant plus a payload, so a position, a name and a
neighbour are each questions about only half of it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(r: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, h: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Shape::First&apos; needs a simple enum, and &apos;Shape&apos; carries data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A generic enum&lt;/strong&gt;, because its name stands for no one value set until it is applied:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]
    &lt;span class=&quot;hl-function&quot;&gt;Full&lt;/span&gt;(v: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;Empty&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Box&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;First&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Box&apos; is generic, so &apos;Box::First&apos; has no single enum to read
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And an attribute outside the set is answered by name, since the set is closed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Red&lt;/span&gt;
    &lt;span class=&quot;hl-type&quot;&gt;Green&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Color&lt;/span&gt;::&lt;span class=&quot;hl-type&quot;&gt;Nonesuch&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;Color&apos; has no attribute &apos;Nonesuch&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;test-a-function-with-a-caller-nothing-else-has&quot;&gt;&lt;code&gt;@test&lt;/code&gt; — a function with a caller nothing else has&lt;/h2&gt;
&lt;p&gt;A word after &lt;code&gt;@&lt;/code&gt; that is neither &lt;code&gt;test&lt;/code&gt; nor &lt;code&gt;tailrec&lt;/code&gt; is answered by name rather than as grammar. The
set is closed, which is what makes a misspelling an error instead of a marker that quietly does
nothing — annotations are deliberately &lt;em&gt;not&lt;/em&gt; a general mechanism yet.&lt;/p&gt;
&lt;p&gt;The annotation goes on its own line above an ordinary function declaration, which may still be
&lt;code&gt;private&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, b: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = a + b

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;adds_two&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one and one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;an empty slice has no first element&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;first_of_empty&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nothing to see&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program prints &lt;code&gt;5&lt;/code&gt; and runs neither test, which is the whole of the arrangement: &lt;code&gt;sysl run&lt;/code&gt;
builds the program, and the tests are for &lt;code&gt;sysl test&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Four forms of the annotation:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;written&lt;/th&gt;&lt;th&gt;means&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@test&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an ordinary test, named after the function&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@test(&amp;quot;a sentence&amp;quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;named by the sentence instead&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@test(should_trap)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the test &lt;strong&gt;passes&lt;/strong&gt; by stopping the program&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@test(should_trap: &amp;quot;past the end&amp;quot;)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;…and the run must have printed that text&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;what-a-test-may-be&quot;&gt;What a test may be&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A test is an ordinary function with a caller nothing else has&lt;/strong&gt;: no parameters, no result, not
generic. All three are the same requirement from different sides, since the runner calls it with
nothing and reads the answer off whether it returned. They are checked &lt;strong&gt;at the annotation&lt;/strong&gt;, because
the function is a perfectly good function and it is &lt;code&gt;@test&lt;/code&gt; that made a promise about it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;takes_one&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(n &amp;gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;positive&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;@test&apos; function takes no parameters, and &apos;takes_one&apos; takes one — &apos;sysl test&apos; calls it with nothing, so there is nowhere for an argument to come from
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;generic_one&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;@test&apos; function has no type parameters, and &apos;generic_one&apos; declares &apos;T&apos; — a generic is compiled for the arguments a caller fixes, and the runner supplies none
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;gives_back&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a &apos;@test&apos; function returns nothing, and &apos;gives_back&apos; returns &apos;int&apos; — a test&apos;s result is whether it came back, so there is nothing to read a value with
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-test-passes-by-returning&quot;&gt;A test passes by returning&lt;/h3&gt;
&lt;p&gt;That is the whole protocol, and it is what lets a test assert &lt;strong&gt;in the language it is testing&lt;/strong&gt;
rather than in a framework. A broken &lt;code&gt;require&lt;/code&gt;, a bounds violation, an &lt;code&gt;unwrap&lt;/code&gt; of a &lt;code&gt;None&lt;/code&gt; — each
ends the process, and none of them had to know it was running under a test.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;should_trap&lt;/code&gt; inverts the reading, for a test whose subject &lt;em&gt;is&lt;/em&gt; the check. With a string it
additionally requires that the run printed it, which is what tells a trap from the &lt;strong&gt;right&lt;/strong&gt; trap. A
silent trap satisfies &lt;code&gt;should_trap&lt;/code&gt; and can satisfy no string, because a compiler-inserted check
raises a signal and says nothing — see &lt;a href=&quot;/reference/errors/&quot;&gt;what stopping looks like&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;a-test-has-one-caller-and-the-program-is-not-it&quot;&gt;A test has one caller, and the program is not it&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;run_it&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;adds_two&lt;/span&gt;()

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;adds_two&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;adds_two&apos; is a &apos;@test&apos; function, which &apos;sysl test&apos; calls and nothing else does — every other build leaves it out, so this call would have no definition to reach. Work two tests share belongs in an ordinary function they both call
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-is-dropped-and-when&quot;&gt;What is dropped, and when&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;sysl run&lt;/code&gt;, &lt;code&gt;sysl build&lt;/code&gt; and &lt;code&gt;sysl emit-llvm&lt;/code&gt; drop the tests — and drop them &lt;strong&gt;after&lt;/strong&gt; analysis. So a
&lt;code&gt;@test&lt;/code&gt; that does not compile is an error in a build that would never have run it, and a module’s
capability clause reaches its tests like any other member.&lt;/p&gt;
&lt;p&gt;That ordering is what lets a test sit beside what it tests: a program’s tests do not run when it
runs, and they do not stop being checked.&lt;/p&gt;
&lt;p&gt;A helper only a test calls leaves with it, because it becomes unreachable and pruning notices; a
helper the program also calls stays, because the program still calls it.&lt;/p&gt;
&lt;p&gt;What a test build keeps regardless is the four definitions &lt;strong&gt;nothing in the program names&lt;/strong&gt;: an
interrupt handler, an &lt;a href=&quot;/reference/ffi/&quot;&gt;&lt;code&gt;@export&lt;/code&gt;&lt;/a&gt;, a &lt;code&gt;@section&lt;/code&gt; definition (below), and a
&lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt;. Each is entered from somewhere no walk over the
program can see — the processor, a caller outside this compilation, a linker script gathering a named
section, and the release hook generated from a payload type — so each is a root wherever the walk
begins. A test build swaps the roots, putting the tests where the entry point was, and these four
are roots there too. They have to be: leaving them out would not make them reachable from the tests
instead, it would make them reachable from nothing.&lt;/p&gt;
&lt;p&gt;That matters most to a package, whose only build is its own suite. A test build dropping a destructor
could not link at all, the release hook being left to call a symbol nothing defined; one dropping an
export would link, pass, and quietly go without the surface the package exists to provide.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sysl build-lib&lt;/code&gt; is the exception, and drops them &lt;em&gt;before&lt;/em&gt; analysis.&lt;/strong&gt; An artifact is the one
output that outlives the compilation that made it, and analysis is not a passive reading: a test
naming &lt;code&gt;Buf[int]&lt;/code&gt; &lt;strong&gt;creates&lt;/strong&gt; the whole of &lt;code&gt;Buf&lt;/code&gt; at &lt;code&gt;int&lt;/code&gt;, and that instantiation is an ordinary
library function afterwards, with nothing in it recording which declaration asked for it. Dropping
the test from the analyzed program would therefore drop the test and keep everything it caused —
shipping instantiations no caller of the library ever asked for, and making the artifact’s contents
a fact about its tests.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The line falls between parsing and analysis.&lt;/strong&gt; Every source is parsed before the drop, so a
&lt;strong&gt;syntax&lt;/strong&gt; error in a &lt;code&gt;@tests&lt;/code&gt; file still stops a &lt;code&gt;build-lib&lt;/code&gt;. What such a file no longer gets is
everything after the parse — name resolution, types, visibility, capabilities, the &lt;code&gt;@test&lt;/code&gt;
well-formedness rules above, generic instantiation, and the duplicate-&lt;code&gt;@export&lt;/code&gt; check. So a library
test that is well-formed text and wrong in every other way builds clean, and its real errors are
reported by &lt;a href=&quot;/getting-started/cli/&quot;&gt;&lt;code&gt;sysl test --std&lt;/code&gt;&lt;/a&gt;, which is where a library’s tests are run.&lt;/p&gt;
&lt;p&gt;That last one is worth naming because it is the case where “everything after the parse” is easy to
apply to only half of a build. An &lt;code&gt;@export&lt;/code&gt; in a &lt;code&gt;@tests&lt;/code&gt; file names a symbol &lt;strong&gt;this&lt;/strong&gt; build is about
to discard, so it can collide with nothing — and a check that read the tree before the drop would
refuse a program over a name that was never going to be emitted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read the other way, &lt;code&gt;sysl test&lt;/code&gt; is the build where such an export &lt;em&gt;is&lt;/em&gt; a definition&lt;/strong&gt;, and it is
held to every rule on the &lt;a href=&quot;/reference/ffi/&quot;&gt;FFI page&lt;/a&gt; accordingly — private, variadic, generic, a
parameter C has no declaration for, two exports claiming one symbol, and an export reaching computed
module storage. Each of those asks about the symbol table the build in hand emits, so which tree is
read is the whole of the difference between the two commands.&lt;/p&gt;
&lt;h3 id=&quot;tests-a-file-of-scaffolding&quot;&gt;&lt;code&gt;@tests&lt;/code&gt; — a file of scaffolding&lt;/h3&gt;
&lt;p&gt;Pruning answers for a &lt;strong&gt;program&lt;/strong&gt;. It does not answer for a &lt;strong&gt;library&lt;/strong&gt;, which has no &lt;code&gt;main&lt;/code&gt; to lower
outwards from, so every public declaration is a potential entry and all of them are emitted. A helper
only a test called would ride into the artifact and be advertised out of it, nameable by everything
that links the library. Nothing about the declaration says it is scaffolding, and nothing could — it
is an ordinary function, which is the point of it.&lt;/p&gt;
&lt;p&gt;So the &lt;strong&gt;file&lt;/strong&gt; says it, in its header, beside the capability clauses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tests&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt; * &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the fixture is the answer&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;the_fixture_holds&lt;/span&gt;() =
    &lt;span class=&quot;hl-function&quot;&gt;assert_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;(), &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is &lt;code&gt;@tests&lt;/code&gt; and not &lt;code&gt;@test&lt;/code&gt; because the two say different things: &lt;code&gt;@test&lt;/code&gt; names something the
runner calls, and this names something no build but the runner’s keeps. One word for both would read
as though the file were itself a test.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two rules, and either alone would be unsound.&lt;/strong&gt; Every build but &lt;code&gt;sysl test&lt;/code&gt; drops everything such a
file declares — and nothing outside a test may name any of it. Without the second, a program that
called a helper would compile here and fail at the &lt;em&gt;link&lt;/em&gt;, with a message about a missing symbol
rather than about the line that named it.&lt;/p&gt;
&lt;p&gt;The restriction is stated over the &lt;strong&gt;referring declaration&lt;/strong&gt;, not over the file it sits in. So a
&lt;code&gt;@test&lt;/code&gt; function may name scaffolding wherever it was written — which is what keeps a test able to
sit beside what it tests — and another &lt;code&gt;@tests&lt;/code&gt; file may, and nothing else may:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tests&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt; * &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;error: &apos;fixture&apos; is declared in a file that said &apos;@tests&apos;, so it is there for the module&apos;s tests and no build but &apos;sysl test&apos; keeps it — only another such file, or a &apos;@test&apos; function, may name it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A closure counts as the body it was written in.&lt;/strong&gt; It is lowered to a function of its own under a
name nobody wrote, so on its own terms it belongs to no file — but what decides is where it sits, not
what it ends up called. A lambda inside a test may name the test file’s own scaffolding, and so may a
bare function name, which is the same thing written shorter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tests&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt; * &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Fn&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(n)

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the fixture is the answer, reached through a callback&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;the_fixture_holds&lt;/span&gt;() =
    &lt;span class=&quot;hl-function&quot;&gt;assert_eq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(v -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;fixture&lt;/span&gt;() + v, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It goes when the file goes, too, which is the half that makes the naming safe: the program that ships
carries no body for it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;impl&lt;/code&gt; block may not sit in one.&lt;/strong&gt; It declares no name; it fills a slot in a method table, which
the rest of the program reads without naming anything. Kept in a test build and dropped everywhere
else, it would mean a trait answering one way while the tests ran and another way in the program that
ships. The impl belongs beside the type. A closure is the one exception the compiler makes for
itself, and it is not a hole: the table it writes is dropped with the closure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It stops at the package boundary.&lt;/strong&gt; A package is compiled from source and a library arrives as an
artifact whose test files were never encoded, so a rule that let the reference cross would compile
against one and fail against the other. A test-support library &lt;em&gt;meant&lt;/em&gt; to be imported is therefore
ordinary code that ships, and is a different thing from a file of scaffolding inside a package.&lt;/p&gt;
&lt;h3 id=&quot;the-runner&quot;&gt;The runner&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;sysl test &amp;lt;path&amp;gt;
sysl test &amp;lt;path&amp;gt; --filter &amp;lt;text&amp;gt;
sysl test &amp;lt;path&amp;gt; --fail-fast
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One build, one process per test.&lt;/strong&gt; The tree is compiled once, into a binary whose entry point takes
a test’s name and runs that test alone — the program’s own statements and its &lt;code&gt;main&lt;/code&gt; are not run,
though its module-level &lt;code&gt;val&lt;/code&gt;s are still filled, since a test reads a module’s storage like any other
function. The runner then starts that binary once per test.&lt;/p&gt;
&lt;p&gt;The process per test is not a cost being tolerated; &lt;strong&gt;it is the mechanism.&lt;/strong&gt; A test that fails does
so by ending its process, so a run that shared one would report the first failure and nothing after
it. The compile is the slow half, and there is only ever one of it.&lt;/p&gt;
&lt;p&gt;Exit status is 0 if and only if every test that ran passed. A tree with no tests, and a filter that
matched none of the tests there are, both exit 0 and say which happened.&lt;/p&gt;
&lt;h3 id=&quot;assert-and-panic&quot;&gt;&lt;code&gt;assert&lt;/code&gt; and &lt;code&gt;panic&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Both are ordinary functions in the standard module:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;panic&lt;/span&gt;(msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;never&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;panic:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, msg)
    &lt;span class=&quot;hl-function&quot;&gt;exit&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(cond: &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt;, msg: &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; !cond &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;panic&lt;/span&gt;(msg)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They exist because &lt;code&gt;require&lt;/code&gt; is a promise about a &lt;strong&gt;call&lt;/strong&gt;, checked on entry, and a test’s fifth
statement has no contract to hang a claim on — the contract was about the arguments, four statements
ago.&lt;/p&gt;
&lt;p&gt;They stop the program the way &lt;code&gt;unwrap&lt;/code&gt; does — a line naming what happened, then the hosted exit —
rather than through the trap instruction, because &lt;strong&gt;a check a program makes is one the compiler
cannot see, and the message is the whole point of it.&lt;/strong&gt; The message is required rather than
defaulted, because the condition’s source is not available to print and a failure saying only
“assertion failed” sends its reader looking for which one.&lt;/p&gt;
&lt;h2 id=&quot;assert-a-condition-settled-while-compiling&quot;&gt;&lt;code&gt;@assert&lt;/code&gt; — a condition settled while compiling&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; capacity: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;512&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(capacity == &lt;span class=&quot;hl-number&quot;&gt;512&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the protocol fixes this&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(capacity)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;512
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The condition is a &lt;a href=&quot;/reference/modules/&quot;&gt;constant expression&lt;/a&gt;, folded by the machinery
a &lt;code&gt;const&lt;/code&gt; initializer already goes through — so it may name constants, &lt;code&gt;sizeof&lt;/code&gt;, &lt;code&gt;alignof&lt;/code&gt;,
&lt;code&gt;offsetof&lt;/code&gt;, and the arithmetic and comparisons over them, including a constant declared &lt;em&gt;below&lt;/em&gt; it. A true one emits
nothing at all. A false one stops the compilation, quoting the message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; == &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;arithmetic broke&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;assertion failed: arithmetic broke
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The message is optional and is the reader’s own, because they know what the number &lt;em&gt;means&lt;/em&gt; — that a
struct matches its C counterpart, that a table is the size a protocol fixes — where the expression
alone says only that two numbers differ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A failed comparison also says what each side came out as.&lt;/strong&gt; The compiler folded both in order to
decide the condition, so it has the numbers at the moment it reports that one of them is wrong, and
withholding them would leave you editing the literal and rebuilding to find out. A side you wrote as
a literal is not repeated back — it is on the line above the message — so &lt;code&gt;sizeof(FRect) == 16&lt;/code&gt;
reports only the left; where both sides are computed, both are named. A condition that is not a
comparison has nothing to add, since the thing that came out &lt;code&gt;false&lt;/code&gt; is its only operand.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is not &lt;code&gt;require&lt;/code&gt;.&lt;/strong&gt; A &lt;code&gt;require&lt;/code&gt; is a runtime precondition: it is compiled, it branches, and it
traps when the program reaches it. This is settled while compiling and reaches the binary as nothing.
A condition it cannot settle is refused rather than deferred — and a call is the line, since a call
in a constant expression would be a request for compile-time evaluation of arbitrary code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() == &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;has to be a constant expression
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;checking-a-c-struct-s-layout&quot;&gt;Checking a C struct’s layout&lt;/h3&gt;
&lt;p&gt;This is what it was built for. sysl lays a struct out in declaration order and is C-compatible by
construction, but from inside sysl that claim cannot be checked: &lt;code&gt;sizeof&lt;/code&gt; reports what &lt;em&gt;sysl&lt;/em&gt; laid
out, not what the header says, so comparing the two is a tautology.&lt;/p&gt;
&lt;p&gt;Where the C side is &lt;code&gt;__attribute__((packed))&lt;/code&gt; or was declared at a boundary, &lt;code&gt;@packed&lt;/code&gt; and
&lt;code&gt;@align(n)&lt;/code&gt; further down this page are how the sysl side says the same thing — and the check below is
what proves the two agree rather than merely look similar.&lt;/p&gt;
&lt;p&gt;It stops being one when both sides name the same number. The C half goes in a &lt;code&gt;.c&lt;/code&gt; beside the sysl,
which &lt;a href=&quot;/reference/ffi/&quot;&gt;is compiled with it&lt;/a&gt; and for the same target, so it reads the headers of the
machine being built for:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;lt;stddef.h&amp;gt;
_Static_assert(sizeof(struct pair) == 8, &amp;quot;struct pair size moved&amp;quot;);
_Static_assert(offsetof(struct pair, b) == 4, &amp;quot;struct pair.b moved&amp;quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the sysl half pins what sysl laid out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Pair must match struct pair&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;, b) == &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;struct pair.b moved&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;, b))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Neither half finds the other’s mistake, which is why both are written: the &lt;code&gt;.c&lt;/code&gt; catches a header that
moved, and the &lt;code&gt;@assert&lt;/code&gt; catches a struct that was transcribed wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pin every field you read, not only the total.&lt;/strong&gt; A size catches a field that changed width and one
that was added. It says nothing about &lt;strong&gt;order&lt;/strong&gt; — so two same-width fields transposed in the mirror
leave the total unchanged, and the size assertion on &lt;em&gt;both&lt;/em&gt; sides passes while every read is off by
the distance between them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;
    b: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Pair&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;) == &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Pair must match struct pair&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;, b) == &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;struct pair.b moved&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;assertion failed: struct pair.b moved — the left side is 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the failure the whole pairing exists to prevent, arriving through the half that was not
checked. &lt;code&gt;offsetof(T, field)&lt;/code&gt; closes it: it takes a type and a field &lt;strong&gt;name&lt;/strong&gt;, and answers where the
field starts in bytes. A field the struct does not have is refused by name rather than reported as a
condition that would not fold.&lt;/p&gt;
&lt;h3 id=&quot;inside-a-generic-where-it-is-settled-once-per-instantiation&quot;&gt;Inside a generic, where it is settled once per instantiation&lt;/h3&gt;
&lt;p&gt;A generic’s interesting facts are not properties of its declaration — they are properties of each set
of arguments it is compiled for. &lt;code&gt;sizeof(T)&lt;/code&gt; has no width until something chooses a &lt;code&gt;T&lt;/code&gt;, so an
assertion about one is settled at every instantiation rather than once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;slab&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) &amp;gt;= &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a free block has to hold the link through it&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;slab&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u64&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An argument the claim does not hold for stops the compilation, and the report names which one asked —
the mistake is at the call that chose the type, while the sentence explaining why is at the
declaration, so a message carrying only one of the two sends its reader to the wrong file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;slab&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;](x: &lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;) &amp;gt;= &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a free block has to hold the link through it&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;slab&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1u8&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;assertion failed: a free block has to hold the link through it — the left side is 1 and the right side is 8 — where T = byte
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;This is the check &lt;code&gt;require&lt;/code&gt; cannot make.&lt;/strong&gt; A precondition over &lt;code&gt;sizeof(T)&lt;/code&gt; written as a &lt;code&gt;require&lt;/code&gt; is
a runtime branch for a fact that was settled at the call: a container instantiated at a type too
narrow compiles, ships, and traps the first time anybody uses it. &lt;code&gt;guide/slab&lt;/code&gt; was written that way
before this and is the worked example of the difference.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;value&lt;/strong&gt; parameter is bound the same way and so is checked the same way, which is what lets a
generic hold its caller to a bound on a length:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scratch&lt;/span&gt;[&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;](xs: [&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;assert&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt; &amp;lt;= &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the scratch buffer is a stack array&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; small: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;scratch&lt;/span&gt;(small))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A generic nothing instantiates is not checked&lt;/strong&gt;, and that is the same deferral an array bound
already lives under: &lt;code&gt;[sizeof(T)]u8&lt;/code&gt; is a well-formed length nobody can name until a &lt;code&gt;T&lt;/code&gt; is chosen,
and the width is not wrong there — it is not being measured yet. The claim is settled at the first
call, which is the first moment there is anything to settle. A condition that could &lt;em&gt;never&lt;/em&gt; fold is
still refused inside a generic, exactly as it is outside one.&lt;/p&gt;
&lt;h2 id=&quot;tailrec-an-assertion-that-the-frame-is-reused&quot;&gt;&lt;code&gt;@tailrec&lt;/code&gt; — an assertion that the frame is reused&lt;/h2&gt;
&lt;p&gt;A function whose last act is a call to itself compiles to a branch back to its own entry rather than
a second frame, so the recursion is bounded by the arithmetic and not by the stack. That happens
whether or not anything is written — see
&lt;a href=&quot;/reference/declarations/#tail-calls&quot;&gt;tail calls&lt;/a&gt; for what counts as the last act, and for the two
things that end a tail position.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@tailrec&lt;/code&gt; asserts the jump is there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tailrec&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, acc: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; =
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; acc &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, acc + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;100000&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;100000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What it buys is the refusal. The optimization is silent, so an edit that costs it is silent too —
until the day the recursion is deep enough to matter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;tailrec&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, acc: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; =
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n == &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; acc &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; + &lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(n - &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, acc)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;count&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;calls itself nowhere the jump can replace
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It changes nothing about what is emitted. Write it where losing the jump silently would be a bug,
and leave it off everywhere else.&lt;/p&gt;
&lt;h2 id=&quot;packed-and-align-n-where-a-struct-s-fields-sit&quot;&gt;&lt;code&gt;@packed&lt;/code&gt; and &lt;code&gt;@align(n)&lt;/code&gt; — where a struct’s fields sit&lt;/h2&gt;
&lt;p&gt;By default a struct pads: each field begins on its own alignment, and the aggregate takes the widest
of them. That is the layout a program wants unless something outside the program has an opinion.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three bytes of that eight are a gap in front of &lt;code&gt;len&lt;/code&gt;. &lt;strong&gt;Two attributes move a struct off the
default, and they are separate axes&lt;/strong&gt; — one removes the padding &lt;em&gt;between&lt;/em&gt; fields, the other raises
where the aggregate &lt;em&gt;begins&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;packed-no-interior-padding&quot;&gt;&lt;code&gt;@packed&lt;/code&gt; — no interior padding&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 1 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The fields are laid end to end, the aggregate needs no alignment of its own, and an array of them has
no gap between elements either. A register block, and a C struct that has to match one, are what it
is for.&lt;/p&gt;
&lt;p&gt;The fields still read and write their own values — packing changes where they sit, not what they are:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h = &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1000&lt;/span&gt;)

h.len += &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(h.tag, h.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 1001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A packed field has no address.&lt;/strong&gt; &lt;code&gt;&amp;amp;s.f&lt;/code&gt; is refused, and so is any &lt;code&gt;*T&lt;/code&gt; into one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h = &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;h.len

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;&amp;amp;&apos; here makes a &apos;*uint&apos; into Head, which is &apos;@packed&apos; — its fields sit at their declared offsets, so this one need not be on a &apos;uint&apos; boundary, and every use of a &apos;*uint&apos; is entitled to assume that it is. Read or write the field through the struct, which is where the offset is known, or take the address of the Head itself
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The field sits at its declared offset, which is very often &lt;em&gt;not&lt;/em&gt; a multiple of its own alignment —
that is the point of the attribute — while a &lt;code&gt;*u32&lt;/code&gt; is a &lt;code&gt;*u32&lt;/code&gt; wherever it came from, and every use
of one is entitled to assume the address is aligned. Only the escaped address loses that, and it
would lose it arbitrarily far from the &lt;code&gt;&amp;amp;&lt;/code&gt; that made it. &lt;strong&gt;The struct’s own address is untouched&lt;/strong&gt;,
being an ordinary pointer to an ordinary aggregate.&lt;/p&gt;
&lt;h3 id=&quot;bitfields-an-in-field-in-exactly-n-bits&quot;&gt;Bitfields — an &lt;code&gt;iN&lt;/code&gt; field in exactly N bits&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Inside &lt;code&gt;@packed&lt;/code&gt;, an integer field occupies exactly its declared width.&lt;/strong&gt; A packed struct whose
fields all lower to an integer, at least one of them narrower than a byte, &lt;strong&gt;is&lt;/strong&gt; one unsigned
integer — and its fields are ranges of it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    enable: u1
    mode: u3
    prescale: u4

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;), c.enable, c.mode, c.prescale)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 1 5 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No syntax was needed for this, which is why there is none: the open integer family already does the
work C needs &lt;code&gt;int x : 3&lt;/code&gt; for, so a five-bit field is written &lt;code&gt;u5&lt;/code&gt; in a struct exactly as it is
anywhere else.&lt;/p&gt;
&lt;p&gt;Two things follow that C leaves to the implementation, and pinning them is the point of the feature
rather than a detail of it — it is why portable embedded C avoids bitfields and writes the shifts out
by hand. &lt;strong&gt;The bits fill from the least significant upward in declaration order&lt;/strong&gt;, and &lt;strong&gt;a field
straddles a byte boundary&lt;/strong&gt; rather than moving off it. Both are visible in the storage:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    enable: u1
    mode: u3
    prescale: u4

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; arena: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

c.enable = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
c.mode = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
c.prescale = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(arena[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;155
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;155&lt;/code&gt; is &lt;code&gt;1 | 5 &amp;lt;&amp;lt; 1 | 9 &amp;lt;&amp;lt; 4&lt;/code&gt;: the first field declared is the low bits.&lt;/p&gt;
&lt;p&gt;The rule is stated over the &lt;strong&gt;integer’s value&lt;/strong&gt; and never over memory bytes. Written the other way —
“the low bits of byte 0” — it would be a claim about endianness, which nothing in sysl is allowed to
make. Written this way it costs nothing: the struct is an integer, so how it reaches memory is the
target’s ordinary byte order for an integer of that width. A wire format’s byte order belongs to the
protocol rather than to the CPU, and stays with
&lt;a href=&quot;/library/encoding/&quot;&gt;&lt;code&gt;sysl.encoding.binary&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;get_u16_le&lt;/code&gt; and the rest.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every field has to be an integer.&lt;/strong&gt; A &lt;code&gt;bool&lt;/code&gt; is not one here — its storage is a byte and its
representation a bit — and neither is a pointer, a float or an array:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Mixed&lt;/span&gt;
    p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    a: u3

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; m = &lt;span class=&quot;hl-type&quot;&gt;Mixed&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(m.a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is one integer, and every field of it has to be one too
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nesting is the composition path&lt;/strong&gt;, and it costs nothing: a bitfield struct is a leaf, and an
ordinary &lt;code&gt;@packed&lt;/code&gt; struct lays one out as a field of its size.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    enable: u1
    mode: u3
    prescale: u4

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Block&lt;/span&gt;
    ctrl: &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    count: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-type&quot;&gt;Block&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)

b.ctrl.mode = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Block&lt;/span&gt;), b.ctrl.enable, b.ctrl.mode, b.count)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;5 1 2 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A bitfield may be &lt;code&gt;volatile&lt;/code&gt;, and it means a volatile access of the container.&lt;/strong&gt; Reading a field is
one volatile load of the whole container; writing one is a volatile load and a volatile store of it —
what C does with &lt;code&gt;volatile unsigned x : 3&lt;/code&gt;, and what lets a &lt;code&gt;@packed&lt;/code&gt; struct describe a hardware
register rather than only a data layout:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Reg&lt;/span&gt;
    enable: volatile u1
    mode: volatile u3
    prescale: volatile u4

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; block: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0u8&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; r: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Reg&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;block[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

r.enable = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
r.prescale = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;
r.mode = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(block[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], r.enable, r.mode, r.prescale)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;155 1 5 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The qualifier belongs to the container rather than to one range of it&lt;/strong&gt;, so writing it on any field
qualifies every access to the struct. Every field of a bitfield struct is bits of one word, so there
is no shadow field here to stay ordinary — which is the thing per-field qualification buys in an
ordinary register block. The struct itself still may not carry the qualifier, and does not need to:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    a: u3
    b: u5

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;volatile &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;ptr_cast&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4096usize&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p.a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;volatile Ctrl&apos; is not a type
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A write is a read-modify-write, and nothing diagnoses what that costs.&lt;/strong&gt; A device is entitled to one
bus cycle, so writing a field of a register with &lt;strong&gt;clear-on-read&lt;/strong&gt; or &lt;strong&gt;write-1-to-clear&lt;/strong&gt; semantics
corrupts the ranges beside it — the read that begins the sequence has already had its effect. Nothing
in the language describes a register’s read semantics, so this is stated rather than refused, exactly
as it is in C. A register of that kind keeps its &lt;code&gt;volatile u32&lt;/code&gt; and its shifts, where the single
access is written out.&lt;/p&gt;
&lt;p&gt;A field that is a set of named values is a &lt;strong&gt;simple enum&lt;/strong&gt;, which is one integer and may be &lt;code&gt;volatile&lt;/code&gt;
like any other. A &lt;strong&gt;data enum&lt;/strong&gt; may not — a tag beside a payload is more than the one access the
qualifier promises.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bitfield has no byte offset&lt;/strong&gt;, so &lt;code&gt;offsetof&lt;/code&gt; says so rather than rounding down to the byte the
field begins in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;
    enable: u1
    mode: u3
    prescale: u4

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;offsetof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ctrl&lt;/span&gt;, mode))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is a bitfield — it starts at bit 1 of the struct and is 3 bits wide, so it has no byte offset
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It has no address either, which is the packed rule above and needs no separate ruling.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Across a C boundary it travels as what it is&lt;/strong&gt; — a packed struct of one integer — and not as a C
bitfield struct. Those are different things on some machines, and it is C’s own doing: MSVC allocates
&lt;code&gt;unsigned a:1&lt;/code&gt; into a four-byte unit where the Itanium ABI packs it into a byte, so a C bitfield
struct of the same fields need not even be the same &lt;em&gt;size&lt;/em&gt; everywhere. A sysl bitfield struct is one
integer on every target.&lt;/p&gt;
&lt;h3 id=&quot;align-n-where-the-aggregate-begins&quot;&gt;&lt;code&gt;@align(n)&lt;/code&gt; — where the aggregate begins&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;64 64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The size rounds up as well as the start, so an array keeps every element on the boundary. &lt;strong&gt;It may
only raise&lt;/strong&gt;: asking for less than the fields already need changes nothing, since lowering is what
&lt;code&gt;@packed&lt;/code&gt; is for and a type that under-promised would be unsound to pass around.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The bound is folded rather than lexed&lt;/strong&gt;, so a program writes the name it already has for the number,
and arithmetic over one works:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;CACHE_LINE&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;CACHE_LINE&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It must be a power of two — an address is aligned by having low bits clear, so a boundary of six is
unsatisfiable rather than merely weak:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;S&lt;/span&gt;
    a: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;@align(6)&apos; on &apos;S&apos; is not an alignment — a boundary is a power of two, since an address is aligned by having low bits clear
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;they-compose&quot;&gt;They compose&lt;/h3&gt;
&lt;p&gt;The gaps &lt;em&gt;between&lt;/em&gt; fields and the boundary the whole thing &lt;em&gt;starts&lt;/em&gt; on are different questions, so a
wire header that has to live in a DMA-capable buffer is both at once. The order they are written in
does not matter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;
    tag: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    len: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;sizeof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;), &lt;span class=&quot;hl-keyword&quot;&gt;alignof&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Head&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;16 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Sub-byte fields are a separate axis and &lt;code&gt;@align(n)&lt;/code&gt; does not touch them.&lt;/strong&gt; Inside &lt;code&gt;@packed&lt;/code&gt; an &lt;code&gt;iN&lt;/code&gt;
field occupies exactly N bits (&lt;a href=&quot;#bitfields-an-in-field-in-exactly-n-bits&quot;&gt;bitfields&lt;/a&gt; above); the
boundary the aggregate &lt;em&gt;begins&lt;/em&gt; on is this attribute, and a bitfield struct takes one like any other.&lt;/p&gt;
&lt;h3 id=&quot;align-n-on-a-binding&quot;&gt;&lt;code&gt;@align(n)&lt;/code&gt; on a binding&lt;/h3&gt;
&lt;p&gt;The boundary may also be written on the storage itself — a &lt;code&gt;var&lt;/code&gt; or a &lt;code&gt;val&lt;/code&gt;, at the top of a module
or inside a function, and on the &lt;code&gt;static&lt;/code&gt; spelling of either.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; region: [&lt;span class=&quot;hl-number&quot;&gt;128&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;

region[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;7u8&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(region[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], region.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 128
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It says nothing the struct form could not. A boundary put on a type travels with every value of it,
and a named aligned type is reusable where a repeated attribute is not — so reach for the type when
more than one thing needs the boundary. What this spelling saves is at the &lt;em&gt;use&lt;/em&gt; site: a buffer
wrapped in a struct is read as &lt;code&gt;region.bytes[i]&lt;/code&gt; rather than &lt;code&gt;region[i]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;@packed&lt;/code&gt; has no meaning here&lt;/strong&gt;, and says so, because it describes the arrangement of fields inside
an aggregate and a binding has none:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;packed&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;@packed&apos; describes how a struct&apos;s fields are laid out, so it can only mark a struct — a &apos;var&apos; or a &apos;val&apos; has no fields to pack, and &apos;@align(n)&apos; is the one of the two that may stand above one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A binding that names &lt;strong&gt;several&lt;/strong&gt; things is refused for a related reason: there is no one object for a
boundary to be about.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a, b = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;@align(n)&apos; is the boundary one object&apos;s storage begins on, and a binding that names several has no one object for it to be about — declare them on lines of their own
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bound is held to the same rule a struct’s is — a power of two, folded rather than lexed, so a
&lt;code&gt;const&lt;/code&gt; or arithmetic over one is what a program writes.&lt;/p&gt;
&lt;h2 id=&quot;section-where-a-symbol-lands&quot;&gt;&lt;code&gt;@section(&amp;quot;...&amp;quot;)&lt;/code&gt; — where a symbol lands&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@align(n)&lt;/code&gt; says what boundary storage begins on. &lt;code&gt;@section&lt;/code&gt; says &lt;strong&gt;where the storage is&lt;/strong&gt;, and it is
what a program reaches for when the address of a thing is part of what it is: a vector table at the
address the processor fetches from, storage in &lt;code&gt;.noinit&lt;/code&gt; that survives a warm reset, a DMA buffer in
the RAM bank the engine can reach, a function copied into RAM so it can run while flash is being
erased.&lt;/p&gt;
&lt;p&gt;It marks whatever occupies an address — a module &lt;code&gt;var&lt;/code&gt;, a module &lt;code&gt;val&lt;/code&gt;, and a function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.noinit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; crash_reason: &lt;span class=&quot;hl-type&quot;&gt;u32&lt;/span&gt;

&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.ramfunc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;erase_page&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;bool&lt;/span&gt; = n &amp;lt; &lt;span class=&quot;hl-number&quot;&gt;64&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Nothing on this page runs one of these.&lt;/strong&gt; A section name belongs to the target’s object format —
&lt;code&gt;.noinit&lt;/code&gt; is ELF’s spelling, &lt;code&gt;__DATA,__mine&lt;/code&gt; is Mach-O’s — so a program that places something is a
program about one machine, and the machine this page’s examples run on is not the interesting one.&lt;/p&gt;
&lt;p&gt;That is also why the compiler does not check what is in the string. A set of characters chosen by
sysl would refuse a section some target requires, and the assembler that will not take one says so
better than a rule here could. It is &lt;code&gt;extern&lt;/code&gt;‘s link name and &lt;code&gt;@export&lt;/code&gt;‘s symbol read a third time:
a spelling belongs to whoever consumes it.&lt;/p&gt;
&lt;h3 id=&quot;it-composes-with-align-n&quot;&gt;It composes with &lt;code&gt;@align(n)&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The two are different axes — one is the boundary an object &lt;em&gt;begins&lt;/em&gt; on, the other is where it
&lt;em&gt;lives&lt;/em&gt; — and a statically placed stack is written with both. The order does not matter.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;align&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4096&lt;/span&gt;)
&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.noinit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; page_table: [&lt;span class=&quot;hl-number&quot;&gt;512&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u64&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-placed-symbol-is-kept&quot;&gt;A placed symbol is kept&lt;/h3&gt;
&lt;p&gt;Nothing inside the program reads a table that a linker script gathers — that is the whole point of
writing one — so a placed definition is a &lt;strong&gt;root&lt;/strong&gt;, exactly as an interrupt handler and an &lt;code&gt;@export&lt;/code&gt;ed
function are, and a placed symbol is marked so that the optimizer does not delete an object with no
reader.&lt;/p&gt;
&lt;p&gt;Without that second half the attribute would compile, link, and place nothing. The failure would be
the &lt;em&gt;absence&lt;/em&gt; of a section, which is not a thing anybody looks for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A placed definition a dependency supplied is kept only where your program reaches its module&lt;/strong&gt;,
which is the rule &lt;a href=&quot;/reference/ffi/&quot;&gt;the FFI page&lt;/a&gt; states for every kind of root at once. It bites
hardest here, because being marked is exactly what stops anything downstream undoing it: a placed
definition kept for want of the rule is bytes in your image that no optimizer will remove, in the
region the attribute exists to manage. A package whose placed definition you want is one you name —
an &lt;code&gt;import&lt;/code&gt; is enough.&lt;/p&gt;
&lt;h3 id=&quot;what-it-may-not-mark&quot;&gt;What it may not mark&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;const&lt;/code&gt; is folded into every use and has no storage; a type is not an object. Neither takes a
section:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.rodata&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;N&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;@section(&amp;quot;...&amp;quot;)&apos; places one object in a linker section, so it marks a &apos;var&apos;, a &apos;val&apos; or a function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;local&lt;/strong&gt; is refused for a different reason, and the message says which — its storage is the frame
of whichever call is running, while a section is a region of the image, decided once at the link:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.noinit&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    n

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;n&apos; is a local, so it cannot be placed in section &amp;quot;.noinit&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A binding that names several things has no one object for a section to be about, which is the rule
&lt;code&gt;@align(n)&lt;/code&gt; above already follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;section&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;.data&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a, b = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;@section(&amp;quot;...&amp;quot;)&apos; places one object, and a binding that names several has no one object for it to be about
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;if-gating-lines-before-the-lexer&quot;&gt;&lt;code&gt;#if&lt;/code&gt; — gating lines before the lexer&lt;/h2&gt;
&lt;p&gt;Everything a target decides is a fact the &lt;em&gt;compiler&lt;/em&gt; reads about the machine. &lt;code&gt;#if&lt;/code&gt; is the one place
a &lt;strong&gt;program&lt;/strong&gt; reads one, and it exists because machines genuinely differ in ways a library cannot
paper over: a syscall number, a struct a header lays out two ways, a symbol one libc exports and the
other does not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; posix
&lt;span class=&quot;hl-function&quot;&gt;line_ending&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;line_ending&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a posix machine&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;line_ending&lt;/span&gt;().len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a posix machine 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What differs between the branches is the implementation, not the answer.&lt;/strong&gt; That is the shape most
uses of &lt;code&gt;#if&lt;/code&gt; have: a syscall number, a struct a header lays out two ways, a symbol one libc exports
and the other does not — chosen per machine so that everything above the choice can stop caring.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#elif&lt;/code&gt; chains, and &lt;code&gt;#else&lt;/code&gt; catches what nothing named:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; aarch64
&lt;span class=&quot;hl-function&quot;&gt;machine&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;aarch64&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;elif&lt;/span&gt; x86_64
&lt;span class=&quot;hl-function&quot;&gt;machine&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x86_64&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;elif&lt;/span&gt; riscv64
&lt;span class=&quot;hl-function&quot;&gt;machine&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;riscv64&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;machine&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;something else&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That one is quoted rather than run, because what it prints is &lt;em&gt;supposed&lt;/em&gt; to depend on the machine —
which is the whole point of the construct and exactly what a page cannot pin to one answer.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#if&lt;/code&gt; / &lt;code&gt;#elif&lt;/code&gt; / &lt;code&gt;#else&lt;/code&gt; / &lt;code&gt;#endif&lt;/code&gt;, nesting freely, and &lt;strong&gt;the branches are exclusive&lt;/strong&gt; — the first
whose condition holds is the one that contributes, and a group inside a branch that was not taken
contributes nothing however its own condition reads.&lt;/p&gt;
&lt;h3 id=&quot;it-gates-lines-and-it-gates-them-before-anything-is-parsed&quot;&gt;It gates lines, and it gates them before anything is parsed&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A line in a branch this build is not for is replaced by an empty line, not removed&lt;/strong&gt;, and so is
every directive line. After the pass the file is an ordinary sysl file that happens to have some
blank lines in it, and nothing downstream knows any of this happened.&lt;/p&gt;
&lt;p&gt;Replaced rather than removed, because &lt;strong&gt;every line below a gate has to keep the number it was written
at.&lt;/strong&gt; Deleting them would leave the messages right and the carets somewhere else, with nothing to say
so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; linux
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;extra&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;another&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(missing_name)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;:7:7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The caret is on line 7, which is where &lt;code&gt;print(missing_name)&lt;/code&gt; is written — not line 2, where it would
be if the four gated lines had been dropped.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A directive sits at the margin, column 1.&lt;/strong&gt; That is a rule and not a convention. sysl is
indentation-sensitive, and indentation is how the language reads block structure — so a gate written
&lt;em&gt;in&lt;/em&gt; that channel would look like it takes part in a nesting it has nothing to do with, when in fact
the line is gone before anything counts a column. At the margin it is visibly not part of the code’s
shape, which is what it is. It is also how C is written. What keeps a declaration’s &lt;code&gt;@test&lt;/code&gt; from ever
being mistaken for one of these is the &lt;strong&gt;sigil&lt;/strong&gt;, not the margin — an annotation on a &lt;code&gt;module&lt;/code&gt; header
sits at column 1 too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why lines and not a construct wrapping declarations.&lt;/strong&gt; Rust spells this &lt;code&gt;#[cfg]&lt;/code&gt;, an attribute on
an item, and can because Rust is brace-delimited: the attribute attaches without moving anything.
Here the equivalent would have to take an indented block, so adding or removing a platform gate would
reindent everything inside it — a one-line intent showing up as a whole-body diff. A flat marker
disturbs nothing.&lt;/p&gt;
&lt;h3 id=&quot;the-symbols-are-derived-from-the-target-and-the-set-is-closed&quot;&gt;The symbols are derived from the target, and the set is closed&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;kind&lt;/th&gt;&lt;th&gt;symbols&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;operating system&lt;/td&gt;&lt;td&gt;&lt;code&gt;macos&lt;/code&gt;, &lt;code&gt;linux&lt;/code&gt;, &lt;code&gt;windows&lt;/code&gt;, &lt;code&gt;freestanding&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;processor&lt;/td&gt;&lt;td&gt;&lt;code&gt;aarch64&lt;/code&gt;, &lt;code&gt;x86_64&lt;/code&gt;, &lt;code&gt;riscv64&lt;/code&gt;, &lt;code&gt;riscv32&lt;/code&gt;, &lt;code&gt;thumb&lt;/code&gt;, &lt;code&gt;x86&lt;/code&gt;, &lt;code&gt;wasm32&lt;/code&gt;, &lt;code&gt;craft&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;derived&lt;/td&gt;&lt;td&gt;&lt;code&gt;hosted&lt;/code&gt; (not &lt;code&gt;freestanding&lt;/code&gt;), &lt;code&gt;posix&lt;/code&gt; (&lt;code&gt;macos&lt;/code&gt; or &lt;code&gt;linux&lt;/code&gt;)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That is the whole vocabulary. There is &lt;strong&gt;no &lt;code&gt;#define&lt;/code&gt;&lt;/strong&gt;, nothing a project can add, and no dependence
on a project config. A condition is a symbol, &lt;code&gt;!&lt;/code&gt;, &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;, &lt;code&gt;||&lt;/code&gt;, and parentheses; &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; binds tighter
than &lt;code&gt;||&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;posix&lt;/code&gt; is a name for the commonest disjunction rather than a replacement for writing it — &lt;code&gt;#if linux || macos&lt;/code&gt; still says the same thing. Note that this &lt;code&gt;posix&lt;/code&gt; is not the &lt;em&gt;capability&lt;/em&gt; of the same name:
this one asks &lt;strong&gt;is this a POSIX system&lt;/strong&gt;, a fact about the machine settled by the target, where the
capability asks &lt;strong&gt;may this module use POSIX&lt;/strong&gt;, a permission a project grants and a &lt;code&gt;no posix&lt;/code&gt; clause
takes away. They agree today only because nothing denies anything yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A symbol nobody knows is an error, not false:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; darwin
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;darwin&apos; is not something a target says about itself — sysl knows aarch64, craft, freestanding, hosted, linux, macos, posix, riscv32, riscv64, thumb, wasm32, windows, x86, x86_64
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The set is closed, so a name outside it is a mistake rather than a fact this build happens not to
have — and a misspelling that read as &lt;em&gt;false&lt;/em&gt; would gate code out of the build with nothing said.
&lt;strong&gt;Silently missing code is the one failure this feature cannot be allowed to have, and it is the one
C has.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A target’s &lt;em&gt;name&lt;/em&gt; is not a symbol — it has a &lt;code&gt;-&lt;/code&gt; in it, which no identifier carries — and writing one
is told what to write instead, because otherwise the reader is told that &lt;code&gt;-&lt;/code&gt; is not an operator,
which is true and no help:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; aarch64-macos
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;aarch64-macos&apos; is a target&apos;s name rather than something a condition asks about — a condition asks about one fact of the machine at a time, so this is written &apos;aarch64 &amp;amp;&amp;amp; macos&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every condition is checked, in the branch being taken and the ones being skipped alike.&lt;/strong&gt; So a
misspelling in the Linux half is caught by a macOS build, which is where it would otherwise sit until
somebody built for Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;if&lt;/span&gt; linux
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;elif&lt;/span&gt; nosuchmachine
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;else&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;three&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-punctuation&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;endif&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;nosuchmachine&apos; is not something a target says about itself
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That refusal comes from a build whose &lt;code&gt;#if linux&lt;/code&gt; was already false and whose &lt;code&gt;#else&lt;/code&gt; is the branch
being taken. The condition on the way past was still read.&lt;/p&gt;
&lt;h3 id=&quot;what-is-given-up-and-what-is-not&quot;&gt;What is given up, and what is not&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;The inactive branch is never syntax-checked.&lt;/strong&gt; That is the price of gating text rather than trees,
it is C’s price too, and a Linux branch can therefore rot while the macOS build stays green. What
finds that is a build for each target — a thing to &lt;em&gt;run&lt;/em&gt;, not a thing to design around. The
conditions themselves are the part that is checked everywhere, and they are the part where a mistake
would otherwise be silent.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The gate runs before anything knows what a string or a comment is&lt;/strong&gt;, so a line that begins at the
margin with a directive word is a directive even inside a text block or a block comment. Recognizing
those would mean a second copy of the lexer’s rules about literals, in a place where the two could
drift with nothing to notice — a worse defect than this one. The margin rule is what keeps it rare: a
text block written anywhere but the top level is indented in the source, whatever its value turns out
to be.&lt;/p&gt;
&lt;h3 id=&quot;the-library-is-subject-to-it-too&quot;&gt;The library is subject to it too&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;library/sysl&lt;/code&gt; is sysl source, so it may gate on the machine like any other — which makes “the standard
module” a question with a target in it, and the library’s source is parsed once per target
accordingly.&lt;/p&gt;
&lt;p&gt;The one thing held fixed is that &lt;strong&gt;a name the compiler spells for itself is declared on every
target&lt;/strong&gt;. A library that gated &lt;code&gt;Option&lt;/code&gt; away for Windows would be a library nothing compiles against
there, so that is refused in a registry-wide check rather than at the first &lt;code&gt;?&lt;/code&gt; somebody writes.&lt;/p&gt;
&lt;p&gt;And &lt;strong&gt;an artifact records the target it was built for&lt;/strong&gt; and is refused by a build for another,
because the trees a library ships are now a per-target answer.&lt;/p&gt;
&lt;h2 id=&quot;what-is-deliberately-absent&quot;&gt;What is deliberately absent&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;absent&lt;/th&gt;&lt;th&gt;why&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;a general annotation mechanism&lt;/td&gt;&lt;td&gt;the set is closed: &lt;code&gt;@test&lt;/code&gt;, &lt;code&gt;@tailrec&lt;/code&gt;, &lt;code&gt;@pure&lt;/code&gt;, &lt;code&gt;@ghost&lt;/code&gt;, &lt;code&gt;@export&lt;/code&gt;, &lt;code&gt;@reads(...)&lt;/code&gt;, &lt;code&gt;@writes(...)&lt;/code&gt; and &lt;code&gt;@crossing(...)&lt;/code&gt; on a free function, &lt;code&gt;@packed&lt;/code&gt;, &lt;code&gt;@align(n)&lt;/code&gt; and &lt;code&gt;@export(&amp;quot;...&amp;quot;)&lt;/code&gt; on a struct, &lt;code&gt;@section(&amp;quot;...&amp;quot;)&lt;/code&gt; on a binding or a function, &lt;code&gt;@no_&amp;lt;capability&amp;gt;&lt;/code&gt;, &lt;code&gt;@requires&lt;/code&gt;, &lt;code&gt;@link&lt;/code&gt;, &lt;code&gt;@include&lt;/code&gt; and &lt;code&gt;@tests&lt;/code&gt; on a file, and &lt;code&gt;@assert&lt;/code&gt; on nothing at all. Each was designed and added on its own evidence; there is no way to write one the compiler does not already know&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;bitfield syntax&lt;/td&gt;&lt;td&gt;there is nothing to write: inside &lt;code&gt;@packed&lt;/code&gt; an &lt;code&gt;iN&lt;/code&gt; field already occupies exactly N bits, so a five-bit register field is &lt;code&gt;u5&lt;/code&gt; and needs no &lt;code&gt;: 5&lt;/code&gt; beside it. The open integer family does the work C’s declarator syntax was invented for&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;#define&lt;/code&gt;, or any project-supplied symbol&lt;/td&gt;&lt;td&gt;the &lt;code&gt;#if&lt;/code&gt; vocabulary is derived from the target and closed, which is what makes an unknown symbol an error rather than a false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;#if&lt;/code&gt; that asks about a capability&lt;/td&gt;&lt;td&gt;a condition asks what the &lt;em&gt;target&lt;/em&gt; says; what a project permits is a different question, left with the config that would define it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a test framework in the library&lt;/td&gt;&lt;td&gt;a test asserts in the language it is testing, and passes by returning&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a release mode that drops a check&lt;/td&gt;&lt;td&gt;see &lt;a href=&quot;/reference/errors/&quot;&gt;errors and contracts&lt;/a&gt; — every check is in every build&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;p&gt;That is the language. What ships beside it is the &lt;a href=&quot;/library/&quot;&gt;standard library&lt;/a&gt;, which is a section
of its own — nothing in it is a language feature, and every type in it is one a program could have
written.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Arrays and slices</title>
    <link href="https://sysl.sh/tour/arrays/"/>
    <id>https://sysl.sh/tour/arrays/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>One type for storage, one for a view of it — and every index checked.</summary>
    <content type="html">&lt;p&gt;sysl has two sequence types where a lot of languages have one, and the split is Go’s:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[N]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;fixed array&lt;/strong&gt;: &lt;code&gt;N&lt;/code&gt; elements, a value, no header, &lt;code&gt;N&lt;/code&gt; known while compiling&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;slice&lt;/strong&gt;: a view of elements someone owns — &lt;code&gt;{ owner, pointer, length }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;An array &lt;em&gt;is&lt;/em&gt; its elements, so copying one copies all of them. A slice &lt;em&gt;names&lt;/em&gt; elements that live
somewhere else. A function that only reads takes the view and stops caring where the bytes are.&lt;/p&gt;
&lt;p&gt;Both carry a length, so &lt;strong&gt;every index is checked&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;writing-one-down&quot;&gt;Writing one down&lt;/h2&gt;
&lt;p&gt;A literal fixes the length from how many elements it has:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; primes = [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, primes.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;third:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, primes[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;count: 4 third: 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;primes&lt;/code&gt; is a &lt;code&gt;[4]int&lt;/code&gt; — the count is part of the type, not a field of the value. &lt;code&gt;.len&lt;/code&gt; is a
property, so no parentheses, and on a fixed array it is a constant that costs nothing to read.&lt;/p&gt;
&lt;p&gt;A declaration with no initializer starts at the type’s zero value, which is what a scratch buffer
wants. A repeat &lt;code&gt;[value; count]&lt;/code&gt; fills every slot with one value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counters: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ones = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

counters[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;zeroed:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, counters[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;set:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, counters[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;repeat:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, ones.len, ones[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;zeroed: 0 set: 9
repeat: 5 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The zero-value form is not special to arrays — it is a &lt;code&gt;var&lt;/code&gt; with a type and no &lt;code&gt;=&lt;/code&gt;, and it means
“the zero of this type” for any type that has one. A type holding a &lt;code&gt;&amp;amp;T&lt;/code&gt; has no zero, since a
reference always points at something live, so that one asks you for an initializer.&lt;/p&gt;
&lt;h2 id=&quot;an-array-is-a-value&quot;&gt;An array is a value&lt;/h2&gt;
&lt;p&gt;Which means the thing the &lt;a href=&quot;/tour/structs/&quot;&gt;structs chapter&lt;/a&gt; said about &lt;code&gt;b = a&lt;/code&gt; is true here too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = a

b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;b:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a: 1 b: 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three elements were copied. That is fine for four integers and less fine for four thousand, which is
the reason the other type exists.&lt;/p&gt;
&lt;h2 id=&quot;a-slice-is-a-view&quot;&gt;A slice is a view&lt;/h2&gt;
&lt;p&gt;Subscript with a range instead of an index and you get a slice. It does not copy — it names the same
elements:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;50&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; middle = data[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

middle[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;view:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, middle.len, middle[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;original:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, data[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;view: 3 99
original: 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Writing through the view wrote through to the array, because there is only one set of elements.&lt;/p&gt;
&lt;p&gt;Both ends of the range are optional, and the two range operators keep the meanings they have
everywhere else in the language — &lt;code&gt;..&lt;/code&gt; includes its high end, &lt;code&gt;..&amp;lt;&lt;/code&gt; excludes it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; total += x

    total

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(data), &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(data[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(data[..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;sum&lt;/span&gt;(data[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;..]))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;15 9 3 9
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt; on its own is the whole thing: an array standing where a view is asked for &lt;strong&gt;is&lt;/strong&gt; a view of
itself, so the first call needs no subscript at all. The rest name part of it — &lt;code&gt;data[1..3]&lt;/code&gt; is
elements 1 through 3, &lt;code&gt;data[..&amp;lt;2]&lt;/code&gt; is the first two, and &lt;code&gt;data[3..]&lt;/code&gt; runs to the end. Written out,
the whole of it is &lt;code&gt;data[..]&lt;/code&gt;, which is what the position does for you. “The first &lt;code&gt;n&lt;/code&gt;“ is &lt;code&gt;xs[..&amp;lt;n]&lt;/code&gt;, which matches the
&lt;code&gt;for i in 0..&amp;lt;n&lt;/code&gt; that walks it — the two must agree, and that is why the inclusive &lt;code&gt;..&lt;/code&gt; is the one
that looks unusual rather than the one that is wrong.&lt;/p&gt;
&lt;p&gt;There is no &lt;code&gt;xs[lo..&amp;lt;]&lt;/code&gt;: “through the last” is not a question of including or excluding anything, so
the open form is &lt;code&gt;xs[lo..]&lt;/code&gt; and the other spelling is refused rather than quietly meaning the same.&lt;/p&gt;
&lt;h2 id=&quot;a-view-that-may-not-be-written&quot;&gt;A view that may not be written&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;[]const T&lt;/code&gt; is a slice whose elements may not be written &lt;strong&gt;through it&lt;/strong&gt;. It is the signature a
function that only reads should have:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(data)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;this element belongs to a &apos;[]const int&apos;, which views elements it may not write, so there is nothing to assign through. Elements you may write are elements of your own: copy them into a &apos;[]int&apos; first
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;const&lt;/code&gt; is a property of the &lt;em&gt;view&lt;/em&gt;, not of the element type — which is why it sits after the
brackets, and why a &lt;code&gt;[]T&lt;/code&gt; is accepted anywhere a &lt;code&gt;[]const T&lt;/code&gt; is wanted but never the other way
round. Giving up the ability to write is a promise the caller can always make; inventing one is what
the type exists to stop.&lt;/p&gt;
&lt;h2 id=&quot;iterating&quot;&gt;Iterating&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;for x in xs&lt;/code&gt; binds a &lt;strong&gt;copy&lt;/strong&gt; of each element, which is what value semantics mean. To change
elements, walk the indices:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;saw:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, x)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;xs.len
    xs[i] *= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scaled:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;saw: 1
saw: 2
saw: 3
scaled: 10 20 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The loop evaluates its sequence once, so a slice written directly in the header lives for the whole
loop rather than being rebuilt each step.&lt;/p&gt;
&lt;h2 id=&quot;a-length-worked-out-while-running&quot;&gt;A length worked out while running&lt;/h2&gt;
&lt;p&gt;Every form so far fixes its length in the type, and that is exactly what a program reading a file
cannot do — the size is in the header, and the header is read by the code that needs the buffer.&lt;/p&gt;
&lt;p&gt;A length that is not in the type is what &lt;code&gt;[]T&lt;/code&gt; already is, so this needs no new spelling. The
declared type decides which reading you get:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;squares&lt;/span&gt;(n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; n]

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;n &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; xs[i] = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(i) * &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(i)

    xs

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; s = &lt;span class=&quot;hl-function&quot;&gt;squares&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;len:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;last:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, s[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;len: 5 last: 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under a &lt;code&gt;[N]T&lt;/code&gt; the count must be constant; under a &lt;code&gt;[]T&lt;/code&gt; it can be any expression, and the storage
that gets made belongs to the view. That is the whole mechanism — a slice’s owner word is an
ordinary counted reference, so storage a function makes this way can be &lt;strong&gt;returned&lt;/strong&gt;, and a decoder
that learns its size from what it is decoding does not have to ask its caller to size a buffer whose
size is in a header the caller has not read.&lt;/p&gt;
&lt;h2 id=&quot;growing-one&quot;&gt;Growing one&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Buf[T]&lt;/code&gt; is the growable sequence, and the interesting thing about it is that it is &lt;strong&gt;ordinary sysl
in the library&lt;/strong&gt; — a &lt;code&gt;[]T&lt;/code&gt; for the storage, a count of how much is live, and methods. The section
above is what makes that possible.&lt;/p&gt;
&lt;p&gt;Nothing in the language reaches it, so a program that wants one asks:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(i * i)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;len:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;first:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;cap:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, b.&lt;span class=&quot;hl-function&quot;&gt;cap&lt;/span&gt;() &amp;gt;= b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())

b.&lt;span class=&quot;hl-function&quot;&gt;pop&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Some&lt;/span&gt;(v) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;popped:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, v)
    &lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt; -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;len: 4 first: 1 cap: true
popped: 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two details worth catching. &lt;code&gt;b.len()&lt;/code&gt; has parentheses where &lt;code&gt;xs.len&lt;/code&gt; did not: the built-in length is
a property of a type the compiler knows, while &lt;code&gt;Buf&lt;/code&gt;‘s is an ordinary method. And &lt;code&gt;b[0]&lt;/code&gt; works
because &lt;code&gt;Buf&lt;/code&gt; implements the &lt;code&gt;Index&lt;/code&gt; trait — the same syntax, reaching a call rather than an address.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pop&lt;/code&gt; returns an &lt;code&gt;Option&lt;/code&gt; because taking from an empty buffer is a question a caller asks on purpose,
while &lt;code&gt;b[i]&lt;/code&gt; past the end panics, because that is a mistake in the program rather than a value it
meant to handle.&lt;/p&gt;
&lt;p&gt;Handing the elements to something that takes a slice is &lt;code&gt;view()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t += x

    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(i)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;total:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;total: 15
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-a-view-keeps-alive&quot;&gt;What a view keeps alive&lt;/h2&gt;
&lt;p&gt;Taking a slice &lt;strong&gt;retains whatever owns the elements&lt;/strong&gt;, and dropping the slice releases it. So a view
cannot dangle: the storage it names is alive for exactly as long as the view is.&lt;/p&gt;
&lt;p&gt;That holds even across a growth. A &lt;code&gt;push&lt;/code&gt; that runs out of room allocates fresh storage and copies —
and a view taken before that keeps the &lt;em&gt;old&lt;/em&gt; storage alive and goes on showing what it was made
from. It does not become invalid, which is the half of Go’s behaviour sysl could not reproduce even
if it wanted to. What it does not do is grow with the buffer; take the view again to see more.&lt;/p&gt;
&lt;p&gt;Where there is nothing to keep alive — a view of a string literal, or of a region behind a &lt;code&gt;*T&lt;/code&gt; —
the owner word is simply null and the counting compiles away.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/tour/strings/&quot;&gt;strings&lt;/a&gt; — the same three words, with a guarantee added and an operation
taken away.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Arrays and slices</title>
    <link href="https://sysl.sh/reference/arrays/"/>
    <id>https://sysl.sh/reference/arrays/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>Two sequence types — storage and a view of it — and the rules for writing one down, indexing it, slicing it, and knowing what it keeps alive.</summary>
    <content type="html">&lt;p&gt;sysl has two sequence types where many languages have one:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;type&lt;/th&gt;&lt;th&gt;what it is&lt;/th&gt;&lt;th&gt;shape&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[N]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;fixed array&lt;/strong&gt;: &lt;code&gt;N&lt;/code&gt; elements of &lt;code&gt;T&lt;/code&gt;, a value, no header&lt;/td&gt;&lt;td&gt;the elements, and nothing else&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;slice&lt;/strong&gt;: a view of elements someone owns&lt;/td&gt;&lt;td&gt;&lt;code&gt;{ owner, ptr, len }&lt;/code&gt; — three words&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[]const T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a slice that may be read and not written&lt;/td&gt;&lt;td&gt;the same three words, with a bit&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The split is Go’s, and for Go’s reason: one type for storage, one for a view, so a function that only
reads takes the view and never has to care where the bytes live. Both carry a length, so &lt;strong&gt;every
index is checked&lt;/strong&gt; — which is what makes them the thing to reach for in place of a &lt;code&gt;*T&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;An array &lt;strong&gt;is&lt;/strong&gt; its elements. A slice &lt;strong&gt;names&lt;/strong&gt; elements that live somewhere else. Everything on
this page follows from that one sentence, and a call is where it shows most plainly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scribble&lt;/span&gt;(a: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;
    a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;set_first&lt;/span&gt;(xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;scribble&lt;/span&gt;(a), a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;set_first&lt;/span&gt;(a)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;99 1
99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;scribble&lt;/code&gt; was handed four integers and wrote on its own copy of them. &lt;code&gt;set_first&lt;/code&gt; was handed three
words naming the caller’s four integers, and wrote on those. Neither function said anything about
copying; the types did.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;string&lt;/code&gt; is the second row of that table with one thing added and one taken away — its bytes are
guaranteed well-formed UTF-8, and nothing may write through it. Everything here about indexing,
slicing, length and ownership is therefore true of a string as well, and
&lt;a href=&quot;/reference/strings/&quot;&gt;strings&lt;/a&gt; is where the two differences are.&lt;/p&gt;
&lt;p&gt;A third shape sits beside these and is deliberately not on that table: &lt;code&gt;&amp;lt;N&amp;gt;T&lt;/code&gt;, a
&lt;a href=&quot;/reference/vectors/&quot;&gt;vector&lt;/a&gt;, holds the same values an &lt;code&gt;[N]T&lt;/code&gt; holds and is not storage at all. It
lives in a register and its operators work on every lane at once, so &lt;code&gt;a + b&lt;/code&gt; on two &lt;code&gt;&amp;lt;4&amp;gt;f32&lt;/code&gt; is one
instruction doing four additions. Everything on &lt;em&gt;this&lt;/em&gt; page — indexing checked while the program
runs, slicing, ownership — is about things with an address, and a vector has none.&lt;/p&gt;
&lt;p&gt;An array and a slice are how a vector reaches memory, though, and the two methods that move a run of
elements between them are &lt;em&gt;theirs&lt;/em&gt;: &lt;code&gt;xs.load(i)&lt;/code&gt; reads the run starting at element &lt;code&gt;i&lt;/code&gt; into a
vector, and &lt;code&gt;xs.store(i, v)&lt;/code&gt; writes one back. Both are bounds-checked like a subscript, and checked
as a whole run — see &lt;a href=&quot;/reference/vectors/&quot;&gt;vectors&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;writing-one-down&quot;&gt;Writing one down&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A literal&lt;/strong&gt; lists its elements, and the count becomes part of the type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; primes = [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; row: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;f64&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0.0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(primes.len, primes[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], row[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;4 5 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A declaration with no initializer&lt;/strong&gt; starts at the type’s zero value. &lt;strong&gt;A repeat&lt;/strong&gt; &lt;code&gt;[value; count]&lt;/code&gt;
fills every element with one value, and is the form for an element type whose zero is not the wanted
starting point — or which has no zero at all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;6&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; counters: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ones = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; grid = [[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; window = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; n]

grid[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;][&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counters[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], ones[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;], grid[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;][&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], grid[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;][&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], window.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 1 5 0 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three rules govern the repeat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The count is a compile-time constant&lt;/strong&gt; — a literal, a &lt;code&gt;const&lt;/code&gt; naming one, or an expression over
those — for the same reason an array bound is one: it &lt;em&gt;is&lt;/em&gt; the bound, and the type is not known
without it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; k: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; buf: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; k]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an array&apos;s repeat count must be a constant, since it is the array&apos;s bound
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The diagnostic goes on to name the way out, and it is the section below: a count computed while
running makes &lt;em&gt;storage&lt;/em&gt; rather than an array, and storage is written where a &lt;code&gt;[]T&lt;/code&gt; is expected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The element type comes from the value&lt;/strong&gt;, or from the context where the value is a bare literal.
And &lt;strong&gt;the value is evaluated exactly once&lt;/strong&gt;, then copied into every element:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;
    n: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Counter&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(c: &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    c.n = c.n + &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-type&quot;&gt;Counter&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; three = [&lt;span class=&quot;hl-function&quot;&gt;bump&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;c); &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(three[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], three[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], three[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], c.n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 7 7 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One call, three elements. That is what makes the form a construction rather than shorthand for
writing the value out &lt;code&gt;count&lt;/code&gt; times — and where the element type holds a reference, each of those
copies is a share of its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An empty literal&lt;/strong&gt; has no element type of its own and takes one from the context, exactly as a
bare &lt;code&gt;None&lt;/code&gt; does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; empty: [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = []

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(empty.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-zero-value-form-is-not-about-arrays&quot;&gt;The zero-value form is not about arrays&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;var counters: [4]int&lt;/code&gt; is a &lt;code&gt;var&lt;/code&gt; with a declared type and no &lt;code&gt;=&lt;/code&gt;, and it means “the zero value of
this type” for &lt;strong&gt;any&lt;/strong&gt; type that has one. What matters here is which types do not: a type containing
a &lt;code&gt;&amp;amp;T&lt;/code&gt; has no zero value, because a reference always points at something live.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
    next: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; Node&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; n: &lt;span class=&quot;hl-type&quot;&gt;Node&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;Node has no zero value, so &apos;n&apos; needs an initial value
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That keeps the non-null guarantee of &lt;a href=&quot;/reference/memory/&quot;&gt;memory&lt;/a&gt; true with no special case for
arrays, and it is why &lt;code&gt;[Empty; 16]&lt;/code&gt; is the form an array of enum values takes.&lt;/p&gt;
&lt;h3 id=&quot;a-table-written-at-the-top-of-a-file&quot;&gt;A table written at the top of a file&lt;/h3&gt;
&lt;p&gt;The same three forms written outside a function are a &lt;code&gt;val&lt;/code&gt;, which is what a table somebody else
fixed wants:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; order: [&lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;17&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t += x

    t

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(order[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(order[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]), order.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;18 35 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The difference from a &lt;code&gt;const&lt;/code&gt; is an &lt;strong&gt;address&lt;/strong&gt;. A constant is folded into every use and has none, so
it can size an array but cannot &lt;em&gt;be&lt;/em&gt; one; a &lt;code&gt;val&lt;/code&gt; is storage, so it may be indexed at a position only
known while running, sliced, and iterated. What it may not be is written, and slicing one therefore
yields a &lt;code&gt;[]const T&lt;/code&gt; — which is the whole of why a &lt;code&gt;val&lt;/code&gt; is sliceable at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;val&lt;/code&gt; may hold a value the program had to build.&lt;/strong&gt; Storage that exists for the whole run is never
let go of, so the count it takes is never given back — which is what a static is, and is why this is
admitted rather than refused:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;squares&lt;/span&gt;(k: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; k]

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;k &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; xs[i] = &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(i) * &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;(i)

    xs

&lt;span class=&quot;hl-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; table: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hl-function&quot;&gt;squares&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(table[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], table[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], table.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 9 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the value &lt;strong&gt;is&lt;/strong&gt; still decides where the storage gets filled. A string literal’s bytes are a
constant in the object file and its owner word is null, so a table of them is storage all the way
down and needs no code to run first — which is what lets a module with no allocator hold one, exactly
as &lt;code&gt;order&lt;/code&gt; above is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; names: [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; = [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(names[i], names[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;].len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;gamma 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the case a &lt;code&gt;const&lt;/code&gt; could never have served: a constant is folded into its uses and has no
address, so there is nothing to index at &lt;code&gt;i&lt;/code&gt;. A raw pointer may be held for the same reason a
literal may — it counts nothing, so there is no release to write.&lt;/p&gt;
&lt;h2 id=&quot;storage-sized-while-running&quot;&gt;Storage sized while running&lt;/h2&gt;
&lt;p&gt;Every form so far fixes its length in the type, and that is the one thing a program reading a file
cannot do: the size is in the header, and the header is read by the code that needs the buffer.&lt;/p&gt;
&lt;p&gt;A length that is not in the type is precisely what a &lt;code&gt;[]T&lt;/code&gt; is, so nothing here needs a new spelling.
&lt;strong&gt;The expected type decides&lt;/strong&gt; which reading a literal or a repeat gets:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;decode&lt;/span&gt;(header: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;) -&amp;gt; []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; out: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;(header[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])]

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;out.len &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; out[i] = header[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] + &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;(i)

    out

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; frame: [&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; body = &lt;span class=&quot;hl-function&quot;&gt;decode&lt;/span&gt;(frame)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(body.len, body[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], body[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 10 12
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Under a &lt;code&gt;[N]T&lt;/code&gt; a non-constant count is the error above; under a &lt;code&gt;[]T&lt;/code&gt; a constant one is simply the
easy case. The three spellings side by side:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var buf: [64]u8 = [0; 64]     // an array — the count is in the type, so it is constant
var raw: []u8   = [0; n]      // a view of fresh storage — n is any expression
var xs:  []int  = [1, 2, 3]   // likewise, with the elements written out
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The storage is the view’s own.&lt;/strong&gt; The &lt;code&gt;owner&lt;/code&gt; word is an ordinary counted reference to the elements,
so everything under &lt;a href=&quot;#what-a-view-keeps-alive&quot;&gt;ownership&lt;/a&gt; is already true of it: a sub-slice retains
it, the last view to go releases it, and the elements are destroyed before the bytes go back. Nothing
about indexing, slicing, &lt;code&gt;.len&lt;/code&gt; or iterating tells such a view apart from one over somebody else’s
elements — which is the point, and why a second type would have been a second type for nothing.&lt;/p&gt;
&lt;p&gt;What it adds is &lt;strong&gt;leaving the frame&lt;/strong&gt;, which is what the program above does: a decoder that learns
its size from what it is decoding returns a result, instead of asking its caller to size a buffer
whose size is in a header the caller has not read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three things are checked&lt;/strong&gt;, because a computed length is where arithmetic goes wrong. The count is
widened to the address width and read unsigned, so a negative one arrives as a very large one; the byte size is
computed with an overflow-checked multiply and add, so a count that would wrap cannot allocate a
small buffer that is then written past; and a failed allocation traps rather than handing back a null
the elements are then stored through.&lt;/p&gt;
&lt;h2 id=&quot;indexing&quot;&gt;Indexing&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a[i]&lt;/code&gt; reads the element, and it is a &lt;strong&gt;place&lt;/strong&gt; — so &lt;code&gt;a[i] = v&lt;/code&gt;, &lt;code&gt;a[i] += 1&lt;/code&gt;, &lt;code&gt;a[i]++&lt;/code&gt; and &lt;code&gt;&amp;amp;a[i]&lt;/code&gt;
all follow from the same machinery assignment and address-of use everywhere else, with nothing said
about arrays in particular:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;]

a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] += &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;
a[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;]++

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;a[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], a[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], a[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;15 21 99
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The index may be any integer type.&lt;/strong&gt; Requiring &lt;code&gt;usize&lt;/code&gt; would make &lt;code&gt;for i in 0..&amp;lt;10 do a[i] …&lt;/code&gt; need
a conversion for no benefit, since the check has to happen anyway:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; narrow: &lt;span class=&quot;hl-type&quot;&gt;i8&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; unsigned: &lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sized: &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt; = &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[narrow], a[unsigned], a[sized])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;20 30 40
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The index is widened to &lt;strong&gt;the address width&lt;/strong&gt; and compared &lt;strong&gt;unsigned&lt;/strong&gt; against the length. That is
one comparison rather than two, and it rejects a negative index as a very large one — the trick a
bounds check has always used. (It is the address width rather than a flat sixty-four because what it
is compared against is a length, and a length is a &lt;code&gt;usize&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;An index already &lt;em&gt;wider&lt;/em&gt; than an address — a &lt;code&gt;u128&lt;/code&gt; anywhere, or an ordinary &lt;code&gt;int&lt;/code&gt; on a 16-bit
machine — is asked whether it fits and then narrowed, in that order. Nothing holds more than &lt;code&gt;usize&lt;/code&gt;
elements, so a value that does not fit names no element and traps like any other index out of range;
testing before narrowing is what stops &lt;code&gt;2^64 + 5&lt;/code&gt; arriving as &lt;code&gt;5&lt;/code&gt; and passing on a six-element
array. So &lt;code&gt;for i in 0..&amp;lt;n do a[i] …&lt;/code&gt; needs no conversion on any machine, which is the whole point of
the index being any integer type.&lt;/p&gt;
&lt;h3 id=&quot;a-failed-check-traps&quot;&gt;A failed check traps&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt; = -&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[i])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The process stops at the index. This is the same runtime-safety category as the partial &lt;code&gt;char(u)&lt;/code&gt;
conversion and a mid-character string slice, and it gets the same treatment: a trap instruction, no
message, and no unwinding. Output already written but not yet flushed goes with it — so &lt;code&gt;before&lt;/code&gt;
does not appear, which is worth knowing before reading a truncated log as evidence of where a program
got to.&lt;/p&gt;
&lt;h3 id=&quot;a-raw-pointer-is-indexed-anyway&quot;&gt;A raw pointer is indexed anyway&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;*T&lt;/code&gt; is the one receiver with nothing to check against, and it is subscripted regardless — that is
C’s subscript, the address arithmetic, unchecked. Slicing one needs the end written, because nothing
in the type can supply it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t += x

    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; back = [&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;back[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(p[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], &lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(p[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;8 15
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The resulting view owns nothing, since a &lt;code&gt;*T&lt;/code&gt; region has nothing to keep alive. &lt;strong&gt;The check is a
property of the type, not of the syntax&lt;/strong&gt;: a &lt;code&gt;*[N]T&lt;/code&gt;, whose length is in its type, keeps every check
an array has. Reaching for a slice is how a program stays safe; reaching for a pointer is how it
talks to hardware and to C, and the language supplies both rather than withholding the second.&lt;/p&gt;
&lt;h3 id=&quot;a-type-with-no-elements-of-its-own-is-indexed-through-a-trait&quot;&gt;A type with no elements of its own is indexed through a trait&lt;/h3&gt;
&lt;p&gt;Everything above is about the built-in subscript rather than about &lt;code&gt;[]&lt;/code&gt; as a token. A user type — the
library’s &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;Buf[T]&lt;/code&gt;&lt;/a&gt;, a lookup table, anything a program writes — implements &lt;code&gt;Index&lt;/code&gt;
and is read with the same syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;9 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two differences follow from its being a call rather than a walk to an address. The index is whatever
the implementation takes, and need not be an integer. And the element is &lt;strong&gt;not a place&lt;/strong&gt;, so &lt;code&gt;b[i] = v&lt;/code&gt; reaches a second trait’s method and the compound forms are refused outright:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)

b[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] += &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;would evaluate the receiver and the index twice — write it out as &apos;b[i] = b[i] + …&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note also that &lt;code&gt;b.len()&lt;/code&gt; has parentheses where &lt;code&gt;a.len&lt;/code&gt; does not: the built-in length is a property of
a type the compiler knows, and &lt;code&gt;Buf&lt;/code&gt;‘s is an ordinary method. Nothing a program writes competes with
the built-in subscript — an array, a slice and a string are indexed by the compiler.&lt;/p&gt;
&lt;h2 id=&quot;slicing&quot;&gt;Slicing&lt;/h2&gt;
&lt;p&gt;A slice expression is an index whose subscript is a range, and the two range operators keep the
meanings they have &lt;a href=&quot;/reference/expressions/&quot;&gt;everywhere else&lt;/a&gt;: &lt;code&gt;..&lt;/code&gt; includes its high end, &lt;code&gt;..&amp;lt;&lt;/code&gt;
excludes it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;].len, d[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;].len, d[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..].len, d[..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].len, d[..].len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 2 3 2 5
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inclusive &lt;code&gt;..&lt;/code&gt; is the odd one against C-family habit, and the alternative is worse:
&lt;code&gt;for i in 0..&amp;lt;n&lt;/code&gt; and &lt;code&gt;a[0..&amp;lt;n]&lt;/code&gt; &lt;strong&gt;must&lt;/strong&gt; mean the same thing, and a language that has already chosen
two range operators does not get to give them different meanings in a subscript. So “the first &lt;code&gt;n&lt;/code&gt;“
is &lt;code&gt;a[..&amp;lt;n]&lt;/code&gt;, matching the loop that walks it.&lt;/p&gt;
&lt;p&gt;Both ends are optional: an omitted low end is 0, an omitted high end is the last element. Because
“through the last” is not a question of including or excluding anything, only one spelling of the
open-ended form exists:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = a[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;an open-ended slice is written &apos;a[lo..]&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The check is on the half-open interval the slice ends up naming.&lt;/strong&gt; With &lt;code&gt;s&lt;/code&gt; the first index and &lt;code&gt;e&lt;/code&gt;
one past the last, &lt;code&gt;s &amp;lt;= e&lt;/code&gt; and &lt;code&gt;e &amp;lt;= len&lt;/code&gt; must both hold, and the inclusive form additionally
requires that its named high element exist. An empty slice is legal, including at the very end:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; d = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d[d.len..].len, d[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;..&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;].len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What can be sliced:&lt;/strong&gt; a fixed array, a slice, or an array reached through a &lt;code&gt;&amp;amp;[N]T&lt;/code&gt; or a &lt;code&gt;*[N]T&lt;/code&gt; —
one-level auto-deref applies to a subscript as it does to field selection, so the expression reads
the same whether the name is the array or a reference to it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; t = &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; t += x

    t

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; boxed: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;[&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(boxed), boxed[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], boxed.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 3 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That call says &lt;code&gt;total(boxed)&lt;/code&gt; rather than &lt;code&gt;total(boxed)&lt;/code&gt;, which is the next section.&lt;/p&gt;
&lt;h2 id=&quot;an-array-where-a-view-is-asked-for&quot;&gt;An array where a view is asked for&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;[N]T&lt;/code&gt; standing where a &lt;code&gt;[]T&lt;/code&gt; is wanted is &lt;code&gt;a[..]&lt;/code&gt;, written by the position instead of by hand.&lt;/strong&gt;
An array is the one value that already knows both halves a view is made of — where the elements are,
and how many — so nothing is taken on trust and no bound is guessed.&lt;/p&gt;
&lt;p&gt;It matters most where a whole API is caller-supplied storage, which is how anything freestanding is
written: the caller lends, the callee fills, and nobody allocates.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;fill&lt;/span&gt;(s: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;s.len &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; s[i] = v

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;fill&lt;/span&gt;(a, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], a[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;], a.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;7 7 4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It happens at every position that asks for a view rather than merely requiring one — an argument, a
&lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt; with the view’s type written on it, a &lt;code&gt;return&lt;/code&gt;, a parameter’s default — and a &lt;code&gt;&amp;amp;[N]T&lt;/code&gt;
converts on the same terms, with the reference as what the view is taken over.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What it does not do is change the storage’s own terms.&lt;/strong&gt; A view of a &lt;code&gt;val&lt;/code&gt; array is a &lt;code&gt;[]const T&lt;/code&gt;,
exactly as &lt;code&gt;a[..]&lt;/code&gt; would give, so a &lt;code&gt;val&lt;/code&gt; array reaching a &lt;code&gt;[]T&lt;/code&gt; is refused and told which half is
missing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;fill&lt;/span&gt;(s: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;, v: &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;s.len &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; s[i] = v

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;fill&lt;/span&gt;(a, &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is a licence to write them — so the one does not become the other
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;&amp;amp;sync [N]T&lt;/code&gt; does not convert either, for the reason it cannot be sliced. And a &lt;code&gt;*[N]T&lt;/code&gt; is left
out on purpose: the raw-pointer tier is written out where it is used, and a view of pointed-at
storage taken silently is the one case where nothing in the type says the elements are really there.&lt;/p&gt;
&lt;h2 id=&quot;const-t-a-view-that-may-not-be-written&quot;&gt;&lt;code&gt;[]const T&lt;/code&gt; — a view that may not be written&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;const&lt;/code&gt; sits after the brackets, where &lt;code&gt;sync&lt;/code&gt; sits after the &lt;code&gt;&amp;amp;&lt;/code&gt;, and for the same reason: it is
a property of the &lt;strong&gt;view&lt;/strong&gt;, not of the element type. It is the signature a function that only reads
should have.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;)
    xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;99&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; data = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;scale&lt;/span&gt;(data)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;which views elements it may not write, so there is nothing to assign through
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same diagnostic answers &lt;code&gt;xs[i] += 1&lt;/code&gt; and &lt;code&gt;xs[i]++&lt;/code&gt;, and finishes by naming the way out: elements
you may write are elements of your own, so copy them into a &lt;code&gt;[]T&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is one type with a bit, not two types.&lt;/strong&gt; Both forms are the same three words, reach through the
same instructions, and keep the same thing alive; what the bit changes is only what may be &lt;em&gt;done&lt;/em&gt;
with the view. So a &lt;code&gt;[]T&lt;/code&gt; is accepted wherever a &lt;code&gt;[]const T&lt;/code&gt; is wanted — and never the other way
round:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;writes&lt;/span&gt;(xs: []&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;] = &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;
    xs.len

&lt;span class=&quot;hl-function&quot;&gt;hand_over&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;writes&lt;/span&gt;(xs)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;is a licence to write them — so the one does not become the other
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Giving up the ability to write is a promise the caller can always make; inventing one is the whole of
what the type exists to stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What produces one.&lt;/strong&gt; Slicing a &lt;code&gt;val&lt;/code&gt;, since read-only storage gives a read-only view — and so is
a &lt;code&gt;val&lt;/code&gt; array standing where a view is asked for, which is the same rule reached without the
brackets. &lt;code&gt;s.bytes&lt;/code&gt;, whose elements are a string’s own and may be a literal’s. Re-slicing one,
because a bit a second subscript dropped would make &lt;code&gt;xs[..]&lt;/code&gt; the way around &lt;code&gt;xs&lt;/code&gt;. And a buffer
literal written where one is wanted, since storage an expression makes has no other holder to
disagree with it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;readonly&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;usize&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; again = xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..]
    again.len

&lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(xs: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; p = &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
    &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;p

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;readonly&lt;/span&gt;(a), &lt;span class=&quot;hl-function&quot;&gt;first&lt;/span&gt;(a))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What it does not refuse is &lt;code&gt;&amp;amp;&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;&amp;amp;xs[0]&lt;/code&gt; is a &lt;code&gt;*T&lt;/code&gt; the moment it is written, which is the tier
where the guarantees stop, and it is how a view reaches a C function taking a pointer and a length.
The library’s own &lt;code&gt;find_byte&lt;/code&gt; is &lt;code&gt;memchr&lt;/code&gt; over exactly this. A read-only view that could not yield an
address could not do the job it was added for. This is &lt;em&gt;not&lt;/em&gt; the rule for a &lt;code&gt;val&lt;/code&gt; itself, where
&lt;code&gt;&amp;amp;k[0]&lt;/code&gt; is refused: a &lt;code&gt;val&lt;/code&gt; is storage whose promise is kept where it was made, and a view is a value
whose promise is about writing through it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;[N]const T&lt;/code&gt; is not a type.&lt;/strong&gt; An array is storage rather than a view of one, and storage written
once is what &lt;code&gt;val&lt;/code&gt; declares:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;frozen&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; table: [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    table[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;const&apos; says a view refuses writes, and an array is storage rather than a view of one
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What a view does not record&lt;/strong&gt; is whose elements these are, whether they outlive the program, and
whether their owner’s count is atomic. Those are properties of the &lt;em&gt;owner&lt;/em&gt;, and a view can only
report on them — which is what the &lt;a href=&quot;#what-is-still-refused&quot;&gt;refusal below&lt;/a&gt; is about.&lt;/p&gt;
&lt;h2 id=&quot;length&quot;&gt;Length&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a.len&lt;/code&gt; is the number of elements, as a &lt;code&gt;usize&lt;/code&gt;. On a &lt;code&gt;[N]T&lt;/code&gt; it is the constant &lt;code&gt;N&lt;/code&gt; and costs
nothing; on a &lt;code&gt;[]T&lt;/code&gt; it is the third word.&lt;/p&gt;
&lt;p&gt;It is a &lt;strong&gt;property&lt;/strong&gt; — a member read without parentheses — because a length is a projection of what
is already there rather than a computation over it. On the built-in array and slice types it is
compiler-provided, so &lt;code&gt;a.len&lt;/code&gt; reads the same whether &lt;code&gt;a&lt;/code&gt; is a fixed array whose length is a constant
or a slice whose length is a word it carries.&lt;/p&gt;
&lt;h2 id=&quot;iterating&quot;&gt;Iterating&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; xs = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;]

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; xs
    x = x * &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;xs.len
    xs[i] *= &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;10 20 30
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;for x in seq&lt;/code&gt; over an array or a slice binds a &lt;strong&gt;copy&lt;/strong&gt; of each element, which is what value
semantics mean — the first loop above multiplies three copies and throws them away. Changing the
sequence goes through the index form. The loop evaluates its sequence once, so a slice written
directly in the header lives for the whole loop rather than being rebuilt each step.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage is walked by index, and that is why a container is not an iterator.&lt;/strong&gt; A &lt;code&gt;for&lt;/code&gt; also accepts
a cursor — a value implementing &lt;code&gt;Iterate&lt;/code&gt; — but no built-in sequence implements it, and &lt;code&gt;Buf&lt;/code&gt;
deliberately does not: &lt;code&gt;for x in b.view()&lt;/code&gt; reads elements already sitting in memory, which costs an
index where a cursor would cost a call apiece. The protocol is for sequences whose elements have to
be &lt;em&gt;computed&lt;/em&gt;, which a container’s never are.&lt;/p&gt;
&lt;h2 id=&quot;what-a-view-keeps-alive&quot;&gt;What a view keeps alive&lt;/h2&gt;
&lt;p&gt;Taking a slice &lt;strong&gt;retains the owner&lt;/strong&gt;; dropping one releases it. That is what makes “a slice never
dangles” a fact rather than a hope, and it holds across a reallocation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.buf.{&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;, buf}

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;Buf&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;] = &lt;span class=&quot;hl-function&quot;&gt;buf&lt;/span&gt;()

b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)
b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = b.&lt;span class=&quot;hl-function&quot;&gt;view&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;..&amp;lt;&lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;do&lt;/span&gt; b.&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(i)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(v.len, v[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], b.&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2 1 102
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pushes moved the elements to fresh storage. The view made before the move keeps the &lt;strong&gt;old&lt;/strong&gt;
storage alive and goes on showing what it was made from — it does not become invalid, which is the
half of Go’s behaviour sysl could not have reproduced even if it had wanted to. What it does not do
is grow with the buffer: it is a view of some elements and it has the length it was made with. Take
it again to see more.&lt;/p&gt;
&lt;p&gt;Two consequences for how this is implemented:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The owner word is null&lt;/strong&gt; whenever there is nothing to keep alive — a view of a string literal, of
static storage, or of a &lt;code&gt;*T&lt;/code&gt; region — so retain and release on a slice must tolerate null. The
&lt;code&gt;&amp;amp;T&lt;/code&gt; path does not pay for that check: a reference is non-null by construction, so nullability is
the slice’s problem alone and gets its own pair of runtime helpers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Release cannot be per payload type.&lt;/strong&gt; A &lt;code&gt;[]u8&lt;/code&gt; may view a 64-byte buffer today and a 4096-byte
one tomorrow, so the static type of the slice does not name the type of the object its owner points
at. Giving back a count is therefore type-erased, through the deallocation hook every ARC object
carries — which is why releasing a slice’s owner is the same instruction sequence as releasing any
other reference, with no static type in sight.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A view that would outlive the array it was made from does not fail: the array is &lt;strong&gt;promoted&lt;/strong&gt; to a
buffer instead, so a program that means to return one writes the ordinary &lt;code&gt;var buf: [64]u8&lt;/code&gt; and says
nothing. &lt;a href=&quot;/reference/memory/#escape-analysis&quot;&gt;Memory&lt;/a&gt; is where that is settled, along with what is
still refused — storage the body did not declare.&lt;/p&gt;
&lt;h2 id=&quot;growing-one&quot;&gt;Growing one&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Buf[T]&lt;/code&gt; is the growable array, and it is &lt;strong&gt;ordinary sysl in the library&lt;/strong&gt; rather than a type the
compiler knows: a &lt;code&gt;[]T&lt;/code&gt; field for the storage, a count of how much of it is live, and the methods
over them. That it can be written at all is what the section on storage sized while running bought —
a container does not need a &lt;a href=&quot;/reference/memory/&quot;&gt;destructor&lt;/a&gt; if its storage is a value that already
has one, which the &lt;code&gt;[]T&lt;/code&gt; field is.&lt;/p&gt;
&lt;p&gt;It lives in &lt;a href=&quot;/library/buf/&quot;&gt;&lt;code&gt;sysl.buf&lt;/code&gt;&lt;/a&gt;, which is where the surface is documented. Nothing in the
language reaches it: an array literal makes an array or a slice, and a &lt;code&gt;for&lt;/code&gt; walks whatever
implements &lt;code&gt;Iterate&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;How a push is seen by another name for the same buffer is not a question this language has to answer,
because it is already answered by how the buffer is held:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;var p: &amp;amp;Buf[int] = buf()
var q = p                   // one buffer, two names: q sees every push through p
var c = *p                  // a copy, because copying a struct is what that means
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go’s confusion — two slices that agree until one of them grows — comes from having one representation
and therefore one behaviour. Held by reference, a &lt;code&gt;Buf&lt;/code&gt; behaves as a &lt;code&gt;&amp;amp;T&lt;/code&gt; behaves; held by value it
is a value. Neither is a rule about growable arrays.&lt;/p&gt;
&lt;h2 id=&quot;what-is-still-refused&quot;&gt;What is still refused&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;&amp;amp;sync&lt;/code&gt; array cannot be sliced.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; boxed: &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;sync [&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]&lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; v = boxed[..]&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a slice does not record whether its owner&apos;s count is atomic
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the one place where the read-only bit’s existence does not help, and the reason is the
asymmetry between the two properties. A &lt;code&gt;[]const T&lt;/code&gt; can be &lt;em&gt;made&lt;/em&gt; out of a writable view by giving
something up, which is why widening is safe and why the bit costs nothing at run time. An atomic
count cannot be made out of a non-atomic one at all: it is fixed when the object is allocated, and a
view claiming it would be reporting on somebody else’s storage rather than describing itself. Rust
reaches the same three answers with three mechanisms and splits them the same way — &lt;code&gt;&amp;amp;[T]&lt;/code&gt; carries
writability in the reference, &lt;code&gt;Rc&amp;lt;[T]&amp;gt;&lt;/code&gt; against &lt;code&gt;Arc&amp;lt;[T]&amp;gt;&lt;/code&gt; carries count discipline in the &lt;em&gt;owner’s&lt;/em&gt;
type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no unchecked-index escape hatch&lt;/strong&gt; for a hot loop. A &lt;code&gt;*T&lt;/code&gt; is the way to write one today.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no rectangular multi-dimensional type.&lt;/strong&gt; &lt;code&gt;[3][3]f64&lt;/code&gt; is an array of arrays and works;
a distinct type with one bounds check for two indices is not planned.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/reference/strings/&quot;&gt;strings&lt;/a&gt; — the same three words, with a guarantee added and an operation
taken away.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>sysl.args</title>
    <link href="https://sysl.sh/library/args/"/>
    <id>https://sysl.sh/library/args/</id>
    <updated>2026-08-16T01:26:07.924728867Z</updated>
    <summary>How argc and argv become a []string, and the two layers that read options out of them.</summary>
    <content type="html">&lt;p&gt;&lt;code&gt;sysl.args&lt;/code&gt; is three things, in the order a program meets them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;args_of&lt;/code&gt;&lt;/strong&gt; turns what the platform hands an entry point into a &lt;code&gt;[]string&lt;/code&gt;. Almost no program
writes its name — declaring &lt;code&gt;main(args: []string)&lt;/code&gt; is what calls it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Scan&lt;/code&gt;&lt;/strong&gt; reads a command line one option at a time and leaves what each one &lt;em&gt;means&lt;/em&gt; to the
program. This is the layer a small program wants.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Cli&lt;/code&gt;&lt;/strong&gt; describes the options in a table and generates the &lt;code&gt;--help&lt;/code&gt; that documents them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The two parsing layers are not a beginner’s and an expert’s. They answer different shapes: a table
is worth writing when the options are many enough that their help text is the point, and a &lt;code&gt;match&lt;/code&gt; is
better when there are three of them.&lt;/p&gt;
&lt;h2 id=&quot;getting-the-arguments-at-all&quot;&gt;Getting the arguments at all&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;args_of(argc: i32, argv: **u8) -&amp;gt; []string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the platform hands an entry point is C’s pair — a count, and a vector of NUL-terminated byte
runs. What a sysl program asks for is a slice of strings. Something has to walk the one and build the
other, and doing it &lt;strong&gt;in the library&lt;/strong&gt; is what keeps the pair out of every sysl signature: the two
foreign types are named in one place instead of in every program that wants its arguments.&lt;/p&gt;
&lt;h2 id=&quot;where-it-is-actually-called&quot;&gt;Where it is actually called&lt;/h2&gt;
&lt;p&gt;A program’s top-level statements are its entry point, and a declared &lt;code&gt;main&lt;/code&gt; is the other way of
writing that same place — one that has the thing statements cannot get at: the arguments the program
was started with. A program starts in &lt;strong&gt;one&lt;/strong&gt; place, so it writes one or the other, and a program that
wants its arguments puts inside &lt;code&gt;main&lt;/code&gt; what it would otherwise have written above.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the work runs here, with&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, args.len, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;argument&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;the work runs here, with 1 argument
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Declaring it with a parameter is the whole of what asks for the conversion — the entry point the
compiler lays out is what calls &lt;code&gt;args_of&lt;/code&gt;, which is why a program that reads its arguments still
contains no mention of this module.&lt;/p&gt;
&lt;p&gt;The count is &lt;code&gt;1&lt;/code&gt; above because the program was started with no arguments of its own. Element zero is
always there, and it is the program’s own path — the same convention C has, and the reason a loop
over arguments starts at one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(args.len)

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;..&amp;lt;args.len
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(i, args[i])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run through the compiler’s own driver, &lt;strong&gt;everything after a bare &lt;code&gt;--&lt;/code&gt; belongs to the program&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sysl run report.sysl -- --verbose report.txt
3
1 --verbose
2 report.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The split is made before sysl’s own options are parsed, which is why an argument that looks like one
of sysl’s is still the program’s.&lt;/p&gt;
&lt;h2 id=&quot;the-two-signatures-and-nothing-else&quot;&gt;The two signatures, and nothing else&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;main()&lt;/code&gt; and &lt;code&gt;main(args: []string)&lt;/code&gt;. A &lt;code&gt;[]const string&lt;/code&gt; is accepted in the same position, because a
program that only reads its arguments may say so and it costs the entry point nothing — the two
views are one layout, and what &lt;code&gt;args_of&lt;/code&gt; yields may stand in for either:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(args: []&lt;span class=&quot;hl-keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(args.len)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A result other than a &lt;code&gt;Result[unit, E]&lt;/code&gt; is refused&lt;/strong&gt;, because it would be an exit status, and an
exit status is not something a sysl signature spells:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;() -&amp;gt; &lt;span class=&quot;hl-type&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; yields nothing or a &apos;Result[unit, E]&apos;, so it may not result in int — a program&apos;s exit status is not something a signature can say
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The one result a &lt;code&gt;main&lt;/code&gt; may have is &lt;a href=&quot;/reference/modules/&quot;&gt;&lt;code&gt;Result[unit, E]&lt;/code&gt;&lt;/a&gt;, which is not an exit
status but an error to report: a failure travels out as a value, is printed on stderr, and the status
is &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The platform’s own pair is refused&lt;/strong&gt;, which is the refusal this module exists to make unnecessary:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;(argc: &lt;span class=&quot;hl-type&quot;&gt;i32&lt;/span&gt;, argv: *&lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(argc)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; takes either nothing or one &apos;[]string&apos; of the program&apos;s arguments, not (int, **byte)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Type parameters are refused&lt;/strong&gt;, since the caller is the platform and it has none to give:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;[&lt;span class=&quot;hl-type&quot;&gt;T&lt;/span&gt;]()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nothing calls this with a type&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; is called by the platform, which has no type arguments to give it
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;And there is one &lt;code&gt;main&lt;/code&gt; in a program&lt;/strong&gt;, wherever it is written — so a module may not declare one
beside the one the program starts at. That is the same reservation C makes and for the same reason:
it is not a name a program calls, it is the name the platform calls, and two of them would leave
which one the program &lt;em&gt;is&lt;/em&gt; to whichever was emitted last.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the other one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;&apos;main&apos; is where a program starts, so there is one — a second declaration of it would overload the name, and a program has one beginning rather than a set of them
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reading-options-the-scanner&quot;&gt;Reading options: the scanner&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Scan&lt;/code&gt; knows the &lt;em&gt;shape&lt;/em&gt; of a command line and nothing about which options a program has. It knows
that &lt;code&gt;--name=value&lt;/code&gt; carries its value with it, that &lt;code&gt;-abc&lt;/code&gt; is three options in one word, that &lt;code&gt;--&lt;/code&gt;
ends the options and everything after it is an operand. Deciding what each one means is the &lt;code&gt;match&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;scan(args)&lt;/code&gt; skips the zeroth argument, since that is the program’s own path and never an option.
&lt;code&gt;scan_all&lt;/code&gt; reads every word it is given, which is what the examples on this page use — a page’s
programs are run with no arguments, so the words have to come from somewhere.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(argv: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;scan_all&lt;/span&gt;(argv)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; verbose = &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; output = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
        a.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Short&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;v&apos;&lt;/span&gt;))) | &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Long&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))) -&amp;gt; verbose = &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;

            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Short&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;o&apos;&lt;/span&gt;))) | &lt;span class=&quot;hl-type&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Long&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))) -&amp;gt;
                a.&lt;span class=&quot;hl-function&quot;&gt;value&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
                    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(v)  -&amp;gt; output = v
                    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())

            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Positional&lt;/span&gt;(p))) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;operand:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p)

            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;

            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(_)) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;unknown option:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, a.option)

            &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt;
                &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())
                &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, verbose)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;output :&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, output)
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-vo&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;out.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;one&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-two&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;operand: one
operand: -two
verbose: true
output : out.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things in that loop are the whole design.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The &lt;code&gt;match&lt;/code&gt; is why to prefer this to a query API.&lt;/strong&gt; An option nobody handled is a missing arm, and
&lt;a href=&quot;/reference/patterns/&quot;&gt;exhaustiveness&lt;/a&gt; makes that a diagnostic — where a &lt;code&gt;parsed.value(&amp;quot;output&amp;quot;)&lt;/code&gt;
spelling would hand back a &lt;code&gt;None&lt;/code&gt; at run time that reads exactly like an option the user did not
pass. &lt;code&gt;Short(&apos;o&apos;) | Long(&amp;quot;output&amp;quot;)&lt;/code&gt; is the arm that reads best, and it is legal because an
alternative may not bind and neither of those two does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A value is asked for rather than reported.&lt;/strong&gt; Whether the next word belongs to the option or stands
on its own is not something the shape can tell — &lt;code&gt;-o x&lt;/code&gt; is an option and its value, &lt;code&gt;-v x&lt;/code&gt; is an
option and an operand. Only the program knows, so &lt;code&gt;value()&lt;/code&gt; is a call it makes on the options that
take one, and all four spellings reach it: &lt;code&gt;-ox&lt;/code&gt;, &lt;code&gt;-o x&lt;/code&gt;, &lt;code&gt;--output=x&lt;/code&gt;, &lt;code&gt;--output x&lt;/code&gt;. What it takes
is the next word &lt;em&gt;whatever it looks like&lt;/em&gt;, which is what getopt has always done and what every
program that has had to name a file &lt;code&gt;-&lt;/code&gt; depends on.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is deliberately no &lt;code&gt;Iterate&lt;/code&gt;&lt;/strong&gt;, so &lt;code&gt;for arg in a&lt;/code&gt; does not compile. A &lt;code&gt;for&lt;/code&gt; walks a &lt;em&gt;copy&lt;/em&gt; of
its cursor, so the &lt;code&gt;value()&lt;/code&gt; call inside the loop would advance a cursor the loop is not reading, and
every option’s value would arrive somewhere else. The loop is written by hand and cannot go wrong
that way.&lt;/p&gt;
&lt;p&gt;The scanner reports two failures of its own. One is an option whose value is not there; the other is
a value nobody asked for, which is the case a scanner without a &lt;code&gt;Result&lt;/code&gt; gets wrong:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;(argv: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;scan_all&lt;/span&gt;(argv)

    &lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
        a.&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Long&lt;/span&gt;(n))) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;long:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, n)
            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Short&lt;/span&gt;(c))) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;short:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, c)
            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Some&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Positional&lt;/span&gt;(p))) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;operand:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p)
            &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;None&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;
            &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e) -&amp;gt;
                &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())
                &lt;span class=&quot;hl-keyword&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; read&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--verbose=yes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;read&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--output&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;long: verbose
error: --verbose takes no value
long: output
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;--verbose=yes&lt;/code&gt; at a program whose &lt;code&gt;--verbose&lt;/code&gt; takes nothing cannot be reported as an operand and
must not be dropped — silently dropping it would turn a mistake about what a flag means into a run
that looked successful. It is caught when the program goes on to the next argument, since asking for
a value is precisely what does &lt;em&gt;not&lt;/em&gt; reveal it.&lt;/p&gt;
&lt;h2 id=&quot;describing-a-command-line&quot;&gt;Describing a command line&lt;/h2&gt;
&lt;p&gt;The upper layer adds a table, and what the table buys is the two things a hand-written &lt;code&gt;match&lt;/code&gt; cannot
generate for itself: a usage text that cannot drift from the options it documents, and one wording
for every failure.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; verbose = &lt;span class=&quot;hl-function&quot;&gt;flag&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;v&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;print more about what is happening&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; output  = &lt;span class=&quot;hl-function&quot;&gt;option&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;o&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;write the result here&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; dry     = &lt;span class=&quot;hl-function&quot;&gt;long_flag&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;dry-run&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;work out what would happen, and do none of it&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; spec = &lt;span class=&quot;hl-function&quot;&gt;cli&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, [verbose, output, dry],
               about = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Count what is in a file.&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,
               version = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;0.1.0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,
               operands = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[file...]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;help&lt;/span&gt;(spec))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;usage: count [options] [file...]

Count what is in a file.

options:
  -v, --verbose        print more about what is happening
  -o, --output &amp;lt;path&amp;gt;  write the result here
      --dry-run        work out what would happen, and do none of it
  -h, --help           show this help and exit
  -V, --version        show the version and exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Six constructors build an option — &lt;code&gt;flag&lt;/code&gt; and &lt;code&gt;option&lt;/code&gt; for one written both ways, &lt;code&gt;long_flag&lt;/code&gt; and
&lt;code&gt;long_option&lt;/code&gt; for one with no letter, &lt;code&gt;short_flag&lt;/code&gt; and &lt;code&gt;short_option&lt;/code&gt; for one with no word. Only
&lt;code&gt;name&lt;/code&gt; and the table are required of &lt;code&gt;cli&lt;/code&gt;; &lt;code&gt;about&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt; and &lt;code&gt;operands&lt;/code&gt; are
&lt;a href=&quot;/reference/functions/&quot;&gt;defaults&lt;/a&gt;, so a program writes the ones it has.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An option is named by the value that declares it&lt;/strong&gt;, not by a string or an index:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; verbose = &lt;span class=&quot;hl-function&quot;&gt;flag&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;v&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;print more&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; output  = &lt;span class=&quot;hl-function&quot;&gt;option&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;o&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;write here&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; spec    = &lt;span class=&quot;hl-function&quot;&gt;cli&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, [verbose, output], operands = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;[file...]&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(spec, [&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-v&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-o&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;out.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;in.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ready&lt;/span&gt;(p)) -&amp;gt;
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p.&lt;span class=&quot;hl-function&quot;&gt;given&lt;/span&gt;(verbose))
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;output :&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p.&lt;span class=&quot;hl-function&quot;&gt;value_or&lt;/span&gt;(output, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;files  :&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, p.positionals.len)
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;HelpRequested&lt;/span&gt;)    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;help was asked for&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;VersionRequested&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;the version was asked for&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e)               -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;verbose: true
output : out.txt
files  : 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The alternative spellings were both worse. A string — &lt;code&gt;p.value(&amp;quot;output&amp;quot;)&lt;/code&gt; — makes a typo a &lt;code&gt;None&lt;/code&gt;
that reads like an option nobody passed. An index into the table makes it worse: a wrong number is a
&lt;em&gt;different option’s&lt;/em&gt; value, silently, and it asks a program to keep two lists in step by hand. A
binding is a name, so a typo is &lt;code&gt;undefined name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The table is built &lt;strong&gt;inside a body&lt;/strong&gt; rather than at the top level, and that is a rule rather than a
preference: an &lt;code&gt;Opt&lt;/code&gt; holds strings, and a &lt;a href=&quot;/reference/modules/&quot;&gt;module-level &lt;code&gt;val&lt;/code&gt;&lt;/a&gt; whose value is
built while the program runs is refused, since storage that lives for the whole run has nowhere to
write the release its count would need. A program wanting its description at the top level writes a
function returning one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;p.count&lt;/code&gt; is what a flag given more than once answers, so &lt;code&gt;-vvv&lt;/code&gt; means what it means everywhere;
&lt;code&gt;p.value&lt;/code&gt; is &lt;code&gt;None&lt;/code&gt; for an option that was not given and for one that takes no value however often it
was; &lt;code&gt;p.positionals&lt;/code&gt; is everything that was not an option, in the order it was written.&lt;/p&gt;
&lt;h3 id=&quot;help-and-version&quot;&gt;Help and version&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;--help&lt;/code&gt; is always offered and &lt;code&gt;--version&lt;/code&gt; whenever a version was given, along with &lt;code&gt;-h&lt;/code&gt; and &lt;code&gt;-V&lt;/code&gt; —
but &lt;strong&gt;only where the program has not claimed the spelling&lt;/strong&gt;. A program whose &lt;code&gt;-V&lt;/code&gt; means verbose keeps
it, and the help text then lists &lt;code&gt;--version&lt;/code&gt; with no letter rather than taking one that means
something else:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; height  = &lt;span class=&quot;hl-function&quot;&gt;option&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;h&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;how tall&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; verbose = &lt;span class=&quot;hl-function&quot;&gt;flag&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;V&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;say more&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;prints&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;help&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;cli&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, [height, verbose], version = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;usage: thing [options]

options:
  -h, --height &amp;lt;n&amp;gt;  how tall
  -V, --verbose     say more
      --help        show this help and exit
      --version     show the version and exit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What they do is &lt;strong&gt;reported rather than done&lt;/strong&gt;. &lt;code&gt;parse&lt;/code&gt; neither prints nor stops the program, which is
what keeps it a function of its arguments and what lets a test drive it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.*

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q    = &lt;span class=&quot;hl-function&quot;&gt;flag&lt;/span&gt;(&lt;span class=&quot;hl-string&quot;&gt;&apos;q&apos;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;quiet&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;say less&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; spec = &lt;span class=&quot;hl-function&quot;&gt;cli&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, [q], version = &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;(argv: []&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;parse&lt;/span&gt;(spec, argv) &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;Ready&lt;/span&gt;(_))         -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;ready&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;HelpRequested&lt;/span&gt;)    -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;help&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;Ok&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;VersionRequested&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
        &lt;span class=&quot;hl-function&quot;&gt;Err&lt;/span&gt;(e)               -&amp;gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;error:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e.&lt;span class=&quot;hl-function&quot;&gt;message&lt;/span&gt;())
&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt; say&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-q&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--help&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;-V&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;say&lt;/span&gt;([&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;thing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--nope&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ready
help
version
error: unknown option --nope
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;the-conventions-and-who-applies-them&quot;&gt;The conventions, and who applies them&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;parse_or_exit&lt;/code&gt; is the one that acts, and its name says so:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--help&lt;/code&gt; and &lt;code&gt;--version&lt;/code&gt; print to &lt;strong&gt;standard output&lt;/strong&gt; and exit &lt;strong&gt;0&lt;/strong&gt;, because printing them was
what the program was asked to do — which is what lets &lt;code&gt;prog --help | less&lt;/code&gt; work.&lt;/li&gt;
&lt;li&gt;A command line that could not be read goes to &lt;strong&gt;standard error&lt;/strong&gt; with the usage line and a pointer
at &lt;code&gt;--help&lt;/code&gt;, and exits &lt;strong&gt;2&lt;/strong&gt; — the status getopt, argp and every parser since reserve for being
invoked wrongly, as against 1 for running and failing.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;$ wc --nope
wc: error: unknown option --nope
usage: wc [options] &amp;lt;file&amp;gt;
try &apos;wc --help&apos; for more information.
$ echo $?
2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The usage line and the help text are separate outputs on purpose.&lt;/strong&gt; &lt;code&gt;usage_line&lt;/code&gt; is the one line;
&lt;code&gt;help&lt;/code&gt; is the whole thing. Answering a mistyped flag with forty lines of help buries the sentence
saying what was mistyped.&lt;/p&gt;
&lt;p&gt;Nothing in the help text is wrapped to a terminal width, which is a deliberate limit: asking how wide
the terminal is means asking the platform, and this is otherwise pure string work that a program with
no &lt;code&gt;os&lt;/code&gt; capability can still call. A description longer than its column takes the next line.&lt;/p&gt;
&lt;h2 id=&quot;calling-it-yourself&quot;&gt;Calling it yourself&lt;/h2&gt;
&lt;p&gt;The function stays public, and there are two reasons — the second of which is the interesting one.&lt;/p&gt;
&lt;p&gt;The first is the ordinary one: a program handed an &lt;code&gt;argv&lt;/code&gt; by something &lt;strong&gt;other than the platform&lt;/strong&gt; —
an embedder, a shell it implements, a test that wants to drive its own argument parsing — has
somewhere to go.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.args_of
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.text.cstring

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; a = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; b = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; c = &lt;span class=&quot;hl-function&quot;&gt;cstring&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;file.txt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; vec = [a.ptr, b.ptr, c.ptr]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; made = &lt;span class=&quot;hl-function&quot;&gt;args_of&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;vec[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(made.len)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(made[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], made[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], made[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(made[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;].len, made[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] == &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;--verbose&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
prog --verbose file.txt
9 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second is that &lt;strong&gt;this is the only surface on which an argument vector’s failure can be reached at
all&lt;/strong&gt;, since a well-formed one is all a real process will ever hand over. That failure is the next
section.&lt;/p&gt;
&lt;h2 id=&quot;what-the-conversion-actually-does&quot;&gt;What the conversion actually does&lt;/h2&gt;
&lt;p&gt;Three things, and each is a decision worth knowing about.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It finds each run’s length by looking for the terminator&lt;/strong&gt;, rather than by calling &lt;code&gt;strlen&lt;/code&gt;. So the
conversion asks the platform for nothing beyond the two values it was handed, which is what lets a
target with no libc still start a program.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It validates and copies.&lt;/strong&gt; A &lt;code&gt;string&lt;/code&gt; owns what it holds, so an argument outlives the vector it
came from, and nothing a program does to one reaches memory the platform still owns. That copy is
not an oversight to be optimized away later — a borrowed view into &lt;code&gt;argv&lt;/code&gt; would be a slice whose
owner is the process image, which is a thing no sysl type describes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An argument that is not UTF-8 stops the program&lt;/strong&gt;, the way &lt;code&gt;unwrap&lt;/code&gt; does, and it names the byte:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sysl&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; sysl.args.args_of

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; bad: []&lt;span class=&quot;hl-type&quot;&gt;u8&lt;/span&gt; = [&lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; vec = [&lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;bad[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]]
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; made = &lt;span class=&quot;hl-function&quot;&gt;args_of&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt;vec[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(made.len)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That program prints&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;panic: command-line argument 0 is not UTF-8 at byte 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and exits with status 1. It is not a checked program on this page for that reason — a non-zero exit
is a failure to the harness — but the message is what a real one prints, and note that it &lt;em&gt;does&lt;/em&gt;
print, unlike the &lt;a href=&quot;/library/sync/&quot;&gt;trap&lt;/a&gt; a violated contract lowers to. This one is an ordinary
&lt;code&gt;print&lt;/code&gt; and &lt;code&gt;exit&lt;/code&gt;, so the text reaches the terminal.&lt;/p&gt;
&lt;p&gt;Putting the check here is deliberate: validation belongs &lt;strong&gt;at the boundary&lt;/strong&gt;, so that everything
above it can treat a &lt;code&gt;string&lt;/code&gt; as well-formed without asking. An argument vector is a boundary.&lt;/p&gt;
&lt;h2 id=&quot;why-it-is-a-module-of-its-own&quot;&gt;Why it is a module of its own&lt;/h2&gt;
&lt;p&gt;Two reasons, and both are what a submodule is for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Almost nobody writes this name.&lt;/strong&gt; A &lt;code&gt;main(args: []string)&lt;/code&gt; is what asks for the conversion, and
the entry point the compiler lays out is what makes it. A name nearly nobody writes has no business
in the set every file gets for free, so a program that does want it names &lt;code&gt;sysl.args.args_of&lt;/code&gt; and
says so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It cannot live beside the platform externs in &lt;a href=&quot;/library/sys/&quot;&gt;&lt;code&gt;sysl.sys&lt;/code&gt;&lt;/a&gt;.&lt;/strong&gt; This calls &lt;code&gt;print&lt;/code&gt; and
&lt;code&gt;exit&lt;/code&gt;, which are &lt;code&gt;sysl&lt;/code&gt;‘s, and &lt;code&gt;sysl&lt;/code&gt; reaches &lt;code&gt;sysl.sys&lt;/code&gt; for its printing — putting both in one
module would make the two depend on each other, which the
&lt;a href=&quot;/reference/modules/&quot;&gt;acyclic module graph&lt;/a&gt; refuses. What is left in &lt;code&gt;sys&lt;/code&gt; is a &lt;strong&gt;leaf that needs
nothing&lt;/strong&gt;, which is what a platform module should be.&lt;/p&gt;
&lt;p&gt;That second reason is worth sitting with, because it is a general shape rather than an accident of
this module. A conversion that reports its failure in words is not a leaf, because reporting is
itself a dependency. Splitting it out is what let the thing underneath stay one.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Next: &lt;a href=&quot;/library/sys/&quot;&gt;&lt;code&gt;sysl.sys&lt;/code&gt;&lt;/a&gt; — the platform seam, and the leaf it was split out to protect.&lt;/p&gt;</content>
  </entry>
</feed>
