<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>slate</title>
  <link href="https://slatelang.dev/feed.xml" rel="self"/>
  <link href="https://slatelang.dev/"/>
  <id>https://slatelang.dev/feed.xml</id>
  <updated>2026-09-06T00:36:22.158815252Z</updated>
  <author><name>Ed Maxedon</name></author>
  <entry>
    <title>slate:zstd</title>
    <link href="https://slatelang.dev/library/zstd/"/>
    <id>https://slatelang.dev/library/zstd/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Zstandard — the encoding for a hot path, and for a protocol whose two ends are both yours.</summary>
    <content type="html">&lt;h1 id=&quot;slatezstd&quot;&gt;&lt;code&gt;slate:zstd&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Zstandard — the encoding for a hot path, and for a protocol whose two ends are both yours.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { zstd, unzstd } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:zstd

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; page &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toBytes&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;&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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; small &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;zstd&lt;/span&gt;(page, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)                   &lt;span class=&quot;hl-comment&quot;&gt;// the level: 1 fast, 3 the default, 19 for storage&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; back &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;unzstd&lt;/span&gt;(small, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)           &lt;span class=&quot;hl-comment&quot;&gt;// the limit is not optional&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(small) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(page))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(page)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;unzstd&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;toBytes&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 zstd&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-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true true
false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;why-it-is-here-beside-brotli-and-gzip&quot;&gt;Why it is here beside brotli and gzip&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;It fills the gap between them.&lt;/strong&gt; &lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt; at quality 5 is the slow end of what a
request handler can afford; &lt;code&gt;deflate&lt;/code&gt; is the fast end and compresses worse than either. zstd at level 3
is several times faster than deflate and compresses better than it, and at 19 it is in brotli’s range —
so it is the first encoding worth reaching for on a response being built now, and the obvious one for a
build cache, a log, or a wire format where both ends are yours.&lt;/p&gt;
&lt;h2 id=&quot;the-names-are-the-formats-own-verbs&quot;&gt;The names are the format’s own verbs&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;zstd&lt;/code&gt; and &lt;code&gt;unzstd&lt;/code&gt;, not &lt;code&gt;compress&lt;/code&gt; and &lt;code&gt;decompress&lt;/code&gt;.&lt;/strong&gt; Those two are &lt;code&gt;slate:brotli&lt;/code&gt;‘s, and every
built-in module’s names are declared into one scope — so two modules cannot own a word.
&lt;a href=&quot;/library/gzip/&quot;&gt;&lt;code&gt;slate:gzip&lt;/code&gt;&lt;/a&gt; settled this first with &lt;code&gt;gzip&lt;/code&gt;, &lt;code&gt;gunzip&lt;/code&gt;, &lt;code&gt;deflate&lt;/code&gt; and &lt;code&gt;inflate&lt;/code&gt;, and these are
what the command line calls them.&lt;/p&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;zstd&lt;/code&gt; faults&lt;/strong&gt; — it cannot fail on input the program already holds. &lt;strong&gt;&lt;code&gt;unzstd&lt;/code&gt; answers a result&lt;/strong&gt;,
because what is being decompressed came from somewhere else: a request body that is not a zstd frame is
an ordinary thing to be sent and a &lt;code&gt;400&lt;/code&gt; to answer, not a defect in the program reading it.&lt;/p&gt;
&lt;p&gt;The three failures are three sentences, since they mean three different things to whoever sent the bytes:
&lt;em&gt;expands past the N bytes it was allowed&lt;/em&gt;, &lt;em&gt;ends in the middle&lt;/em&gt;, &lt;em&gt;is not a zstd frame&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-limit-is-required&quot;&gt;The limit is required&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A zstd frame is entitled to say nothing about how large it becomes&lt;/strong&gt;, and where its header does carry a
size that number is the frame’s claim rather than a fact. So there is no form of &lt;code&gt;unzstd&lt;/code&gt; that omits the
limit.&lt;/p&gt;
&lt;h2 id=&quot;the-level-is-written-at-every-call&quot;&gt;The level is written at every call&lt;/h2&gt;
&lt;p&gt;There is no default, for &lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt;‘s reason: it is the one number a caller has to think
about, and no single value is right often enough to be the quiet one. The scale runs from libzstd’s own
minimum to 22 and is &lt;strong&gt;not&lt;/strong&gt; linear — negative levels are a regime of their own that skips most of the
match search, 1 to 3 are for anything on a hot path, 9 is a good compress-once setting, and 19 to 22 want
real memory at the writing end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A frame carries a checksum&lt;/strong&gt;, which is what tells a damaged stream from one that was never zstd.&lt;/p&gt;
&lt;h2 id=&quot;both-hosts-have-it-and-a-browser-does-not&quot;&gt;Both hosts have it, and a browser does not&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;node has carried Zstandard in &lt;code&gt;zlib&lt;/code&gt; since 22.15&lt;/strong&gt;, so this module is native under &lt;code&gt;slate js&lt;/code&gt; as well
as here — and the compressed bytes are not compared between the two, node linking its own copy of libzstd
and the interpreter linking the machine’s. Two encoders at one level may frame the same input differently
and both be right; what is checked is the round trip and what each makes of the other’s frames.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One difference is documented rather than papered over.&lt;/strong&gt; node’s decompressor answers &lt;em&gt;nothing&lt;/em&gt; about
a frame that ends in the middle — an empty buffer and no error, where libzstd’s one-shot call says
&lt;code&gt;srcSize_wrong&lt;/code&gt; — so the JavaScript back end reads the frame header and measures what came back against
what it claimed. A frame that declared &lt;strong&gt;no&lt;/strong&gt; size is the one case it cannot check, and there the two
back ends read a truncation differently: this one answers what it managed and the interpreter refuses.
Every frame &lt;code&gt;zstd&lt;/code&gt; writes declares its size, so this is about frames from somewhere else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No browser has zstd&lt;/strong&gt; — &lt;code&gt;CompressionStream&lt;/code&gt; takes &lt;code&gt;gzip&lt;/code&gt;, &lt;code&gt;deflate&lt;/code&gt; and &lt;code&gt;deflate-raw&lt;/code&gt;, and no engine
has proposed a fourth — so both names refuse there naming zstd, exactly as &lt;code&gt;slate:brotli&lt;/code&gt; does.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; writes &lt;code&gt;Content-Encoding: zstd&lt;/code&gt; for a client that asks for it, in preference to
brotli, with nothing asked of the handler; that page says what the rules are.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:ws</title>
    <link href="https://slatelang.dev/library/ws/"/>
    <id>https://slatelang.dev/library/ws/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>WebSockets, written in slate over the slate:http upgrade seam.</summary>
    <content type="html">&lt;h1 id=&quot;slatews&quot;&gt;&lt;code&gt;slate:ws&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;WebSockets, written in slate over the &lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; upgrade seam.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { serve } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:http
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { accept } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:ws

&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(port, handler, (req, socket, head) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; ws &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;accept&lt;/span&gt;(req, socket, head)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

    ws&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;onMessage&lt;/span&gt;((m) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; ws&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;send&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;echo:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; m)))&lt;/code&gt;&lt;/pre&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;open(url)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;promise&lt;/strong&gt; of a result holding the connection — the client&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;accept(req, socket, head)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;result&lt;/strong&gt; holding the connection — the server&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;accepting(req)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;whether this request is a WebSocket handshake&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;framed(payload, opcode)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a frame a server writes, for a program doing its own writing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;maskedFrame(payload, opcode)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same frame a client writes, which is masked&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unframed(bytes)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the other direction&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;openurl--the-client&quot;&gt;&lt;code&gt;open(url)&lt;/code&gt; — the client&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { open } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:ws

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; made &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &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;wss://example.com/socket&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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;made&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok &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;print&lt;/span&gt;(made&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)

    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; made&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

    c&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;onMessage&lt;/span&gt;((m) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;said&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, m))
    c&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;onClose&lt;/span&gt;((code, why) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;gone&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, code))
    c&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;send&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;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A promise of a result and not a promise that fails&lt;/strong&gt;, which is &lt;code&gt;connect&lt;/code&gt;‘s shape in
&lt;a href=&quot;/library/net/&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;&lt;/a&gt;: a server that is not there is a condition a client was always going to deal
with. &lt;code&gt;ws://&lt;/code&gt; and &lt;code&gt;wss://&lt;/code&gt; are the only two schemes, and a url that is not one is refused in the same
sentence wherever the program runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The connection is the same object &lt;code&gt;accept&lt;/code&gt; answers&lt;/strong&gt; — &lt;code&gt;onMessage&lt;/code&gt;, &lt;code&gt;onBinary&lt;/code&gt;, &lt;code&gt;onClose&lt;/code&gt;, &lt;code&gt;send&lt;/code&gt;,
&lt;code&gt;sendBytes&lt;/code&gt;, &lt;code&gt;ping&lt;/code&gt;, &lt;code&gt;close&lt;/code&gt; — so a program that speaks WebSocket does not know which end it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A client masks every frame it sends and a server masks none&lt;/strong&gt;, which is RFC 6455’s rule and not an
implementation detail: masking exists so that a hostile page cannot steer an intermediary into reading
payload bytes as a request of its own, and only the browser’s direction has that problem. Each end
fails the connection when the other gets it wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Under &lt;code&gt;slate js&lt;/code&gt; the client is the HOST’s.&lt;/strong&gt; A browser has no socket at all, so the framing here has
nothing to write onto and the work goes to the &lt;code&gt;WebSocket&lt;/code&gt; object the page already has;
&lt;a href=&quot;/reference/javascript/&quot;&gt;the JavaScript page&lt;/a&gt; says what that changes. The one visible difference
is &lt;code&gt;ping&lt;/code&gt;, which refuses there: a browser writes the protocol’s control frames itself and gives a page
no way to.&lt;/p&gt;
&lt;h2 id=&quot;the-upgrade-seam&quot;&gt;The upgrade seam&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;serve&lt;/code&gt; takes a third function&lt;/strong&gt;, and so does &lt;code&gt;serveStream&lt;/code&gt;. A request that says &lt;code&gt;Connection: upgrade&lt;/code&gt;
reaches it with &lt;code&gt;(req, conn, leftover)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The leftover bytes matter.&lt;/strong&gt; A client may put its first frame in the same packet as the handshake, and
those bytes are already off the socket — so they are handed to &lt;code&gt;accept&lt;/code&gt;, which seeds the connection’s
buffer with them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A server with no upgrade function answers 501 rather than going quiet.&lt;/strong&gt; The client asked for a protocol
this program does not speak, which it can act on; a socket nothing will ever answer is not.&lt;/p&gt;
&lt;h2 id=&quot;what-is-in-the-module&quot;&gt;What is in the module&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The framing, the masking, the fragment reassembly and base64 are all slate.&lt;/strong&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; and
&lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; are slate’s own on 64-bit integers, and &lt;code&gt;toBytes&lt;/code&gt;/&lt;code&gt;fromBytes&lt;/code&gt; are the byte surface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SHA-1 is the one thing reached for&lt;/strong&gt;, from &lt;a href=&quot;/library/crypto/&quot;&gt;&lt;code&gt;slate:crypto&lt;/code&gt;&lt;/a&gt;. This is not a use of SHA-1 that
its weakness touches: nothing is signed, and the protocol wants a value only the other end could have
computed.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Values</title>
    <link href="https://slatelang.dev/reference/values/"/>
    <id>https://slatelang.dev/reference/values/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>slate is dynamically typed. Every value is one of a fixed set of kinds, and a program can ask which.</summary>
    <content type="html">&lt;h1 id=&quot;values&quot;&gt;Values&lt;/h1&gt;
&lt;p&gt;slate is dynamically typed. Every value is one of a fixed set of kinds, and a program can ask which.&lt;/p&gt;
&lt;h2 id=&quot;the-kinds&quot;&gt;The kinds&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;kind&lt;/th&gt;&lt;th&gt;written&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;null&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the only absence there is&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;integer&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;42&lt;/code&gt;, &lt;code&gt;0xff&lt;/code&gt;&lt;/td&gt;&lt;td&gt;64 bits, signed, wraps&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;3.14&lt;/code&gt;, &lt;code&gt;2e10&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a double&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;&lt;code&gt;&amp;quot;text&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a sequence of &lt;strong&gt;characters&lt;/strong&gt;, never of bytes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;array&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;[1, 2]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;reference type, compares by contents&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;object&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{ a: 1 }&lt;/code&gt;&lt;/td&gt;&lt;td&gt;reference type, compares by contents&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;x -&amp;gt; x&lt;/code&gt;, a definition&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;promise&lt;/td&gt;&lt;td&gt;answered by an &lt;code&gt;async&lt;/code&gt; call&lt;/td&gt;&lt;td&gt;see &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Eight more scalar kinds come with &lt;a href=&quot;/library/time/&quot;&gt;&lt;code&gt;slate:time&lt;/code&gt;&lt;/a&gt; — &lt;code&gt;instant&lt;/code&gt;, &lt;code&gt;duration&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;,
&lt;code&gt;time&lt;/code&gt;, &lt;code&gt;dateTime&lt;/code&gt;, &lt;code&gt;zone&lt;/code&gt;, &lt;code&gt;zoned&lt;/code&gt;, &lt;code&gt;period&lt;/code&gt; — and a compiled pattern comes with
&lt;a href=&quot;/library/regex/&quot;&gt;&lt;code&gt;slate:regex&lt;/code&gt;&lt;/a&gt;. Each has a type word that tests for it in
&lt;a href=&quot;/reference/patterns/&quot;&gt;pattern position&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;number&lt;/code&gt; is not a kind.&lt;/strong&gt; It is the union of &lt;code&gt;integer&lt;/code&gt; and &lt;code&gt;real&lt;/code&gt;, and exists because the two are
separate values: a guard about arithmetic would otherwise have to be written twice.&lt;/p&gt;
&lt;h2 id=&quot;truth&quot;&gt;Truth&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Only &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;null&lt;/code&gt; are false.&lt;/strong&gt; Zero, the empty string and the empty array are all true.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;if&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;true&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;false&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;if&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;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;true&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;false&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;if&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;true&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;false&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;true
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;equality&quot;&gt;Equality&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;==&lt;/code&gt; compares &lt;strong&gt;by value, all the way down&lt;/strong&gt;. Two arrays holding the same elements are equal; two
objects holding the same fields are equal.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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-keyword&quot;&gt;==&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;], { a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; { a&lt;span class=&quot;hl-keyword&quot;&gt;:&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;true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An integer and a real compare across the kinds&lt;/strong&gt;, so &lt;code&gt;1 == 1.0&lt;/code&gt; is true — but &lt;code&gt;1 is integer&lt;/code&gt; and
&lt;code&gt;1.0 is integer&lt;/code&gt; still differ, the two being distinct values that happen to compare equal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A function is equal to itself.&lt;/strong&gt; &lt;code&gt;f == f&lt;/code&gt; is true, and two separately written lambdas with the same
body are not equal.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; may take &lt;code&gt;==&lt;/code&gt; over for its own instances by writing &lt;code&gt;equals&lt;/code&gt;, and must write
&lt;code&gt;hash&lt;/code&gt; beside it if those instances are to be used as table keys. &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;gt;=&lt;/code&gt; are one hook,
&lt;code&gt;compare&lt;/code&gt; — see &lt;a href=&quot;/reference/objects/&quot;&gt;Objects&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;numbers&quot;&gt;Numbers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An integer is 64 bits and wraps&lt;/strong&gt;; it does not promote to a real and does not become a big integer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9223372036854775807&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&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;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;-9223372036854775808
1099511627776
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;/&lt;/code&gt; between two integers divides towards zero&lt;/strong&gt; and answers an integer; &lt;code&gt;%&lt;/code&gt; takes the sign of the
left operand. Where either operand is a real the answer is a real.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&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;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;7.0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;/&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 3.5 -3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A real that is whole prints as an integer does.&lt;/strong&gt; &lt;code&gt;string(1.0)&lt;/code&gt; is &lt;code&gt;&amp;quot;1&amp;quot;&lt;/code&gt;. Only &lt;code&gt;%&lt;/code&gt;, indexing, or a
kind test can tell the two apart, so a function that must answer an integer is worth annotating.&lt;/p&gt;
&lt;h2 id=&quot;strings&quot;&gt;Strings&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A slate string is a sequence of characters&lt;/strong&gt;, so every position, length and slice is counted the way
a person counts:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&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;日本語&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;日本語&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-keyword&quot;&gt;..&amp;lt;&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;héllo&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;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;indexOf&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-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;))      &lt;span class=&quot;hl-comment&quot;&gt;// by character; it is 3 by byte&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;There is no character type: a single character is a string of one. That is what lets indexing, &lt;code&gt;chars&lt;/code&gt;
and &lt;code&gt;split&lt;/code&gt; all hand back the same kind of thing.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;toBytes(s)&lt;/code&gt; answers an array of numbers and &lt;code&gt;fromBytes(bs)&lt;/code&gt; answers a &lt;a href=&quot;/reference/faults/&quot;&gt;result&lt;/a&gt;; those two
are the only place a slate program sees UTF-8, and &lt;code&gt;len(toBytes(s))&lt;/code&gt; is the byte count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Case and whitespace are the whole database and not the ASCII range.&lt;/strong&gt; &lt;code&gt;upper&lt;/code&gt; and &lt;code&gt;lower&lt;/code&gt; answer
what any other language with a case table answers, which is not always one character out for one
character in, and &lt;code&gt;trim&lt;/code&gt; takes off Unicode’s &lt;code&gt;White_Space&lt;/code&gt; — so a no-break space pasted out of a form
comes off and a zero-width no-break space, which is not a space at all, stays.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;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;Straße&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;span class=&quot;hl-function&quot;&gt;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;İ&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;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;ΟΔΟΣ&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;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;ΟΔΟΣΑ&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;[&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;trim&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;\u{a0}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\u{a0}&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;+&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;STRASSE 2
οδος οδοσα
[x]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second line is Unicode’s own rule that a sigma ending a word is written &lt;code&gt;ς&lt;/code&gt;, which is context
rather than a table; the first is &lt;code&gt;ß&lt;/code&gt; uppercasing to two letters and &lt;code&gt;İ&lt;/code&gt; lowercasing to two.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;normalize(s, form)&lt;/code&gt; puts text into one of &lt;code&gt;&amp;quot;NFC&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;NFD&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;NFKC&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;NFKD&amp;quot;&lt;/code&gt;, which is what two
strings have to go through before &lt;code&gt;==&lt;/code&gt; between them means what a reader thinks it means — the same
word typed on two machines is routinely two different sequences of characters. &lt;code&gt;casefold(s)&lt;/code&gt; is what
two strings differing only in case both come to, and is &lt;strong&gt;not&lt;/strong&gt; &lt;code&gt;lower&lt;/code&gt;: &lt;code&gt;ß&lt;/code&gt; folds to &lt;code&gt;ss&lt;/code&gt;, so
&lt;code&gt;casefold(&amp;quot;STRASSE&amp;quot;) == casefold(&amp;quot;Straße&amp;quot;)&lt;/code&gt; where lowering leaves them different.&lt;/p&gt;
&lt;h2 id=&quot;conversion&quot;&gt;Conversion&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The type words are the conversions.&lt;/strong&gt; &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;integer&lt;/code&gt;, &lt;code&gt;real&lt;/code&gt; and &lt;code&gt;boolean&lt;/code&gt; each test
in pattern position and convert in expression position; the two never overlap.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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-number&quot;&gt;123&lt;/span&gt;) &lt;span class=&quot;hl-keyword&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;!&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-type&quot;&gt;number&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-type&quot;&gt;number&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nonsense&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-type&quot;&gt;integer&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.9&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;123!
42 null
2 3 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;number&lt;/code&gt; answers &lt;code&gt;null&lt;/code&gt; where the text is not a number, which is how a program checks input without
raising. &lt;code&gt;integer&lt;/code&gt; and &lt;code&gt;real&lt;/code&gt; move between the two numeric kinds; the four roundings — &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; — leave an integer alone.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; take as many arguments as they are given and answer an &lt;strong&gt;integer when every one of
them was&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reference-and-copy&quot;&gt;Reference and copy&lt;/h2&gt;
&lt;p&gt;Arrays and objects are reference types: two names may hold the same array, and a write through one is
visible through the other. Everything else is a scalar.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;a with { f: v }&lt;/code&gt; answers a &lt;strong&gt;copy&lt;/strong&gt; of &lt;code&gt;a&lt;/code&gt; with &lt;code&gt;f&lt;/code&gt; changed, which is how a record is updated without
mutating it. &lt;code&gt;concat(xs, ys)&lt;/code&gt; is the array counterpart.&lt;/p&gt;
&lt;h2 id=&quot;absence&quot;&gt;Absence&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;undefined&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;null&lt;/code&gt; is the only absence, it is an ordinary value, and slate refuses to
store anything else in its place. That single rule explains a run of behaviour that otherwise looks
unrelated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pop&lt;/code&gt;, &lt;code&gt;shift&lt;/code&gt; and &lt;code&gt;at&lt;/code&gt; &lt;strong&gt;fault&lt;/strong&gt; where there is nothing there, rather than answering nothing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;find&lt;/code&gt; and &lt;code&gt;indexOf&lt;/code&gt; answer &lt;strong&gt;&lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; — a search that found nothing is an answer, where reaching
past the end is a mistake.&lt;/li&gt;
&lt;li&gt;A parameter nobody gave is &lt;strong&gt;not bound at all&lt;/strong&gt;, so there is no sentinel to test for and
&lt;code&gt;f(1, null)&lt;/code&gt; is not the same as &lt;code&gt;f(1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;An object field a value need not have is a question about its &lt;a href=&quot;/reference/types/&quot;&gt;shape&lt;/a&gt; (&lt;code&gt;pinned?&lt;/code&gt;), not a
value that might be absent.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>slate:url</title>
    <link href="https://slatelang.dev/library/url/"/>
    <id>https://slatelang.dev/library/url/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Percent-encoding and the name=value grammar — the piece under everything that reads a URL.</summary>
    <content type="html">&lt;h1 id=&quot;slateurl&quot;&gt;&lt;code&gt;slate:url&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Percent-encoding and the &lt;code&gt;name=value&lt;/code&gt; grammar — the piece under everything that reads a URL.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { percentDecode, encodeComponent, parseQuery, parsePairs } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:url

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;parseQuery&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;name=Ada+Lovelace&amp;amp;year=1843&amp;amp;tag=caf%C3%A9&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;(q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;name, q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;year, q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;tag)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;encodeComponent&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?d=e&amp;amp;f&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;percentDecode&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%C3%A9&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;))

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; cookies &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;parsePairs&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;session=abc; theme=dark&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-variable&quot;&gt;false&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(cookies&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;session, cookies&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;theme)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Ada Lovelace 1843 café
a%20b%2Fc%3Fd%3De%26f
café
abc dark
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;it-exists-so-that-a-page-can-import-it&quot;&gt;It exists so that a page can import it&lt;/h2&gt;
&lt;p&gt;These four were &lt;code&gt;slate:http&lt;/code&gt;‘s, and that module exported them saying in as many words that a framework
over it needs the same decoder its router uses. That was true and it was not enough: &lt;strong&gt;the JavaScript
back end emits the whole of an imported module&lt;/strong&gt;, so a browser page importing &lt;code&gt;slate:http&lt;/code&gt; to reach two
functions grew by &lt;strong&gt;239 KB&lt;/strong&gt; — 340,761 bytes to 579,710 — because &lt;code&gt;slate:http&lt;/code&gt; is a server, an HTTP/2
speaker and a file server. A page that only wants to read its own query string was paying for all of it.&lt;/p&gt;
&lt;p&gt;So this is the lowest module slate has after &lt;a href=&quot;/library/llhttp/&quot;&gt;&lt;code&gt;slate:llhttp&lt;/code&gt;&lt;/a&gt;, and it is here for that
module’s reason: what a program actually wanted was underneath something much larger.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:http&lt;/code&gt; still exports all four and always will.&lt;/strong&gt; It imports them from here and forwards them,
so nothing written against that module changed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It asks nothing of the host&lt;/strong&gt; — no socket, no clock, no document — so it works under the interpreter,
under node and in a browser with no branch anywhere.&lt;/p&gt;
&lt;h2 id=&quot;decoding-is-over-bytes-not-characters&quot;&gt;Decoding is over bytes, not characters&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;%C3%A9&lt;/code&gt; is two bytes that are one character, so a decoder working a character at a time cannot put
them back together: this one collects the bytes and decodes the lot at the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It answers its input unchanged where those bytes turn out not to be text.&lt;/strong&gt; A URL is something
somebody else wrote, and a fault here would let any link stop a program. For the same reason, &lt;strong&gt;a &lt;code&gt;%&lt;/code&gt;
not followed by two hex digits is a &lt;code&gt;%&lt;/code&gt;&lt;/strong&gt; — which is what every browser does with one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;plusIsSpace&lt;/code&gt; is the one difference between a query or a form and everything else percent-encoded. A
cookie’s &lt;code&gt;+&lt;/code&gt; is a &lt;code&gt;+&lt;/code&gt;, and so is a path segment’s.&lt;/p&gt;
&lt;h2 id=&quot;encoding-is-the-unreserved-set-and-nothing-more&quot;&gt;Encoding is the unreserved set and nothing more&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;encodeComponent&lt;/code&gt; leaves &lt;code&gt;A-Z&lt;/code&gt;, &lt;code&gt;a-z&lt;/code&gt;, &lt;code&gt;0-9&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;_&lt;/code&gt; and &lt;code&gt;~&lt;/code&gt; alone and encodes everything else,
which is RFC 3986’s unreserved set. Encoding more than is needed is always safe and encoding less never
is, so the rule is the narrow one.&lt;/p&gt;
&lt;h2 id=&quot;a-repeated-name-is-the-last-one&quot;&gt;A repeated name is the last one&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { parseQuery } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:url

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;parseQuery&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=1&amp;amp;a=2&amp;amp;debug&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;(q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;a)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;has&lt;/span&gt;(q, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;debug&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;debug, &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;2
true  |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That is a decision rather than an oversight.&lt;/strong&gt; The alternative every framework reaches for is an array
where a name repeats — which makes the &lt;em&gt;type&lt;/em&gt; of &lt;code&gt;q.name&lt;/code&gt; depend on what somebody put in a link, so a
program that read it as a string works until the day a name arrives twice. A value whose shape varies is
the thing this language argues against everywhere.&lt;/p&gt;
&lt;p&gt;A program that genuinely expects a name more than once reads the raw text by hand; a server has it on
&lt;code&gt;req.search&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A name with no &lt;code&gt;=&lt;/code&gt; is present and empty&lt;/strong&gt;, which is what a bare &lt;code&gt;?debug&lt;/code&gt; means to everybody who writes
one.&lt;/p&gt;
&lt;h2 id=&quot;parsepairs-is-the-grammar-the-three-of-them-share&quot;&gt;&lt;code&gt;parsePairs&lt;/code&gt; is the grammar the three of them share&lt;/h2&gt;
&lt;p&gt;A query string, a form body and a &lt;code&gt;Cookie&lt;/code&gt; header are one grammar with two knobs: the separator, and
whether &lt;code&gt;+&lt;/code&gt; means a space.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { parsePairs } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:url

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parsePairs&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=1&amp;amp;b=two+words&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;amp;&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;.&lt;/span&gt;b)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parsePairs&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=1; b=two+words&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-variable&quot;&gt;false&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;two words
two+words
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is exported because the three callers inside &lt;code&gt;slate:http&lt;/code&gt; do not exhaust it: a dozen headers are
&lt;code&gt;name=value&lt;/code&gt; lists, and a program reading one of them would otherwise write this again — which is the
very thing moving the module was meant to stop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A value wrapped in quotes is unwrapped&lt;/strong&gt;, a cookie’s being so by the specification.&lt;/p&gt;
&lt;h2 id=&quot;base64urlencode-and-base64urldecode&quot;&gt;&lt;code&gt;base64urlEncode&lt;/code&gt; and &lt;code&gt;base64urlDecode&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Bytes as text that survives a URL: RFC 4648 §5’s alphabet, which is base64 with &lt;code&gt;-&lt;/code&gt; for &lt;code&gt;+&lt;/code&gt; and &lt;code&gt;_&lt;/code&gt;
for &lt;code&gt;/&lt;/code&gt;, &lt;strong&gt;and no padding at all&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { base64urlEncode, base64urlDecode } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:url

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64urlEncode&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;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;base64urlEncode&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;251&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;]))

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;base64urlDecode&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Zm9vYmFy&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;(r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; bad &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;base64urlDecode&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*d&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-keyword&quot;&gt;.&lt;/span&gt;ok, bad&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Zm9vYmFy
-_8
true foobar
false `*` is not a base64url character
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Encode takes a string or an array of bytes, and a string is its UTF-8 bytes&lt;/strong&gt; — the same reading
&lt;code&gt;encodeComponent&lt;/code&gt; gives one, and the only reading there is: what an encoding of bytes does with text
is encode the text’s bytes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Decode answers a result, and its value is BYTES.&lt;/strong&gt; Text encoded this way arrives from outside — a
cookie, a token, a signature somebody sent — so being malformed is a condition the caller was always
going to deal with rather than a fault, which is &lt;a href=&quot;/reference/faults/&quot;&gt;the rule&lt;/a&gt; for anything read
from outside. And what was encoded is as likely to be a digest as a sentence, so answering text would
be guessing; &lt;code&gt;fromBytes&lt;/code&gt; is the one call to text and answers a result of its own, so the two compose:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;base64urlDecode&lt;/span&gt;(piece)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; r&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three things are refused, each with its own sentence:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;a character that is not in the alphabet&lt;/strong&gt;, &lt;code&gt;=&lt;/code&gt; included — the padded spelling is base64 and this
is not it, and accepting both would make two encodings of one value valid, which is the shape of
hole a token format compared as text is walked through;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;a length one past a multiple of four&lt;/strong&gt;, which carries no whole byte in its last character, so
such a piece is truncated rather than merely odd;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;bits past the last whole byte that are not zero&lt;/strong&gt;, or two spellings decode to the same bytes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:jwt&lt;/code&gt; is written on these&lt;/strong&gt;, a token being three base64url pieces; it carried a private copy
until the pair moved here, which is why they are in this module and not in that one.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Types</title>
    <link href="https://slatelang.dev/reference/types/"/>
    <id>https://slatelang.dev/reference/types/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>slate is dynamically typed with a gradual checker: nothing has to be annotated, and what is annotated is checked twice — once by a pass before the program runs, and…</summary>
    <content type="html">&lt;h1 id=&quot;types&quot;&gt;Types&lt;/h1&gt;
&lt;p&gt;slate is dynamically typed with a &lt;strong&gt;gradual checker&lt;/strong&gt;: nothing has to be annotated, and what is
annotated is checked twice — once by a pass before the program runs, and once by the machine when the
value actually arrives.&lt;/p&gt;
&lt;h2 id=&quot;the-rule-the-checker-obeys&quot;&gt;The rule the checker obeys&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The pass may only report what the machine would also refuse.&lt;/strong&gt; A program that runs is never refused
before it runs. Everything below follows from that one constraint: where the pass cannot be certain, it
says nothing rather than guessing, and the machine still checks.&lt;/p&gt;
&lt;p&gt;What that costs against TypeScript is worth saying plainly: TS catches a mistake on a path you never
ran, and this only fires where the pass can prove the value is wrong or where that path executes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three deliberate exceptions, each an annotation the machine cannot check for you.&lt;/strong&gt; An annotated
&lt;code&gt;var&lt;/code&gt; is held to its declared type at every assignment; every argument must fit the type a type
parameter was solved to; and an object literal written where a shape is expected may carry only the
fields that shape names. Each is a promise the program made in writing, and being held to it is what
writing one is for.&lt;/p&gt;
&lt;h2 id=&quot;type&quot;&gt;&lt;code&gt;type&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A type is a shape with a name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { centre&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Point, radius&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    Circle &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;a circle of radius &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;v&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;radius&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    Point  &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;the point &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;v&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;x&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;v&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;y&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-variable&quot;&gt;_&lt;/span&gt;      &lt;span class=&quot;hl-keyword&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-string&quot;&gt;no idea&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;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Point)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;({ centre&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; }, radius&lt;span class=&quot;hl-keyword&quot;&gt;:&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;describe&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&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;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;nothing&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;true
a circle of radius 2
the point 3, 4
no idea
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is TypeScript’s &lt;code&gt;type&lt;/code&gt;&lt;/strong&gt; — the same declaration, the same structural reading, asking for &lt;em&gt;at
least&lt;/em&gt; those fields. What differs is that slate’s is not erased: one declaration serves both the
pattern and the check at a boundary, where a TypeScript app that reads an API response writes the shape
twice, once as a &lt;code&gt;type&lt;/code&gt; and once as a schema for the run.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing of a type’s structure exists at run time.&lt;/strong&gt; A name in pattern position is replaced by the
pattern the type declared, while the program is compiled, so &lt;code&gt;p is Point&lt;/code&gt; costs no instruction.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A type may not bind a name.&lt;/strong&gt; &lt;code&gt;type Tagged = { x: n }&lt;/code&gt; is refused: a name written inside a type would
be introduced wherever the type is used. It is the rule an alternative of a &lt;code&gt;|&lt;/code&gt; already followed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;export type&lt;/code&gt; is how an interface leaves the file it was written in, and both halves cross — the shape
the compiler resolves and the value the name binds.&lt;/p&gt;
&lt;h2 id=&quot;the-type-expressions&quot;&gt;The type expressions&lt;/h2&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;any&lt;/code&gt;&lt;/td&gt;&lt;td&gt;anything, and what an unannotated thing is&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;number&lt;/code&gt; &lt;code&gt;integer&lt;/code&gt; &lt;code&gt;real&lt;/code&gt; &lt;code&gt;string&lt;/code&gt; &lt;code&gt;boolean&lt;/code&gt; &lt;code&gt;array&lt;/code&gt; &lt;code&gt;object&lt;/code&gt; &lt;code&gt;function&lt;/code&gt; &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a kind&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;{ a: T, b?: U }&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an object with at least those fields — except a literal written at the spot, which may carry no others&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[T, U]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an array whose first elements fit&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;array of T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an array every element of which fits &lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;object of T&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an object every value of which fits &lt;code&gt;T&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T \| U&lt;/code&gt;&lt;/td&gt;&lt;td&gt;either&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;T &amp;amp; U&lt;/code&gt;&lt;/td&gt;&lt;td&gt;both&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;the same &lt;code&gt;T&lt;/code&gt;, bracketed to group it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;A -&amp;gt; B&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a function of one parameter&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;(A, B) -&amp;gt; C&lt;/code&gt;, &lt;code&gt;() -&amp;gt; C&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a function of none or several&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;a &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt; or &lt;code&gt;data&lt;/code&gt; name&lt;/td&gt;&lt;td&gt;what that declared&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Name[A, B]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a generic type, given what it is generic over&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;array-of-t&quot;&gt;&lt;code&gt;array of T&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;An array pattern tests the elements it writes and lets the rest through — &lt;code&gt;[&amp;quot;a&amp;quot;, 2] is [string, ...]&lt;/code&gt;
is &lt;strong&gt;true&lt;/strong&gt; — so a list of unknown length needs this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Tags&lt;/span&gt;   &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Counts&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;object&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Grid&lt;/span&gt;   &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;integer&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;, &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;is&lt;/span&gt; Tags, [&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Tags, [] &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Tags)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ a&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Counts, { a&lt;span class=&quot;hl-keyword&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;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Counts)
&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-keyword&quot;&gt;is&lt;/span&gt; Grid)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true false true
true false
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An empty container fits&lt;/strong&gt;, every element of nothing fitting anything. A floor is said with an
intersection: &lt;code&gt;[any, ...] &amp;amp; array of string&lt;/code&gt;. The element pattern may not bind, running once per
element.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;for&lt;/code&gt; over one types its variable&lt;/strong&gt;, so &lt;code&gt;for u in users&lt;/code&gt; where &lt;code&gt;users: array of User&lt;/code&gt; makes &lt;code&gt;u&lt;/code&gt; a
&lt;code&gt;User&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;-and-&quot;&gt;&lt;code&gt;?&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A field the value need not have is marked &lt;code&gt;?&lt;/code&gt;.&lt;/strong&gt; Present it must fit; absent the shape still holds —
which a nullable union cannot say, &lt;code&gt;tag: string | null&lt;/code&gt; still requiring the key to be there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Note&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { title&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;boolean&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;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;is&lt;/span&gt; Note)               &lt;span class=&quot;hl-comment&quot;&gt;// absent, and the shape still holds&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Note)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Note)    &lt;span class=&quot;hl-comment&quot;&gt;// present, and does not fit&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;strong&gt;&lt;code&gt;=&lt;/code&gt; is for a pattern that binds and &lt;code&gt;?&lt;/code&gt; is for one that tests&lt;/strong&gt;, and each is refused where the other
belongs.&lt;/p&gt;
&lt;p&gt;A union may have &lt;code&gt;null&lt;/code&gt; as an alternative, which is how a parameter says it will take nothing:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;MaybePoint&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; Point &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { side&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; { radius&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; MaybePoint, { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; MaybePoint, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; MaybePoint)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ side&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Shape, { radius&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Shape, { area&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Shape)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true false
true true false
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; is &lt;code&gt;|&lt;/code&gt;‘s dual and binds tighter, matching only where every part does. A value picks up fields on
its way down through a stack of functions, and this is how the one at the bottom says what it receives:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Authed&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { user&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { id&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; } }
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bodied&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { body&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;handle&lt;/span&gt;(req&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Authed &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt; Bodied) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; req&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;user&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;id

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;handle&lt;/span&gt;({ user&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { id&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt; }, body&lt;span class=&quot;hl-keyword&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;/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;A part may bind, where an alternative may not&lt;/strong&gt;: every part runs, so &lt;code&gt;{ a } &amp;amp; { b }&lt;/code&gt; binding both is
sound.&lt;/p&gt;
&lt;h3 id=&quot;a-function-type&quot;&gt;A function type&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;integer -&amp;gt; integer&lt;/code&gt; is the type of &lt;code&gt;n -&amp;gt; n + 1&lt;/code&gt;, and it is spelled the way the lambda is.&lt;/strong&gt; One
parameter needs no brackets; none or several are a bracketed list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&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;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;f&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;later&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; () &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;apply&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;twice&lt;/span&gt;((a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; b), &lt;span class=&quot;hl-function&quot;&gt;later&lt;/span&gt;(() &lt;span class=&quot;hl-keyword&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-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;2 6 hi
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The arrow is the loosest thing in a type and groups to the right.&lt;/strong&gt; &lt;code&gt;string | null -&amp;gt; integer&lt;/code&gt; is a
function taking either — which is what a parameter usually means — and a union &lt;em&gt;holding&lt;/em&gt; a function
says so with brackets:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Handler&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;MaybeFn&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; MaybeFn) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; f &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&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; &lt;span class=&quot;hl-function&quot;&gt;f&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;run&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;*&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;0 20
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Writing one down is what types the lambda handed to it&lt;/strong&gt;, which is where most of what it buys shows
up: the parameters flow inwards and what the body does with them is checked.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&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;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;`+` does not apply to an integer and a string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;What is checked is the arity and the parameters, and deliberately not the result.&lt;/strong&gt; A function’s own
&lt;code&gt;-&amp;gt; string&lt;/code&gt; is checked against what that function answers and never against what somebody who was
handed it expected, so a mismatch there is a complaint no run could make. Where the result matters —
&lt;code&gt;f(cb) = cb(1) + 1&lt;/code&gt; — it is read off the annotation and the arithmetic is checked on its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At run time a function type asks what it can ask: is this callable, and would it take a call of this
size.&lt;/strong&gt; What a function will &lt;em&gt;do&lt;/em&gt; with what it is given is not a question about the value in front of
you, which is why the parameters are the checker’s business and the count is both.&lt;/p&gt;
&lt;h2 id=&quot;annotating&quot;&gt;Annotating&lt;/h2&gt;
&lt;p&gt;Per parameter, and per result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&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;double&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
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A result that does not fit what was promised is a fault where the answer was written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(p&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { id&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&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;id

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;({ id&lt;span class=&quot;hl-keyword&quot;&gt;:&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-error&quot;&gt;this answers string, and gave back 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A parameter’s complaint lands where the value was handed over:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;d&lt;/span&gt;(b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Point) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;x

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;d&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&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;`d` takes { x: number, y: number } here, and this is { x: integer }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A lambda’s parameters may be annotated and its result may not.&lt;/strong&gt; The arrow already separates the
parameters from the body, so there is nowhere for a result to be written; it is read off the body.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; g &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (n&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;+&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;g&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;h3 id=&quot;a-binding&quot;&gt;A binding&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;val x: T = e&lt;/code&gt; and &lt;code&gt;var n: T = e&lt;/code&gt;&lt;/strong&gt;, checked where the value arrives and again by the pass that runs
before the program does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;ada&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; tags&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;reading&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;writing&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; count&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

count &lt;span class=&quot;hl-keyword&quot;&gt;+=&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;(name, tags, count)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ada [&amp;quot;reading&amp;quot;, &amp;quot;writing&amp;quot;] 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An annotated &lt;code&gt;var&lt;/code&gt; is TypeScript’s &lt;code&gt;let&lt;/code&gt;: the declared type is what the name holds for its whole
life&lt;/strong&gt;, so every assignment is checked against it rather than against what happens to be there.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&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;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

n &lt;span class=&quot;hl-keyword&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;later&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;`n` was declared integer, and this is string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;strong&gt;unannotated&lt;/strong&gt; &lt;code&gt;var&lt;/code&gt; is left as it always was — the union of its initialiser and every value ever
assigned to it — so a program that deliberately reuses a name for another kind is untouched.&lt;/p&gt;
&lt;h3 id=&quot;an-object-literal-written-where-a-shape-is-expected&quot;&gt;An object literal written where a shape is expected&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A shape asks for &lt;em&gt;at least&lt;/em&gt; its fields — except of a literal written at the spot, which may carry
only the fields it names.&lt;/strong&gt; An object that arrives through a name is one other places hold, so the
fields this parameter does not want are somebody else’s business. A literal written here has no other
reader, so a field the shape does not name is not a spare: it is a mistake, and the mistake it nearly
always is is a misspelling.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Style&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { color&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, weight&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;use&lt;/span&gt;(s&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Style) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;color

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;use&lt;/span&gt;({ colour&lt;span class=&quot;hl-keyword&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;red&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, weight&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;400&lt;/span&gt; }))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`colour` is not a field of { color: string, weight: integer }, and an object literal written here may carry only the fields it names -- did you mean `color`?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is &lt;strong&gt;TypeScript’s excess-property check&lt;/strong&gt;, drawn in the same place and for the same reason, and it
applies to a literal at an annotated parameter — including one typed by a solved type parameter — and
to the value of a binding that declared a type.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only a literal standing at the spot.&lt;/strong&gt; A value reaching the same parameter through a name is
structural as it always was; a literal built by a spread is a merge rather than a literal; and a
literal nested inside one is the outer field’s business rather than the annotation’s.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Spot&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(p&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Spot) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;y

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; big &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, z&lt;span class=&quot;hl-keyword&quot;&gt;:&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; some &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, z&lt;span class=&quot;hl-keyword&quot;&gt;:&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-function&quot;&gt;area&lt;/span&gt;(big), &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;({ &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;some, y&lt;span class=&quot;hl-keyword&quot;&gt;:&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;6 6
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-rest-parameter&quot;&gt;A rest parameter&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;...rest: array of T&lt;/code&gt; describes the array&lt;/strong&gt;, because the array is what the name holds: a call gathers
what is left over into one, and it is checked once, where the gathering happened.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;ns&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;reduce&lt;/span&gt;(ns, (a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b, &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;total&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;6
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-the-checker-knows-before-the-program-runs&quot;&gt;What the checker knows before the program runs&lt;/h2&gt;
&lt;h3 id=&quot;a-call-answers-in-terms-of-what-it-was-given&quot;&gt;A call answers in terms of what it was given&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;sorted&lt;/code&gt;, &lt;code&gt;reversed&lt;/code&gt;, &lt;code&gt;slice&lt;/code&gt; and &lt;code&gt;pop&lt;/code&gt; all give back what they were handed, so the element
type survives them and a mistake is caught where it is written — in either spelling, a method being
checked as the free function it is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(xs&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(xs)

&lt;span class=&quot;hl-function&quot;&gt;h&lt;/span&gt;(ns&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(ns&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;filter&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&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;`f` takes array of string here, and this is array of integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;f(filter(ns, n -&amp;gt; n &amp;gt; 1))&lt;/code&gt; draws the same complaint, a method being checked as the free function it
is.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;map(ns, n -&amp;gt; string(n))&lt;/code&gt; is an &lt;code&gt;array of string&lt;/code&gt;, the lambda’s result being read off its body.&lt;/p&gt;
&lt;h3 id=&quot;a-callback-knows-what-it-is-handed&quot;&gt;A callback knows what it is handed&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, &lt;code&gt;forEach&lt;/code&gt; and the rest call their function with one element; &lt;code&gt;sorted&lt;/code&gt; calls its
comparator with two; &lt;code&gt;reduce&lt;/code&gt; calls its function with a running value and an element. &lt;strong&gt;The checker says
so&lt;/strong&gt;, so a lambda written at the call gets its parameters typed from the array beside it — and what it
&lt;em&gt;does&lt;/em&gt; with them is checked:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h&lt;/span&gt;(ns&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(ns, n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)   &lt;span class=&quot;hl-comment&quot;&gt;// an array of integer, not of any&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;h&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[2, 4, 6]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What the callback &lt;em&gt;does&lt;/em&gt; with what it was handed is checked:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;(ss&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(ss, s &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;*&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;`*` does not apply to string and integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and so is its arity — in one direction. &lt;strong&gt;A callback may declare FEWER parameters than the builtin
hands it&lt;/strong&gt;, a native passing as many as the callback declares; see
&lt;a href=&quot;/reference/functions/#callbacks-take-as-many-arguments-as-they-declare&quot;&gt;Callbacks&lt;/a&gt;. Declaring &lt;strong&gt;more&lt;/strong&gt; is
refused, there being nothing to fill them with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;q&lt;/span&gt;(ns&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(ns, (a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`map` takes (integer) -&amp;gt; any here, and this is (integer, any) -&amp;gt; integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is the CALLER that makes the relaxation sound, so it stops at a builtin.&lt;/strong&gt; A parameter the
program annotated is compared strictly in both directions: a call the program wrote passes what the
program wrote, and nothing adapts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;None of that is a type variable.&lt;/strong&gt; A builtin’s signature names an argument by &lt;em&gt;position&lt;/em&gt;, and the
type at that position is filled in at the call — no binding, no scope, nothing to write anywhere. What
a program writes for itself is the next section.&lt;/p&gt;
&lt;h2 id=&quot;type-parameters&quot;&gt;Type parameters&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;first[T](xs: array of T) -&amp;gt; T&lt;/code&gt; is how a function you write says the same thing a builtin says&lt;/strong&gt;: the
answer is whatever the call was given.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;first[T](xs&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of T) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; T &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(&lt;span class=&quot;hl-function&quot;&gt;first&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-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;first&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;ada 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The parameters are solved from the arguments left to right, so a callback written at the call is typed
from the arguments before it — and what it does with them is checked:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;map2[A, B](xs&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of A, f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; A &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; B) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of B &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(xs, f)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map2&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-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;], s &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;upper&lt;/span&gt;(s)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[&amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;They are declared in one place and nowhere else&lt;/strong&gt; — &lt;code&gt;[T]&lt;/code&gt; after the name of a definition or a type —
and there are no bounds, no variance and no defaults. A generic type is used by giving it what it is
generic over, and the shape that comes out is the shape both declarations describe:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[A, B] &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { first&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; A, second&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; B }

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(p&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Pair[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;]) &lt;span class=&quot;hl-keyword&quot;&gt;=&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-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;first&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; is &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;second&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-function&quot;&gt;show&lt;/span&gt;({ first&lt;span class=&quot;hl-keyword&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;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, second&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;36&lt;/span&gt; }))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ first&lt;span class=&quot;hl-keyword&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;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, second&lt;span class=&quot;hl-keyword&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;x&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Pair[&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;ada is 36
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A generic type used without its arguments is refused rather than quietly erased&lt;/strong&gt;, because a check
that passes for the wrong reason is worse than no check:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pair&lt;/span&gt;[A, B] &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { first&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; A, second&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; B }

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(p&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Pair) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;first&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`Pair` is generic over 2 types, so it needs them here
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;every-argument-must-fit-the-type-the-parameter-was-solved-to&quot;&gt;Every argument must fit the type the parameter was solved to&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A type parameter is solved from the arguments, and every one of them has to be contained in the
answer.&lt;/strong&gt; The candidates are gathered across the whole call and the one that every other candidate
fits is chosen; where there is no such candidate the call is refused, naming the parameter, what it
was taken to be, and the argument that disagrees:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;pair[T](a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T, b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of T &lt;span class=&quot;hl-keyword&quot;&gt;=&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;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;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;`T` is integer from an argument before this one, and this is string
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A union is still an answer where the PROGRAM declared one&lt;/strong&gt;, because then it is a candidate like any
other and the value beside it fits:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;pair[T](a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T, b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of T &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; [a, b]

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; mixed&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&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;pair&lt;/span&gt;(mixed, &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;[1, &amp;quot;x&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;fits&lt;/code&gt; is the same relation used everywhere else on this page, so an integer does not fit a &lt;code&gt;real&lt;/code&gt;.&lt;/strong&gt;
&lt;code&gt;pair(1, 2.5)&lt;/code&gt; is refused for that reason, and &lt;code&gt;number&lt;/code&gt; is the type that takes both — which is what to
annotate with where a call means to mix them:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;pair[T](a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T, b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; T) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of T &lt;span class=&quot;hl-keyword&quot;&gt;=&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;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.5&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`T` is integer from an argument before this one, and this is real
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-a-type-parameter-still-does-not-do&quot;&gt;What a type parameter still does not do&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;It is erased, so nothing at run time knows it was there.&lt;/strong&gt; The machine sees values, not the calls
that were made — which is exactly why the check above happens while compiling or not at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So &lt;code&gt;x is T&lt;/code&gt; cannot be asked&lt;/strong&gt;, and it is refused where it is written rather than answering
something. &lt;strong&gt;There are no type arguments at a call either&lt;/strong&gt; — &lt;code&gt;first[string](xs)&lt;/code&gt; is an index followed
by a call, and no grammar can have both — so they are solved from the arguments or not given.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inside the definition a &lt;code&gt;T&lt;/code&gt; is a value nothing is known about&lt;/strong&gt;, which is what makes &lt;code&gt;upper(xs[0])&lt;/code&gt;
in a generic function perfectly legal: &lt;code&gt;T&lt;/code&gt; may be a string, and refusing a program that runs is the one
thing the checker may not do.&lt;/p&gt;
&lt;h3 id=&quot;it-reads-the-rest-of-the-block-before-it-says-what-a-name-holds&quot;&gt;It reads the rest of the block before it says what a name holds&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A &lt;code&gt;var&lt;/code&gt; is the union of its initialiser and every value ever assigned to it&lt;/strong&gt;, so a counter stays an
integer through &lt;code&gt;+= 1&lt;/code&gt; and &lt;code&gt;n++&lt;/code&gt; and a wrong call is refused before the program runs. A &lt;code&gt;var&lt;/code&gt; the
program reassigns to another kind is said nothing about. &lt;strong&gt;An ANNOTATED &lt;code&gt;var&lt;/code&gt; is what it was declared
and every assignment is checked against that&lt;/strong&gt;, which is the one place the pass refuses something the
machine would have run: the annotation is a promise the program made, and being held to it is what
writing one is for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An array literal says what it was built out of&lt;/strong&gt;, so &lt;code&gt;map([1, 2], n -&amp;gt; n * 2)&lt;/code&gt; types its callback
and &lt;code&gt;first([1, 2])&lt;/code&gt; answers an integer. Elements that disagree make a union and one that is not known
gives the whole thing up. &lt;strong&gt;A NAME does not keep it&lt;/strong&gt;: an array is mutable and outlives the line that
built it, so the element type is dropped where a literal is bound to a name — the rule an object’s
shape already follows. An annotation is not dropped, being a promise the machine checks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A local object’s fields are known&lt;/strong&gt; for as long as nothing can have made them stale: its name never
mentioned except to read a field off it, so nothing else holds the object and no field of it is ever
written. &lt;code&gt;o with { … }&lt;/code&gt; is a mention.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An annotated parameter’s shape is not carried past the call.&lt;/strong&gt; The object came from somewhere else,
the caller may hold another name for it, and the annotation is checked on the way in and says nothing
about after.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;where-it-steps-aside&quot;&gt;Where it steps aside&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A call that spreads&lt;/strong&gt; — &lt;code&gt;f(...xs)&lt;/code&gt; — is not checked for arity, the count being a run-time fact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A receiver whose type is &lt;code&gt;any&lt;/code&gt;&lt;/strong&gt; is never asked what methods it has.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An object’s field names&lt;/strong&gt; are the program’s, so an object is never asked whether it has one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A method name is refused before it runs where the receiver’s kind is certain&lt;/strong&gt; — &lt;code&gt;&amp;quot;abc&amp;quot;.push(1)&lt;/code&gt;,
&lt;code&gt;date(…).hour()&lt;/code&gt; — because that asks the machine’s own question: the dispatch table is one table.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a-type-is-a-value-under-its-own-name&quot;&gt;A type is a value under its own name&lt;/h2&gt;
&lt;p&gt;Which is what makes the declaration the validator — nothing written twice, and no schema library to
keep in step with it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Note&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { title&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;boolean&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Note&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;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;(Note&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;mismatch&lt;/span&gt;({ }))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Note&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
[{path: &amp;quot;title&amp;quot;, wanted: &amp;quot;string&amp;quot;, got: &amp;quot;nothing&amp;quot;}]
Note
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mismatch&lt;/code&gt; collects &lt;strong&gt;every&lt;/strong&gt; reason rather than stopping at the first, because a person filling in a
form wants to be told about all of it at once, and &lt;code&gt;path&lt;/code&gt; says where in the value each one is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Those three are the whole surface: a shape’s fields cannot be read back out&lt;/strong&gt;, so nothing can grow to
depend on the structure of a type. &lt;code&gt;is&lt;/code&gt; is deliberately not extended to take one — a bare name in
pattern position binds, so &lt;code&gt;v is s&lt;/code&gt; would match everything — and &lt;code&gt;shape&lt;/code&gt; is a type word, so &lt;code&gt;s is shape&lt;/code&gt;
asks whether &lt;code&gt;s&lt;/code&gt; is one of these.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This covers all three declarations that name a type&lt;/strong&gt;, so a &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; name and a
&lt;a href=&quot;/reference/data-types/&quot;&gt;data&lt;/a&gt; name answer the same three about themselves — the shape being the very pattern
&lt;code&gt;is&lt;/code&gt; tests, interned where the declaration stands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&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; x
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; y

&lt;span class=&quot;hl-keyword&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Failure&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;NotFound&lt;/span&gt;(what)
    Empty

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Point&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(), Point&lt;span class=&quot;hl-keyword&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;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;)), Point&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&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;(Failure&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(Empty), Failure&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;mismatch&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;(NotFound&lt;span class=&quot;hl-keyword&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;NotFound&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;)), NotFound&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(Empty))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Point true false
true [{path: &amp;quot;&amp;quot;, wanted: &amp;quot;Failure&amp;quot;, got: &amp;quot;integer&amp;quot;}]
true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A class and a variant ask a &lt;strong&gt;nominal&lt;/strong&gt; question — was this value made from that declaration — so
&lt;code&gt;test&lt;/code&gt; is &lt;code&gt;is&lt;/code&gt; and a &lt;code&gt;mismatch&lt;/code&gt; against one names the type and stops. There is nothing more useful to
say about a value that was made from something else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A static the class itself declares wins over all three&lt;/strong&gt;, the shape answering only where the
object’s own fields and its whole proto chain have said nothing. So &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; are still words
a class may use for its own purposes.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;shape&lt;/code&gt; as a type word takes all three, so &lt;code&gt;f(s: shape)&lt;/code&gt; is how a function says it wants one — and
&lt;code&gt;Point is shape&lt;/code&gt; is true where &lt;code&gt;Point(1, 2) is shape&lt;/code&gt; is not, a value being what the type describes
rather than the type.&lt;/p&gt;
&lt;h2 id=&quot;interfaces&quot;&gt;Interfaces&lt;/h2&gt;
&lt;p&gt;An interface, in the sense of a set of operations, needs nothing further — functions are values, so
&lt;code&gt;type Drawable = { draw: function }&lt;/code&gt; is one. A &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; promises one with &lt;code&gt;is&lt;/code&gt; in its header,
which is TypeScript’s &lt;code&gt;implements&lt;/code&gt; and is checked where the class is written.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:time</title>
    <link href="https://slatelang.dev/library/time/"/>
    <id>https://slatelang.dev/library/time/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Eight types, because one type is where a date library’s bugs come from. A Date that is an instant answering calendar questions by silently reading the host’s zone is the…</summary>
    <content type="html">&lt;h1 id=&quot;slatetime&quot;&gt;&lt;code&gt;slate:time&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Eight types, because one type is where a date library’s bugs come from.&lt;/strong&gt; A &lt;code&gt;Date&lt;/code&gt; that is an instant
answering calendar questions by silently reading the host’s zone is the conflation every famous defect
follows from, so slate splits it:&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;instant&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a point on the timeline, with no calendar&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an exact length — micros to weeks&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;a calendar date, with no time of day&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;a time of day, with no date&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dateTime&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a wall reading, with no zone&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;zone&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a zone&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;zoned&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a wall reading in a zone&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;period&lt;/code&gt;&lt;/td&gt;&lt;td&gt;months and days&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each has a &lt;a href=&quot;/reference/patterns/&quot;&gt;type word&lt;/a&gt; that tests for it, so &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt; and &lt;code&gt;zone&lt;/code&gt; in
pattern position test rather than bind. Ordinary &lt;code&gt;val date = …&lt;/code&gt; is unaffected.&lt;/p&gt;
&lt;h2 id=&quot;making-one&quot;&gt;Making one&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { now, monotonic, &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;time&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;, localZone, utc } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-function&quot;&gt;now&lt;/span&gt;()                       &lt;span class=&quot;hl-comment&quot;&gt;// an instant&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;monotonic&lt;/span&gt;()                 &lt;span class=&quot;hl-comment&quot;&gt;// a DURATION -- it names no point in time&lt;/span&gt;
&lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&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-type&quot;&gt;time&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;14&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-type&quot;&gt;dateTime&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&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;14&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-type&quot;&gt;zone&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;America/Toronto&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;localZone&lt;/span&gt;()
utc                         &lt;span class=&quot;hl-comment&quot;&gt;// a VALUE, not a call -- the one zone that cannot fail to be found&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;instant&lt;/code&gt;, &lt;code&gt;epochSeconds&lt;/code&gt;, &lt;code&gt;epochMillis&lt;/code&gt; and &lt;code&gt;epochMicros&lt;/code&gt; cross to and from a count.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The clock reads whole milliseconds and an instant holds microseconds.&lt;/strong&gt; &lt;code&gt;now()&lt;/code&gt; is a millisecond
reading on every back end — JavaScript’s has nothing finer, and a timestamp that printed six fractional
digits in one program and three in another would be a difference nobody asked for. An instant a program
builds is exact: &lt;code&gt;epochMicros(1000000001)&lt;/code&gt; keeps its last digit, and &lt;code&gt;monotonic()&lt;/code&gt;, which is what an
elapsed time is measured with, is finer than a millisecond wherever the host clock is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Durations&lt;/strong&gt; are &lt;code&gt;micros millis seconds minutes hours days weeks&lt;/code&gt;; &lt;strong&gt;periods&lt;/strong&gt; are &lt;code&gt;months years&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;)                 &lt;span class=&quot;hl-comment&quot;&gt;// a duration&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;months&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)                   &lt;span class=&quot;hl-comment&quot;&gt;// a period&lt;/span&gt;
&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;()                   &lt;span class=&quot;hl-comment&quot;&gt;// the same length, as a method&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;duration-against-period&quot;&gt;Duration against period&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;This is the distinction that earns the type count.&lt;/strong&gt; A duration is exact timeline and may be added to
anything; a period is months and days and may be added only to a calendar reading.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;, days, months, weeks } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; d &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;date&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;7&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;days&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;(d &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;months&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;months&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;weeks&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026-03-08
2026-04-07
0 14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;zoned + days(1)&lt;/code&gt; keeps the wall clock across a daylight-saving change and &lt;code&gt;zoned + hours(24)&lt;/code&gt; does
not — both right, and the program says which. &lt;code&gt;instant + days(1)&lt;/code&gt; is &lt;strong&gt;refused&lt;/strong&gt;, an instant having no
calendar.&lt;/p&gt;
&lt;p&gt;Both are right, and the program says which.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Months and days never convert.&lt;/strong&gt; &lt;code&gt;months(1).days()&lt;/code&gt; is 0; &lt;code&gt;weeks(2).days()&lt;/code&gt; is 14. A month is 28 to 31
days, so any other answer is wrong somewhere. There is deliberately no &lt;code&gt;days&lt;/code&gt; on a duration.&lt;/p&gt;
&lt;h2 id=&quot;reading-one&quot;&gt;Reading one&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;One word per unit, and the receiver decides the question. Plural is a length, singular is a part.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;, hours, seconds, year, month, day, weekday, daysInMonth, isLeapYear } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; d &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&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;(&lt;span class=&quot;hl-function&quot;&gt;year&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;month&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;day&lt;/span&gt;(d))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(d&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;year&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;weekday&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;daysInMonth&lt;/span&gt;(d), &lt;span class=&quot;hl-function&quot;&gt;isLeapYear&lt;/span&gt;(d))
&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;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;seconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;())       &lt;span class=&quot;hl-comment&quot;&gt;// how many whole minutes it is&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2026 9 2
2026 Wednesday 30 false
2h 1m 30s
180
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;year month day hour minute second weekday monthName dayOfYear daysInMonth isLeapYear&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;at&quot;&gt;&lt;code&gt;at&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;at&lt;/code&gt; is the one word for reading one thing in terms of another:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-type&quot;&gt;instant&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;)
&lt;span class=&quot;hl-type&quot;&gt;zoned&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;)
&lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;time&lt;/span&gt;)
&lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;)           &lt;span class=&quot;hl-comment&quot;&gt;// a RESULT&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A wall reading that a zone skips or repeats is handed back, not guessed at.&lt;/strong&gt; &lt;code&gt;dateTime.at(zone)&lt;/code&gt; answers
an error naming the gap or the ambiguity, and &lt;code&gt;.at(zone, &amp;quot;earlier&amp;quot; | &amp;quot;later&amp;quot; | &amp;quot;after&amp;quot;)&lt;/code&gt; makes the choice
explicitly. Every mainstream library picks one silently.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;offset&lt;/code&gt;, &lt;code&gt;isDST&lt;/code&gt; and &lt;code&gt;abbrev&lt;/code&gt; ask a zone about a moment. &lt;code&gt;startOf&lt;/code&gt; truncates and &lt;code&gt;onOrAfter&lt;/code&gt; moves to the
next weekday.&lt;/p&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { parseDate } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parseDate&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-09-02&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;parseDate&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-comment&quot;&gt;// text from outside is a RESULT&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;{ok: true, value: 2026-09-02}
{ok: false, error: &amp;quot;cannot read \&amp;quot;2026-02-30\&amp;quot; as a date: day is out of range&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Three numbers the program wrote are a &lt;strong&gt;fault&lt;/strong&gt;, the other half of the same rule:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;date&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-number&quot;&gt;30&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;there is no such date
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;parseDate&lt;/code&gt;, &lt;code&gt;parseTime&lt;/code&gt;, &lt;code&gt;parseDateTime&lt;/code&gt; and &lt;code&gt;parseTimestamp&lt;/code&gt;. &lt;strong&gt;There is no &lt;code&gt;Invalid Date&lt;/code&gt; and nothing
spreads &lt;code&gt;NaN&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;comparison&quot;&gt;Comparison&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;==&lt;/code&gt; on a zoned reading needs the same instant and the same zone, where &lt;code&gt;&amp;lt;&lt;/code&gt; compares only the instant.&lt;/strong&gt;
09:00 in Toronto and 09:00 in Tokyo are different readings and neither is before the other. Java draws the
line in the same place.&lt;/p&gt;
&lt;h2 id=&quot;format&quot;&gt;&lt;code&gt;format&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;moment-flavoured, with &lt;code&gt;|bars|&lt;/code&gt; around literal text and &lt;code&gt;WWWW&lt;/code&gt; where moment writes &lt;code&gt;dddd&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;, utc } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; t &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&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;14&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(utc)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;format&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;YYYY-MM-DDThh:mm:ssZ&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&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;format&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;|on| WWWW, MMMM D, YYYY&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;2026-09-02T14:30:00Z
on Wednesday, September 2, 2026
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An element the value does not have is refused, never zero-filled:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2026&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;format&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;hh:mm&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;hh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An element the value does not have is refused, never zero-filled.&lt;/strong&gt; &lt;code&gt;date.format(&amp;quot;hh:mm&amp;quot;)&lt;/code&gt; says a date
has no time of day — a date rendered as &lt;code&gt;00:00&lt;/code&gt; is a midnight the program never meant, and that is exactly
the value that then gets stored and reported on. &lt;code&gt;format&lt;/code&gt; is in the &lt;em&gt;instant’s&lt;/em&gt; table for the same reason,
so the refusal can say “read it in a zone first”.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;f&lt;/code&gt; caps at six digits, a reading being microseconds. &lt;code&gt;a&lt;/code&gt;/&lt;code&gt;A&lt;/code&gt; are &lt;code&gt;am&lt;/code&gt;/&lt;code&gt;AM&lt;/code&gt;. The zone elements are
lower-case &lt;code&gt;z&lt;/code&gt;, so &lt;code&gt;Z&lt;/code&gt; stays a literal.&lt;/p&gt;
&lt;h2 id=&quot;timers&quot;&gt;Timers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;sleep&lt;/code&gt; and &lt;code&gt;setTimeout&lt;/code&gt; take a duration as well as a number&lt;/strong&gt;, so &lt;code&gt;await sleep(2.seconds())&lt;/code&gt; reads as
what it is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;monotonic()&lt;/code&gt; answers a duration, not an instant&lt;/strong&gt;: it names no point in time, and elapsed measurement is
the one thing it is for.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Tests</title>
    <link href="https://slatelang.dev/reference/tests/"/>
    <id>https://slatelang.dev/reference/tests/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>@test marks a function of no arguments, and slate test is the only thing that calls one.</summary>
    <content type="html">&lt;h1 id=&quot;tests&quot;&gt;Tests&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;@test&lt;/code&gt; marks a function of no arguments, and &lt;code&gt;slate test&lt;/code&gt; is the only thing that calls one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; floor &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(x) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; floor &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; floor &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; x

&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;clamp_lifts_a_small_number_to_the_floor&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;assertEq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;clamp&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), floor)

&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;a_missing_file_answers_rather_than_raising&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readFile&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-here.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;assert&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;!&lt;/span&gt;r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;a file that is not there answers a result&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&gt;$ slate test .
  ok    examples/testing.sl :: clamp_lifts_a_small_number_to_the_floor   0ms
  FAIL  examples/testing.sl :: widen_clamps_every_element   0ms
        error: got [2, 5], wanted [2, 5, 2]
          --&amp;gt; examples/testing.sl:41:5
           |
        41 |     assertEq(widen([1, 5, -2]), [2, 5, 2])
           |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

5 passed, 1 failed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;slate test&lt;/code&gt; takes a file or a directory, and walks a directory for every &lt;code&gt;.sl&lt;/code&gt; file under it.
&lt;code&gt;slate test --js&lt;/code&gt; runs the same suite &lt;a href=&quot;/reference/javascript/&quot;&gt;in JavaScript&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-assertions&quot;&gt;The assertions&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;assert(condition)&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(condition, message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assertEq(got, wanted)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;renders both sides, quoting a string so &lt;code&gt;&amp;quot;6&amp;quot;&lt;/code&gt; and &lt;code&gt;6&lt;/code&gt; do not look alike&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assertFaults(fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;calling &lt;code&gt;fn&lt;/code&gt; is supposed to raise&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assertFaults(fn, message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;and the fault has to say that&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;skip(reason)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;this test is not going to run here, and why&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A failed assertion raises&lt;/strong&gt;, and the runner catches it exactly as a &lt;a href=&quot;/reference/faults/&quot;&gt;&lt;code&gt;catch&lt;/code&gt;&lt;/a&gt; would. A test
that faults without asserting anything fails the same way, and whatever it printed is shown above the
failure.&lt;/p&gt;
&lt;h2 id=&quot;a-call-that-is-supposed-to-fail&quot;&gt;A call that is supposed to fail&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;assertFaults&lt;/code&gt; is the one assertion that cannot be written as a condition&lt;/strong&gt;, because a fault leaves
the test rather than answering false. Without it the shape is a &lt;code&gt;try&lt;/code&gt; whose body ends in a complaint —
and a &lt;code&gt;try&lt;/code&gt; that forgets that last line is a test which passes whatever the call does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; pump &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { handle&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;pull&lt;/span&gt;(p) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; p&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;handle &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;throw&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 pump has no 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;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;water&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;pulling_a_handleless_pump_says_so&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;assertFaults&lt;/span&gt;(() &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;pull&lt;/span&gt;(pump), &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;no handle&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 function takes no arguments, so what you write at the call is a lambda around the thing you expect
to go wrong. With a second argument the fault’s own text has to &lt;strong&gt;contain&lt;/strong&gt; it; with one, any fault
will do. What fails, and what it says:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;expected a fault, got a value: 42&lt;/code&gt; — the call answered instead of raising;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;the fault said &amp;quot;…&amp;quot;, wanted it to contain &amp;quot;…&amp;quot;&lt;/code&gt; — it raised, about something else.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;async&lt;/code&gt; function’s fault arrives a turn later, so &lt;code&gt;assertFaults&lt;/code&gt; answers a promise where it was
given one&lt;/strong&gt; — &lt;code&gt;await&lt;/code&gt; it, and the test is &lt;code&gt;async&lt;/code&gt; like any other that waits for something.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;a_file_that_is_not_there_is_a_fault_in_the_strict_reader&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;assertFaults&lt;/span&gt;(readStrictly)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;skip&lt;/code&gt; travels straight through it.&lt;/strong&gt; A skip is the test’s whole verdict rather than the fault the
call was asked for, so &lt;code&gt;assertFaults&lt;/code&gt; never swallows one.&lt;/p&gt;
&lt;h2 id=&quot;leaving-a-test-out&quot;&gt;Leaving a test out&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;skip(reason)&lt;/code&gt; says a test is not going to run here&lt;/strong&gt;, which is what a suite needs where one host has
something another has not — a socket under &lt;a href=&quot;/reference/javascript/&quot;&gt;&lt;code&gt;slate js&lt;/code&gt;&lt;/a&gt;, a database nobody started, a
platform the code is not written for yet.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;a_server_answers_what_it_is_asked&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&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;&lt;span class=&quot;hl-function&quot;&gt;canListen&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &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;this host has no listener&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

    &lt;span class=&quot;hl-function&quot;&gt;assertEq&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ask&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;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&gt;  ok    tests/api.sl :: a_route_is_matched_before_it_is_called   0ms
  skip  tests/api.sl :: a_server_answers_what_it_is_asked   this host has no listener

7 passed, 1 skipped
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It raises&lt;/strong&gt;, so nothing after it runs — which is why there is no &lt;code&gt;return&lt;/code&gt; on the line below it, and
why forgetting one cannot leave the test running on the host it was written to be left out of.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;catch&lt;/code&gt; does not get it.&lt;/strong&gt; A skip is the test’s whole verdict, exactly as &lt;code&gt;exit&lt;/code&gt; is a script’s, so
a library the test called cannot swallow it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A reason is required, and it is shown where the timing is on a pass.&lt;/strong&gt; A test left out with nothing
said is one nobody ever puts back — and a run that skipped anything says so on its last line, so a
suite that quietly stopped running half of itself cannot report a page of greens.&lt;/p&gt;
&lt;h2 id=&quot;setting-up-and-tidying-away&quot;&gt;Setting up, and tidying away&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Four annotations say what runs around a test&lt;/strong&gt;, and every one of them marks a function of no
arguments exactly as &lt;code&gt;@test&lt;/code&gt; does:&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;@setup&lt;/code&gt;&lt;/td&gt;&lt;td&gt;before &lt;strong&gt;each&lt;/strong&gt; test in the file&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@teardown&lt;/code&gt;&lt;/td&gt;&lt;td&gt;after &lt;strong&gt;each&lt;/strong&gt; test, however it went&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@setupAll&lt;/code&gt;&lt;/td&gt;&lt;td&gt;once, before the first test&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;@teardownAll&lt;/code&gt;&lt;/td&gt;&lt;td&gt;once, after the last&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;What they share, they share through the file’s own &lt;code&gt;var&lt;/code&gt;s&lt;/strong&gt;, there being nothing else to pass: a
hook takes no arguments and hands nothing back.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { lmdbOpen, lmdbClose } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:lmdb

&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; store &lt;span class=&quot;hl-keyword&quot;&gt;=&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; wrote &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;@setupAll&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;open_the_store&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    store &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbOpen&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/counting&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, { mapSize&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1048576&lt;/span&gt; })

&lt;span class=&quot;hl-function&quot;&gt;@setup&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;start_from_nothing&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    wrote &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;@teardownAll&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;shut_the_store&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;lmdbClose&lt;/span&gt;(store)

&lt;span class=&quot;hl-function&quot;&gt;@test&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;a_write_is_counted&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    wrote &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; wrote &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;assertEq&lt;/span&gt;(wrote, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One of each to a file, and a second is refused where it is written&lt;/strong&gt;, naming both:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;error: a file has one `@setup` at most, and `first` is already it -- `second` would be the second
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the whole of the arrangement — there is no nesting, no group, and no way for one test to opt
out of the file’s setup. A test that wants something different is a test that belongs in a file of its
own, which costs nothing and reads better than a flag would.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A hook may be &lt;code&gt;async&lt;/code&gt;&lt;/strong&gt;, and is waited for the way an &lt;code&gt;async&lt;/code&gt; test is.&lt;/p&gt;
&lt;h3 id=&quot;when-one-of-them-goes-wrong&quot;&gt;When one of them goes wrong&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A fault in &lt;code&gt;@setup&lt;/code&gt; fails the test it was preparing, and the failure names the setup&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  FAIL  tests/store.sl :: a_write_is_counted   0ms
        `open_the_store` failed before this test ran
        error: the store would not open
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A fault in &lt;code&gt;@setupAll&lt;/code&gt; does that to &lt;strong&gt;every&lt;/strong&gt; test in the file, and a &lt;code&gt;skip&lt;/code&gt; in either leaves the test
out with the reason given — which is how a whole file says &lt;em&gt;this host is not for me&lt;/em&gt; once instead of in
every test.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;@teardown&lt;/code&gt; runs however the test went&lt;/strong&gt; — passed, failed or left out — because what it gives back
is exactly what a setup that stopped halfway had already taken. &lt;strong&gt;Its own fault is a failure of its
own&lt;/strong&gt;, counted on the last line under the teardown’s name rather than folded into the test or quietly
dropped: a passing test with a broken teardown is not a passing file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;@setup&lt;/code&gt;, the test it prepares and its &lt;code&gt;@teardown&lt;/code&gt; run on one event loop&lt;/strong&gt;, and each of the three
is waited for only as far as its own answer. So a socket the setup opened is still open while the test
runs, and a timer the test armed is still armed while the teardown runs — which is what makes
&lt;code&gt;clearTimeout&lt;/code&gt; in a teardown mean anything. The loop is let settle &lt;strong&gt;after&lt;/strong&gt; the teardown, and it waits
only for what the three of them left behind: whatever the file’s &lt;code&gt;@setupAll&lt;/code&gt; opened is the file’s, and
settles after its &lt;code&gt;@teardownAll&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;running-only-some-of-them&quot;&gt;Running only some of them&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--only &amp;lt;substring&amp;gt;&lt;/code&gt; runs the tests whose name contains it&lt;/strong&gt;, and nothing else:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ slate test tests --only clamp
  ok    examples/testing.sl :: clamp_lifts_a_small_number_to_the_floor   0ms

1 passed
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last line still counts what ran. &lt;strong&gt;A filter that matches nothing is a failure, not an empty
success&lt;/strong&gt; — the usual cause is a misspelling, and a test step that is green having run nothing is the
worst outcome available to it:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ slate test tests --only clmap

0 passed
slate: no test name contains &amp;quot;clmap&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A file with nothing chosen is not prepared&lt;/strong&gt;: its &lt;code&gt;@setupAll&lt;/code&gt; does not run, so a filter costs nothing
in a suite whose files each open a database.&lt;/p&gt;
&lt;h2 id=&quot;where-tests-live&quot;&gt;Where tests live&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Beside the code or in a file of their own&lt;/strong&gt;, and the difference is what they can reach. A slate module
is a &lt;em&gt;file&lt;/em&gt;, so a test beside the code sees what that file kept private, and a test file that imports the
module sees exactly what a reader of it sees. Both are ordinary &lt;code&gt;@test&lt;/code&gt; functions; nothing distinguishes
the two arrangements but where you put them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only the file being tested contributes its tests.&lt;/strong&gt; A test file that imports the module it tests does
not run that module’s tests a second time, so walking a directory runs each file’s tests exactly once.&lt;/p&gt;
&lt;h2 id=&quot;two-rules-worth-knowing&quot;&gt;Two rules worth knowing&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;async&lt;/code&gt; test is waited for.&lt;/strong&gt; Calling one hands back a promise that has not settled, so a runner that
read the answer straight away would call every asynchronous test a pass whatever it did.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Running a file plainly calls none of its tests&lt;/strong&gt;, so &lt;code&gt;@test&lt;/code&gt; costs a program that is not being tested
one closure and nothing else.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Statements</title>
    <link href="https://slatelang.dev/reference/statements/"/>
    <id>https://slatelang.dev/reference/statements/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>val cannot be assigned to again; var can. A val bound to an array or an object still allows that container to be changed — the binding is what is…</summary>
    <content type="html">&lt;h1 id=&quot;statements&quot;&gt;Statements&lt;/h1&gt;
&lt;h2 id=&quot;declarations&quot;&gt;Declarations&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name &lt;span class=&quot;hl-keyword&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;slate&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-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;val&lt;/code&gt; cannot be assigned to again; &lt;code&gt;var&lt;/code&gt; can.&lt;/strong&gt; A &lt;code&gt;val&lt;/code&gt; bound to an array or an object still allows
that container to be changed — the binding is what is fixed, not the value.&lt;/p&gt;
&lt;p&gt;Either may say what it holds, and an annotated &lt;code&gt;var&lt;/code&gt; is TypeScript’s &lt;code&gt;let&lt;/code&gt;: the declared type is what
the name holds for its whole life, so every assignment is checked against it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; name&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;slate&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-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

n &lt;span class=&quot;hl-keyword&quot;&gt;+=&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;(name, n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;slate 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/functions/&quot;&gt;definition&lt;/a&gt; is a statement too, and so are &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;class&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt;, each of which
belongs to the top level of a file.&lt;/p&gt;
&lt;h3 id=&quot;what-is-in-scope-where&quot;&gt;What is in scope where&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A definition is HOISTED to the top of the block it is written in&lt;/strong&gt;, which is JavaScript’s rule, so
a name may be used above the line that defines it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sink &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; written

&lt;span class=&quot;hl-function&quot;&gt;written&lt;/span&gt;(r) &lt;span class=&quot;hl-keyword&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;wrote &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(r)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sink&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;wrote 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;val&lt;/code&gt; or &lt;code&gt;var&lt;/code&gt; initialiser stays sequential&lt;/strong&gt; — it may read what is above it and not what is
below — and that is the half that matters: nothing about hoisting makes a program’s data flow depend
on where a function happens to sit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; b
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;=&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`b` is not defined
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The definitions run where they are hoisted&lt;/strong&gt;, so a statement standing between two of them is not
reordered around anything: only the binding moves, and what it binds is a function that has not been
called yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A definition may not take a name its own block has already declared&lt;/strong&gt;, whether by another
definition or by a &lt;code&gt;val&lt;/code&gt; or a &lt;code&gt;var&lt;/code&gt;. The hoisting is the reason: the two would not run in the order
they are written, so what the second one means depends on a rule the reader cannot see.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&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-function&quot;&gt;f&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&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;`f` is declared twice in this block
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;strong&gt;nested&lt;/strong&gt; block is its own, so shadowing an outer name is untouched — and a &lt;code&gt;val&lt;/code&gt; written &lt;em&gt;below&lt;/em&gt;
a definition is not a collision but the ordinary way to name a generator and then run it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counting&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&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; counting &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counting&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(counting&lt;span class=&quot;hl-keyword&quot;&gt;.&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;value, counting&lt;span class=&quot;hl-keyword&quot;&gt;.&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;value)&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;h2 id=&quot;assignment&quot;&gt;Assignment&lt;/h2&gt;
&lt;p&gt;Assignment is a &lt;strong&gt;statement&lt;/strong&gt;, never an expression, so &lt;code&gt;=&lt;/code&gt; cannot appear inside an expression and
there is nothing for it to be confused with.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&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-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-keyword&quot;&gt;=&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; o &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { f&lt;span class=&quot;hl-keyword&quot;&gt;:&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; a &lt;span class=&quot;hl-keyword&quot;&gt;=&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;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

n &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&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; &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;
o&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;f &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;
a, b &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; b, a                 &lt;span class=&quot;hl-comment&quot;&gt;// several places at once&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(n, xs, o, a, b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 [9, 2] {f: 9} 2 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Assignment binds nothing.&lt;/strong&gt; &lt;code&gt;g = 1&lt;/code&gt; where &lt;code&gt;g&lt;/code&gt; was never declared is refused before the program runs,
naming the nearest name it does know; &lt;code&gt;val&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt; are the only things that introduce a name.&lt;/p&gt;
&lt;p&gt;The compound forms are &lt;code&gt;+= -= *= /= %=&lt;/code&gt; and the bitwise &lt;code&gt;&amp;amp;= |= ^= &amp;lt;&amp;lt;= &amp;gt;&amp;gt;=&lt;/code&gt;. &lt;strong&gt;A compound form
evaluates its place once&lt;/strong&gt;, so &lt;code&gt;xs[next()] += 1&lt;/code&gt; calls &lt;code&gt;next&lt;/code&gt; a single time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;++&lt;/code&gt; and &lt;code&gt;--&lt;/code&gt; step a name, a field or an element, prefix or postfix.&lt;/p&gt;
&lt;h2 id=&quot;if&quot;&gt;&lt;code&gt;if&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(mark)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; mark &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;=&lt;/span&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; mark &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;=&lt;/span&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;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;20&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;A B C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The inline form takes &lt;code&gt;then&lt;/code&gt;, and &lt;strong&gt;its body is a statement, not an expression&lt;/strong&gt; — which is the rule
that makes the short forms worth having:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;first_big&lt;/span&gt;(xs)
    &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-keyword&quot;&gt;&amp;lt;=&lt;/span&gt; &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;continue&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&lt;/span&gt; &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; x

    &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-function&quot;&gt;first_big&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;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;]), &lt;span class=&quot;hl-function&quot;&gt;first_big&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;7 null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An &lt;code&gt;if&lt;/code&gt; is an expression when every branch answers one: &lt;code&gt;val g = if c then 1 else 2&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;loops&quot;&gt;Loops&lt;/h2&gt;
&lt;p&gt;Three of them, and &lt;strong&gt;every one is an expression&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&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-number&quot;&gt;3&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    c &lt;span class=&quot;hl-keyword&quot;&gt;-=&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; [&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;(x)

&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-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-keyword&quot;&gt;+=&lt;/span&gt; &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-keyword&quot;&gt;==&lt;/span&gt; &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;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c, n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
2
0 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;do&lt;/code&gt; introduces a one-line body — &lt;code&gt;while c do …&lt;/code&gt;, &lt;code&gt;for x in xs do …&lt;/code&gt;, &lt;code&gt;loop do …&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for await x in source&lt;/code&gt;&lt;/strong&gt; is the fourth, and it walks something that answers &lt;code&gt;next()&lt;/code&gt; a value at a
time — see &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;for&lt;/code&gt; head may take its element apart with a &lt;a href=&quot;/reference/patterns/&quot;&gt;pattern&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; [k, v] &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;entries&lt;/span&gt;({ a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&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, v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a 1
b 2
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;what-a-loop-answers&quot;&gt;What a loop answers&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;break&lt;/code&gt; is what gives a loop a value.&lt;/strong&gt; A loop that finishes on its own answers &lt;code&gt;null&lt;/code&gt;, or whatever
its &lt;code&gt;else&lt;/code&gt; clause left:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;find_first&lt;/span&gt;(xs, wanted)
    &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;&lt;span class=&quot;hl-keyword&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(xs) do
        if xs[i] == wanted then break i
    else
        -1
end find_first

print(find_first([4, 5, 6], 5), find_first([4, 5, 6], 9))&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;The &lt;code&gt;else&lt;/code&gt; clause runs when the loop ended without a &lt;code&gt;break&lt;/code&gt;, and its value &lt;strong&gt;is&lt;/strong&gt; the loop’s.&lt;/p&gt;
&lt;h3 id=&quot;labels&quot;&gt;Labels&lt;/h3&gt;
&lt;p&gt;A label says which loop a &lt;code&gt;break&lt;/code&gt; leaves, which is the only way out of a nested one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; found &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &apos;search &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; a &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;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; b &lt;span class=&quot;hl-keyword&quot;&gt;in&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;if&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;8&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;search [a, b]

&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-output&quot;&gt;[2, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;continue&lt;/code&gt; starts the next turn, and takes a label the same way.&lt;/p&gt;
&lt;h2 id=&quot;blocks&quot;&gt;Blocks&lt;/h2&gt;
&lt;p&gt;A block’s value is its trailing expression. &lt;code&gt;return&lt;/code&gt; is for leaving a function early and nothing else,
so a function whose last statement is its answer does not write one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count &lt;span class=&quot;hl-keyword&quot;&gt;=&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-keyword&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        count

    bump

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;c&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;c&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;c&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;h2 id=&quot;throw&quot;&gt;&lt;code&gt;throw&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;throw v&lt;/code&gt; is a statement, like &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;break&lt;/code&gt; — nothing after it runs, and the value is not
optional. See &lt;a href=&quot;/reference/faults/&quot;&gt;Faults&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;closing-words&quot;&gt;Closing words&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;end if&lt;/code&gt;, &lt;code&gt;end while&lt;/code&gt;, &lt;code&gt;end for&lt;/code&gt;, &lt;code&gt;end loop&lt;/code&gt;, and &lt;code&gt;end &amp;lt;name&amp;gt;&lt;/code&gt; for a definition, a class or a data
type. All are optional and all are for a block long enough to want one.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:sqlite</title>
    <link href="https://slatelang.dev/library/sqlite/"/>
    <id>https://slatelang.dev/library/sqlite/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>SQLite — the database that needs no server, and the one a program can have without asking anybody to install anything.</summary>
    <content type="html">&lt;h1 id=&quot;slatesqlite&quot;&gt;&lt;code&gt;slate:sqlite&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;SQLite — the database that needs no server, and the one a program can have without asking anybody to
install anything.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sqlite } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:sqlite

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; db &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sqlite&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:memory:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;exec&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;create table notes (id integer primary key, title text, weight real)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into notes (title, weight) values (?, ?)&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 note&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.5&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; put &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into notes (title) values (?)&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;another&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;(put&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;changes, put&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;lastInsertRowid)

&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; db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;select id, title from notes order by id&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;(row&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;id, row&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;title)

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&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-output&quot;&gt;1 2
1 a note
2 another
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sqlite(path)&lt;/code&gt; answers the database and everything else is a method on it, which is
&lt;a href=&quot;/library/redis/&quot;&gt;&lt;code&gt;slate:redis&lt;/code&gt;&lt;/a&gt;‘s shape and is the same one &lt;a href=&quot;https://github.com/slate-language/pg&quot;&gt;&lt;code&gt;pg&lt;/code&gt;&lt;/a&gt;
has — so the two databases a program might reach for do not have to be learned twice.&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;db.exec(sql)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;run every statement in the text, for its effect&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;db.query(sql, ...params)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the rows, each an object keyed by column name&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;db.run(sql, ...params)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{ changes, lastInsertRowid }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;db.transaction(work)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;everything &lt;code&gt;work&lt;/code&gt; did, or nothing of it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;db.compiledWith(option)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;whether this SQLite was built with a named option&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;db.close()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the statements go, and then the connection&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-path-is-sqlites-own-and-is-not-always-a-file&quot;&gt;The path is SQLite’s own, and is not always a file&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;:memory:&lt;/code&gt; is a private database living as long as the connection, which is what a test wants, and
&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; is a temporary one on disk that is deleted when the connection goes. Anything else is a path.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; db &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sqlite&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;notes.db&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, { busyTimeout&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;5000&lt;/span&gt; })

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;exec&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;create table if not exists notes (title text)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into notes (title) values (?)&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;kept&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;{ readOnly: true }&lt;/code&gt; opens a database that is already there&lt;/strong&gt; and fails where there is none, rather
than making an empty one. &lt;strong&gt;&lt;code&gt;{ busyTimeout: ms }&lt;/code&gt; is how long to wait for a lock&lt;/strong&gt; before giving up,
and is worth setting on anything more than one process writes to. Those are the two options there is,
and an option spelled any other way is refused by name rather than ignored.&lt;/p&gt;
&lt;h2 id=&quot;exec-runs-several-statements-and-query-runs-one&quot;&gt;&lt;code&gt;exec&lt;/code&gt; runs several statements and &lt;code&gt;query&lt;/code&gt; runs one&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;That is SQLite’s own behaviour rather than this module’s.&lt;/strong&gt; &lt;code&gt;sqlite3_prepare&lt;/code&gt; compiles the &lt;em&gt;first&lt;/em&gt;
statement in a piece of text and hands back a pointer to what is left — so a schema of six
&lt;code&gt;create table&lt;/code&gt;s run through &lt;code&gt;query&lt;/code&gt; would create one table and say nothing about the other five.
&lt;code&gt;exec&lt;/code&gt; walks that pointer, which is why it is the call a schema goes through.&lt;/p&gt;
&lt;h2 id=&quot;the-parameters-are-the-arguments-after-the-sql&quot;&gt;The parameters are the arguments after the SQL&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;db.query(sql, ...params)&lt;/code&gt;, and a list a program worked out is spread: &lt;code&gt;db.query(sql, ...values)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A parameter is never interpolated into the SQL.&lt;/strong&gt; SQLite compiles the statement before it is given
a single value, so nothing a parameter holds can become part of the query — &lt;code&gt;?&lt;/code&gt; is the whole of the
defence against injection, and there is no escaping function here because there is nothing to escape.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;?&lt;/code&gt; nobody bound is refused&lt;/strong&gt; rather than quietly bound to SQL NULL, which is what SQLite would
do: &lt;code&gt;where id = ?&lt;/code&gt; called with no parameter would otherwise run, match nothing, and say nothing.&lt;/p&gt;
&lt;h2 id=&quot;what-crosses-in-each-direction&quot;&gt;What crosses, in each direction&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;SQLite&lt;/th&gt;&lt;th&gt;slate&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;INTEGER&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an integer, read as 64 bits&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;a real&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;TEXT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;BLOB&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an array of bytes&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;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The type belongs to the value and not to the column.&lt;/strong&gt; SQLite is dynamically typed: a column
declared &lt;code&gt;integer&lt;/code&gt; holds whatever was put in it, and two rows of one column may differ — so what a
cell comes back as is decided per row, by what is actually stored there.&lt;/p&gt;
&lt;p&gt;Going out: text as itself, an integer and a real as themselves, &lt;code&gt;null&lt;/code&gt; as SQL NULL, &lt;code&gt;true&lt;/code&gt; and
&lt;code&gt;false&lt;/code&gt; as 1 and 0 (SQLite has no boolean storage class), and &lt;strong&gt;an array as a blob&lt;/strong&gt;. That last one is
simpler here than in PostgreSQL, which has both &lt;code&gt;int[]&lt;/code&gt; and &lt;code&gt;bytea&lt;/code&gt; and needs to be told which.&lt;/p&gt;
&lt;h2 id=&quot;a-transaction-commits-on-a-return-and-rolls-back-on-a-fault&quot;&gt;A transaction commits on a return and rolls back on a fault&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sqlite } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:sqlite

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; db &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sqlite&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:memory:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;exec&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;create table notes (title 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;move&lt;/span&gt;()
    db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into notes (title) values (&apos;a&apos;)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

    &lt;span class=&quot;hl-keyword&quot;&gt;throw&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 went wrong&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;(db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;transaction&lt;/span&gt;(move) &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;message)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;select count(*) as n from notes&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-keyword&quot;&gt;.&lt;/span&gt;n)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;something went wrong
0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The rollback path is the one a program forgets&lt;/strong&gt;, and that is the whole argument for the method: a
failure between &lt;code&gt;begin&lt;/code&gt; and &lt;code&gt;commit&lt;/code&gt; that simply returns leaves the transaction open, holding its
locks, until the connection closes. Here the fault is caught, the transaction is undone, and the fault
carries on with its own words.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SQLite has no nested transactions&lt;/strong&gt;, so a &lt;code&gt;transaction&lt;/code&gt; inside a &lt;code&gt;transaction&lt;/code&gt; is refused by the
database rather than counted.&lt;/p&gt;
&lt;h2 id=&quot;statements-are-prepared-once-and-kept&quot;&gt;Statements are prepared once and kept&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;query&lt;/code&gt; and &lt;code&gt;run&lt;/code&gt; take the SQL rather than a statement object, and the connection keeps what it
compiled — so parsing and planning happen once per piece of SQL for the life of the connection and a
program gets that without holding anything. The cache is bounded, the oldest statement going when the
room runs out, so a program that builds its SQL as text in a loop does not accumulate one per string.&lt;/p&gt;
&lt;h2 id=&quot;full-text-search-where-the-machines-sqlite-has-it&quot;&gt;Full-text search, where the machine’s SQLite has it&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What SQLite can do is a property of the machine&lt;/strong&gt;, it being the library the machine supplies rather
than one slate carries. &lt;code&gt;db.compiledWith(&amp;quot;ENABLE_FTS5&amp;quot;)&lt;/code&gt; is how a program asks — the &lt;code&gt;SQLITE_&lt;/code&gt; prefix
is optional — and the alternative is finding out at the &lt;code&gt;create virtual table&lt;/code&gt;, which fails with
&lt;code&gt;no such module: fts5&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sqlite } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:sqlite

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; db &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sqlite&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:memory:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;exec&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;create virtual table search using fts5(body)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into search (body) values (?)&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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
db&lt;span class=&quot;hl-keyword&quot;&gt;.&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;insert into search (body) values (?)&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 lazy dog sleeping&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; hits &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;query&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;select body, bm25(search) as score from search where search match ? order by score&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;fox&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;len&lt;/span&gt;(hits), hits[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;body)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(hits[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;score &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;real&lt;/span&gt;, hits[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;score &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&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;1 the quick brown fox
true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;bm25&lt;/code&gt; is negative&lt;/strong&gt;, FTS5 ordering a better match first by making its score smaller.&lt;/p&gt;
&lt;h2 id=&quot;faults-not-results&quot;&gt;Faults, not results&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Everything here faults with a sentence&lt;/strong&gt;, which is the one place slate’s rule reads the other way
round. The rule is that &lt;a href=&quot;/reference/faults/&quot;&gt;text from outside the program is an answer and a value the program built
itself is a fault&lt;/a&gt; — and a local database is on the second side of that line
nearly everywhere it can fail: the SQL is in the program, the number of parameters is a property of
that SQL, and a call on a closed database is a mistake in the order the program did things.
&lt;a href=&quot;https://github.com/slate-language/pg&quot;&gt;&lt;code&gt;pg&lt;/code&gt;&lt;/a&gt; answers a result instead, and the difference is the
machine: a server that is down, a password that is wrong and a role that does not exist are all
conditions a program was always going to handle.&lt;/p&gt;
&lt;p&gt;A program that wants an answer rather than a fault writes &lt;code&gt;catch&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; rows &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; db&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;query&lt;/span&gt;(sql) &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; []&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;both-hosts-have-it&quot;&gt;Both hosts have it&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;node has carried &lt;code&gt;node:sqlite&lt;/code&gt; since 22.5&lt;/strong&gt;, so this module is whole under &lt;code&gt;slate js&lt;/code&gt; as well as
here — the same object with the same methods, over node’s own copy of SQLite rather than the
machine’s. &lt;code&gt;tests/js/p28.sl&lt;/code&gt; is what says the two agree: the storage classes, the transaction, the
full-text search and every sentence either back end says about SQL it will not take.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;node writes one line to stderr the first time a program here opens a database&lt;/strong&gt; —
&lt;code&gt;ExperimentalWarning: SQLite is an experimental feature&lt;/code&gt; — which is node’s and not slate’s, and
&lt;code&gt;node --no-warnings&lt;/code&gt; silences it. It is written at the first call rather than when the program starts,
so a program that never opens a database never draws it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A browser has no SQLite and &lt;code&gt;node:sqlite&lt;/code&gt; is not coming to one&lt;/strong&gt; — what a page has instead is
IndexedDB and the long-deprecated Web SQL, neither of which is this — so the module refuses there
naming node’s module, exactly as &lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt; does.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two builds of SQLite are two builds&lt;/strong&gt;, so a version number, a &lt;code&gt;bm25&lt;/code&gt; score and anything else the
library is free to change between releases are properties of the machine rather than claims about
slate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The one such difference worth knowing about is &lt;code&gt;&amp;quot;double quotes&amp;quot;&lt;/code&gt;.&lt;/strong&gt; SQL says a double-quoted word is
an &lt;em&gt;identifier&lt;/em&gt;, and SQLite has a long-standing misfeature where one that matches no column is taken as
a string literal instead — on by default in the build macOS ships and off in node’s, which sets
&lt;code&gt;SQLITE_DQS=0&lt;/code&gt;. So &lt;code&gt;select &amp;quot;hello&amp;quot;&lt;/code&gt; answers the text &lt;code&gt;hello&lt;/code&gt; under the interpreter and
&lt;code&gt;no such column: &amp;quot;hello&amp;quot;&lt;/code&gt; under &lt;code&gt;slate js&lt;/code&gt;. &lt;strong&gt;Write a string literal in single quotes&lt;/strong&gt;, which is what
SQL says and what both builds agree about.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:regex</title>
    <link href="https://slatelang.dev/library/regex/"/>
    <id>https://slatelang.dev/library/regex/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>PCRE2 patterns. One export, because a pattern is one object and everything a program does with it is a method on that object.</summary>
    <content type="html">&lt;h1 id=&quot;slateregex&quot;&gt;&lt;code&gt;slate:regex&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;PCRE2 patterns. &lt;strong&gt;One export, because a pattern is one object and everything a program does with it is a
method on that object.&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;regex&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:regex

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; re &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&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-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;d+)-(&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;d+)&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; text &lt;span class=&quot;hl-keyword&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;a 10-20 b 30-40&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;test&lt;/span&gt;(text))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(re&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(text)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;groups)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(re&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(text)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;start, re&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(text)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;end&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(re&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;replace&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;$2-$1&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;replaceFirst&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;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;(re&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;pattern&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
[&amp;quot;10-20&amp;quot;, &amp;quot;10&amp;quot;, &amp;quot;20&amp;quot;]
2 7
a 20-10 b 40-30
a x b 30-40
(\d+)-(\d+)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Asking for a &lt;code&gt;g&lt;/code&gt; flag is refused by name, since a flag silently ignored would make &lt;code&gt;replace&lt;/code&gt; look like
it had worked for the wrong reason:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;regex&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;g&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;g
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The flags are &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;m&lt;/code&gt;, &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;x&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;a-match-is-an-ordinary-object&quot;&gt;A match is an ordinary object&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;text&lt;/code&gt;, &lt;code&gt;start&lt;/code&gt;, &lt;code&gt;end&lt;/code&gt;, &lt;code&gt;groups&lt;/code&gt; and &lt;code&gt;named&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;groups&lt;/code&gt; has the whole match at 0&lt;/strong&gt;, and &lt;strong&gt;&lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; for a group that took no part.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;named&lt;/code&gt; is always present and empty where the pattern names nothing.&lt;/strong&gt; A field that appears only
sometimes is one a program must test for before reading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every offset is in characters&lt;/strong&gt;, as everywhere else in slate — PCRE2 answers in bytes and the whole
slot array is converted in one pass.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;three-of-javascripts-decisions-are-reversed&quot;&gt;Three of JavaScript’s decisions are reversed&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;slate&lt;/th&gt;&lt;th&gt;JavaScript, and what it costs&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a pattern carries no position&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;a &lt;code&gt;/g&lt;/code&gt; pattern holds a mutable &lt;code&gt;lastIndex&lt;/code&gt;, so &lt;code&gt;re.test(s)&lt;/code&gt; twice on one string is &lt;code&gt;true&lt;/code&gt; then &lt;code&gt;false&lt;/code&gt; — visible only on the second call&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;&lt;code&gt;replace&lt;/code&gt; replaces every match&lt;/strong&gt;, &lt;code&gt;replaceFirst&lt;/code&gt; stops&lt;/td&gt;&lt;td&gt;a bare &lt;code&gt;replace&lt;/code&gt; changes the first only unless &lt;code&gt;/g&lt;/code&gt; is set, which is why &lt;code&gt;replaceAll&lt;/code&gt; had to be added two decades later&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;a match that would backtrack forever is a fault&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;no limit at all, so a crafted subject stops a server answering&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;g&lt;/code&gt; flag&lt;/strong&gt;, and asking for one is refused &lt;em&gt;by name&lt;/em&gt; with the sentence saying what to do
instead — a flag silently ignored would make &lt;code&gt;replace&lt;/code&gt; look like it had worked for the wrong reason.&lt;/p&gt;
&lt;h2 id=&quot;two-dialect-points&quot;&gt;Two dialect points&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;$&lt;/code&gt; is the very end&lt;/strong&gt; rather than also the position before a final newline, and &lt;strong&gt;&lt;code&gt;\d&lt;/code&gt; is &lt;code&gt;[0-9]&lt;/code&gt;&lt;/strong&gt;
rather than every decimal digit in Unicode. Both are settled here so that a pattern means one thing
wherever it runs — each is a place PCRE2 and JavaScript would otherwise disagree silently, compiling
either way and merely matching something else. A program wanting Unicode digits writes &lt;code&gt;\p{Nd}&lt;/code&gt;, which
works regardless.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Under &lt;code&gt;slate js&lt;/code&gt; a pattern is translated into &lt;code&gt;RegExp&lt;/code&gt;&lt;/strong&gt;, and the same rule decides everything there:
&lt;code&gt;\s&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;^&lt;/code&gt;/&lt;code&gt;$&lt;/code&gt; under &lt;code&gt;m&lt;/code&gt; all mean something else to a browser and are written out so that they do
not. A handful of PCRE2 constructs a browser has nothing to mean — a possessive quantifier, an atomic
group, recursion, &lt;code&gt;\K&lt;/code&gt; — are refused where the pattern is written, naming the construct.
&lt;a href=&quot;/reference/javascript/&quot;&gt;The JavaScript page&lt;/a&gt; has the measurements and the three differences that
are left standing, of which the backtracking budget above is one: &lt;code&gt;RegExp&lt;/code&gt; has no such limit in any
browser.&lt;/p&gt;
&lt;h2 id=&quot;equality&quot;&gt;Equality&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An identical pattern compiles once&lt;/strong&gt;, so &lt;code&gt;regex(&amp;quot;a&amp;quot;) == regex(&amp;quot;a&amp;quot;)&lt;/code&gt; is &lt;strong&gt;true&lt;/strong&gt; where two arrays written
the same way are equal by contents but two compiled patterns would not otherwise have been. That falls out
of interning rather than being a decision about equality.&lt;/p&gt;
&lt;p&gt;There is no way to release a pattern, and none is needed: a slot names the same pattern for as long as the
program runs, so a loop writing &lt;code&gt;regex(&amp;quot;\\d+&amp;quot;)&lt;/code&gt; costs one entry and not one per turn.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:redis</title>
    <link href="https://slatelang.dev/library/redis/"/>
    <id>https://slatelang.dev/library/redis/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>A Redis client on the event loop.</summary>
    <content type="html">&lt;h1 id=&quot;slateredis&quot;&gt;&lt;code&gt;slate:redis&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;A Redis client on the event loop.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { redis } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:redis

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;redis&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;6379&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;command&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;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;greeting&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;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-keyword&quot;&gt;await&lt;/span&gt; r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;command&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;GET&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;greeting&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)

r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;onPush&lt;/span&gt;(m &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;pushed:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, m))

r&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One export, because a connection is one object&lt;/strong&gt; and everything else is a method on it. That is
&lt;a href=&quot;/library/regex/&quot;&gt;&lt;code&gt;slate:regex&lt;/code&gt;&lt;/a&gt;‘s shape. &lt;code&gt;redis&lt;/code&gt; is also what &lt;code&gt;connect&lt;/code&gt; had to become, &lt;a href=&quot;/library/net/&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;&lt;/a&gt;
exporting that name and a program with a Redis client in it having sockets in it.&lt;/p&gt;
&lt;h2 id=&quot;the-transport-is-slates&quot;&gt;The transport is slate’s&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Only the reply parser is bound.&lt;/strong&gt; The reader is fed bytes and answers replies and never opens, reads or
writes a socket — so the transport stays on the same loop that is answering HTTP, and &lt;strong&gt;a Redis client in a
server cannot stop the server.&lt;/strong&gt; Binding a blocking &lt;code&gt;redisCommand&lt;/code&gt; would have made that impossible rather
than merely difficult.&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-get-and-no-set&quot;&gt;There is no &lt;code&gt;get&lt;/code&gt; and no &lt;code&gt;set&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Redis has some 240 commands and grows more each release, so a client that named them would be a list to keep
current and a wall between a program and anything new.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;command&lt;/code&gt; gathers its words&lt;/strong&gt; — &lt;code&gt;r.command(...parts)&lt;/code&gt; for a computed one — and &lt;strong&gt;every argument crosses as
a counted string&lt;/strong&gt;, so a value holding CRLF or what looks like a whole second command is still one argument
and there is nothing to escape.&lt;/p&gt;
&lt;h2 id=&quot;the-rules&quot;&gt;The rules&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A command answers a result and a closed client throws.&lt;/strong&gt; &lt;code&gt;-ERR&lt;/code&gt; is the server refusing and a connection
that has gone is an outside condition; calling &lt;code&gt;command&lt;/code&gt; after &lt;code&gt;close&lt;/code&gt; is the program’s own mistake.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every waiting promise is settled when the connection goes&lt;/strong&gt;, with a result rather than a failure — a
program awaiting an answer it will never get would otherwise wait for the rest of the run, which in a
server is a request that never finishes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A push is never matched against a waiting command.&lt;/strong&gt; A pub/sub message arrives &lt;em&gt;between&lt;/em&gt; replies to your
own commands, so a client that assumed every reply was its own would hand a subscriber’s message back as
the answer to a &lt;code&gt;GET&lt;/code&gt; — silently, both being good replies. &lt;code&gt;r.onPush(f)&lt;/code&gt; is where they go.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pipelining is what happens when you do not await.&lt;/strong&gt; RESP has no request ids because answers come back in
the order the commands were written, so issuing several and awaiting them afterwards costs one round trip.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A protocol failure ends the connection&lt;/strong&gt; rather than being stepped over. The two ends disagree about
where a reply begins, so nothing after it can be trusted.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>slate:process</title>
    <link href="https://slatelang.dev/library/process/"/>
    <id>https://slatelang.dev/library/process/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Another program, this program’s own environment, and being asked to stop.</summary>
    <content type="html">&lt;h1 id=&quot;slateprocess&quot;&gt;&lt;code&gt;slate:process&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Another program, this program’s own environment, and being asked to stop.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { env, args } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:process

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(args, &lt;span class=&quot;hl-function&quot;&gt;env&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-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;env&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_VARIABLE_HERE&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;[] true null
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;stderr&quot;&gt;&lt;code&gt;stderr&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;print&lt;/code&gt; is the answer a program produces and &lt;code&gt;stderr&lt;/code&gt; is what it says about producing it&lt;/strong&gt;, which is
the division every shell already makes: &lt;code&gt;slate app.sl &amp;gt; answers.txt&lt;/code&gt; keeps the answers in the file and
lets the complaints through to the terminal.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { stderr } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:process

&lt;span class=&quot;hl-function&quot;&gt;stderr&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;could not reach the database, retrying&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;ul&gt;
&lt;li&gt;&lt;strong&gt;It takes as many values as &lt;code&gt;print&lt;/code&gt; does&lt;/strong&gt; and separates them the same way, and answers nothing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The newline is yours&lt;/strong&gt;, as node’s &lt;code&gt;process.stderr.write&lt;/code&gt; leaves it: a program writing a JSON object
per line and one drawing a progress bar want different answers, and only one of them can be the
default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It writes straight to the descriptor and does not wait.&lt;/strong&gt; A complaint is the one thing a program may
need to have said before the next line runs — a crash after an &lt;code&gt;await&lt;/code&gt; would lose it — so this is
synchronous, exactly as &lt;code&gt;print&lt;/code&gt; is.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;args-and-exit&quot;&gt;&lt;code&gt;args&lt;/code&gt; and &lt;code&gt;exit&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;#!/usr/bin/env slate&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { args, exit } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:process

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; args&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;==&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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;usage: greet &amp;lt;name&amp;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;exit&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; name &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; args
    &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; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; name &lt;span class=&quot;hl-keyword&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;!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;args&lt;/code&gt; is a value, not a call&lt;/strong&gt;, and it holds only what came after the program’s name — so &lt;code&gt;args[0]&lt;/code&gt; is
the first thing a person typed. That is where slate parts from C, node and Python, all three of which
hand a program its whole command line and begin by skipping past themselves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;exit(status)&lt;/code&gt; stops the program and tells the shell what it came to.&lt;/strong&gt; Everything printed before it is
still printed, a &lt;code&gt;try&lt;/code&gt; between it and the top cannot swallow it, and &lt;strong&gt;a status outside 0–255 is refused
rather than truncated&lt;/strong&gt; — a shell keeps the low eight bits, so an unexamined &lt;code&gt;exit(256)&lt;/code&gt; is a program
that says it failed and is recorded as having succeeded.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;slate reads no argument of its own after the program’s name&lt;/strong&gt;, so a script’s own options are safe to
invent.&lt;/li&gt;
&lt;li&gt;Without an &lt;code&gt;exit&lt;/code&gt;, a program that ran answers &lt;code&gt;0&lt;/code&gt; and one that faulted answers &lt;code&gt;1&lt;/code&gt;. &lt;code&gt;slate&lt;/code&gt; itself
answers &lt;code&gt;2&lt;/code&gt; when it could not work out what it was being asked to do.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;env&quot;&gt;&lt;code&gt;env&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;env(name)&lt;/code&gt; answers &lt;code&gt;string | null&lt;/code&gt;. &lt;code&gt;?? &amp;quot;&amp;quot;&lt;/code&gt; is what a program writes.&lt;/p&gt;
&lt;h2 id=&quot;run&quot;&gt;&lt;code&gt;run&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;run&lt;/span&gt;(cmd, args, options)       &lt;span class=&quot;hl-comment&quot;&gt;// { status, signal, out, err } or an error&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Options are &lt;code&gt;{ cwd, env, timeout }&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A child that ran and failed is a success with a non-zero status; an error means there was no child.&lt;/strong&gt;
That is what lets a caller tell “the program said no” from “there is no such program”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A signal is &lt;code&gt;null&lt;/code&gt;, never &lt;code&gt;0&lt;/code&gt;&lt;/strong&gt;, since 0 is a status a program can exit with.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Settling waits for three things&lt;/strong&gt;: the child exiting and &lt;em&gt;both&lt;/em&gt; pipes reaching end of file. A child can
exit with output still in the pipe, so settling on the exit alone hands back a truncated answer that
looks whole.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The child’s stdin is closed, not inherited.&lt;/strong&gt; An inherited descriptor has the child competing with
slate for the terminal, and a child waiting on input nobody will type is a hang with nothing on screen.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;env&lt;/code&gt; replaces the child’s environment.&lt;/strong&gt; A program that wants to add a variable reads it with
&lt;code&gt;env(name)&lt;/code&gt; and passes it through; one that wants an empty environment has no other way to say so.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A timeout sends &lt;code&gt;SIGKILL&lt;/code&gt;&lt;/strong&gt;, a timeout being the caller saying they will not wait any longer and a
signal the child may ignore leaving the promise pending exactly as it was.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output that is not text fails the call&lt;/strong&gt; rather than being replaced or mangled.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;signals&quot;&gt;Signals&lt;/h2&gt;
&lt;p&gt;A program that leaves a socket open never exits, so a server ends only from the inside — and every way a
deployment has of asking one to stop is a signal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { onSignal } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:process
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { serve, close } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:http

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8080&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&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-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;onSignal&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SIGTERM&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;gt;&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;shutting down&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(server))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;SIGTERM&lt;/code&gt; is what a container stopping and a &lt;code&gt;systemd&lt;/code&gt; unit restarting both send; &lt;code&gt;SIGINT&lt;/code&gt; is Ctrl-C.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The handler is an ordinary function at an ordinary time.&lt;/strong&gt; It runs between one turn of the loop and the
next, so nothing about it is restricted the way a C signal handler is: it may print, allocate, close a
socket, start a timer, and take as long as the shutdown needs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It is handed nothing, and the registration is what names the signal.&lt;/strong&gt; slate checks the count of a
call’s arguments, so a name passed to every handler would be a parameter almost none of them would read;
a program that wants one function for two signals registers it twice.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A watcher does not keep the program alive.&lt;/strong&gt; A script that installs a handler and does nothing else
still ends. What keeps a server running is the server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;onSignal&lt;/code&gt; answers an id and &lt;code&gt;offSignal(id)&lt;/code&gt; stops that handler. Stopping one twice is not an error.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;SIGKILL&lt;/code&gt; and &lt;code&gt;SIGSTOP&lt;/code&gt; are refused by name&lt;/strong&gt; — the kernel acts on those itself and nothing a program
says will run first.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>Patterns</title>
    <link href="https://slatelang.dev/reference/patterns/"/>
    <id>https://slatelang.dev/reference/patterns/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>One grammar, used in four places: a match arm, an is test, a binding (val { a } = o), and a parameter that takes its argument apart.</summary>
    <content type="html">&lt;h1 id=&quot;patterns&quot;&gt;Patterns&lt;/h1&gt;
&lt;p&gt;One grammar, used in four places: a &lt;code&gt;match&lt;/code&gt; arm, an &lt;code&gt;is&lt;/code&gt; test, a binding (&lt;code&gt;val { a } = o&lt;/code&gt;), and a
&lt;a href=&quot;/reference/functions/&quot;&gt;parameter&lt;/a&gt; that takes its argument apart.&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;match&lt;/code&gt; is postfix — a transformation of the thing to its left. A guard runs after the pattern has
bound:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    { kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&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;-&amp;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;origin&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    { kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; [x, y] } &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; y &lt;span class=&quot;hl-keyword&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-string&quot;&gt;diagonal&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    [first, &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;rest] &lt;span class=&quot;hl-keyword&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-string&quot;&gt;a list starting &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(first)
    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sat&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;sun&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;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;a weekend&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-string&quot;&gt;a negative number&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-keyword&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-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;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;({ kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&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;classify&lt;/span&gt;({ kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&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;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&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-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;classify&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sun&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-keyword&quot;&gt;-&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;classify&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;origin
diagonal
a list starting 9
a weekend
a negative number
something else
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Arms are tried in order. &lt;strong&gt;A subject matching no arm is a fault&lt;/strong&gt;, as Scala’s &lt;code&gt;MatchError&lt;/code&gt; is.&lt;/p&gt;
&lt;p&gt;An arm’s body may be an expression or an indented block, and the inline &lt;code&gt;then&lt;/code&gt; forms work inside one.&lt;/p&gt;
&lt;h2 id=&quot;what-binds-and-what-tests&quot;&gt;What binds and what tests&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A bare name in a pattern tests for a kind where it names one, and binds otherwise.&lt;/strong&gt; The kind words
are:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;null  boolean  integer  real  number  string  array  object  function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;plus &lt;code&gt;promise&lt;/code&gt;, &lt;code&gt;generator&lt;/code&gt;, &lt;code&gt;regex&lt;/code&gt;, &lt;code&gt;shape&lt;/code&gt;, and the eight &lt;a href=&quot;/library/time/&quot;&gt;temporal&lt;/a&gt; words —
&lt;code&gt;instant&lt;/code&gt;, &lt;code&gt;duration&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;dateTime&lt;/code&gt;, &lt;code&gt;zone&lt;/code&gt;, &lt;code&gt;zoned&lt;/code&gt;, &lt;code&gt;period&lt;/code&gt;. That is the whole list:
twenty-one words. Every &lt;a href=&quot;/reference/types/&quot;&gt;type&lt;/a&gt;, &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; and &lt;a href=&quot;/reference/data-types/&quot;&gt;data variant&lt;/a&gt;
declared in the file adds its own name to it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;None of them is a keyword.&lt;/strong&gt; &lt;code&gt;val int = 3&lt;/code&gt; and &lt;code&gt;val date = readIt()&lt;/code&gt; are ordinary bindings; the words
are read this way in pattern position and nowhere else. What it costs is real: a &lt;code&gt;match&lt;/code&gt; arm may no
longer bind a name spelled &lt;code&gt;date&lt;/code&gt; or &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;number&lt;/code&gt; is the one word that is not a kind, being the union of &lt;code&gt;integer&lt;/code&gt; and &lt;code&gt;real&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;_&lt;/code&gt; matches anything and binds nothing.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;@&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;n @ pat&lt;/code&gt; tests and names at once:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    n &lt;span class=&quot;hl-keyword&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;the negative number &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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    p &lt;span class=&quot;hl-keyword&quot;&gt;@&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, y } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;p&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; is on the y axis at &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;y&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-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-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;(&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-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;tell&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&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;the negative number -4
{x: 0, y: 3} is on the y axis at 3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A broad guard is why this matters.&lt;/strong&gt; &lt;code&gt;n if n &amp;lt; 0&lt;/code&gt; binds &lt;em&gt;anything&lt;/em&gt;, so the guard evaluates
&lt;code&gt;[3, 4] &amp;lt; 0&lt;/code&gt; and faults; &lt;code&gt;n @ number if n &amp;lt; 0&lt;/code&gt; cannot reach the guard with the wrong kind.&lt;/p&gt;
&lt;h2 id=&quot;-and-&quot;&gt;&lt;code&gt;|&lt;/code&gt; and &lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;|&lt;/code&gt; is alternation. &lt;strong&gt;No alternative may bind a name&lt;/strong&gt;, since it would be bound down one path and not
the other:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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;sun&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;sat&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;sun&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;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;a weekend&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-keyword&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-string&quot;&gt;a working day&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 weekend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An alternative that binds is refused where it is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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-keyword&quot;&gt;match&lt;/span&gt;
    a &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;an alternative of a pattern may not bind a name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&lt;/code&gt; is its dual, binds tighter, and &lt;strong&gt;may&lt;/strong&gt; bind — every part of an intersection runs, so both names
are bound down the one path that matched:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    { a } &lt;span class=&quot;hl-keyword&quot;&gt;&amp;amp;&lt;/span&gt; { b } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;a&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-variable&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;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-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;both&lt;/span&gt;({ a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; }), &lt;span class=&quot;hl-function&quot;&gt;both&lt;/span&gt;({ a&lt;span class=&quot;hl-keyword&quot;&gt;:&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 2 no
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;object-patterns&quot;&gt;Object patterns&lt;/h2&gt;
&lt;p&gt;An object pattern matches an object with &lt;strong&gt;at least&lt;/strong&gt; those fields, because a record grows fields over
its life.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Note&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { title&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;?:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;boolean&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;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;is&lt;/span&gt; Note)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Note)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ title&lt;span class=&quot;hl-keyword&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;a&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, pinned&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Note)        &lt;span class=&quot;hl-comment&quot;&gt;// present, and does not fit&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;{ name: n }&lt;/code&gt; binds &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;{ name }&lt;/code&gt; is shorthand for &lt;code&gt;{ name: name }&lt;/code&gt;, and &lt;code&gt;{ pinned? }&lt;/code&gt; is a field
the subject need not have.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A field a proto supplies counts&lt;/strong&gt;, a pattern asking whether the value &lt;em&gt;has&lt;/em&gt; the field — which is the
question &lt;code&gt;.&lt;/code&gt; answers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;=&lt;/code&gt; is for a pattern that binds and &lt;code&gt;?&lt;/code&gt; is for one that tests&lt;/strong&gt;, and each is refused where the other
belongs.&lt;/p&gt;
&lt;h2 id=&quot;array-patterns&quot;&gt;Array patterns&lt;/h2&gt;
&lt;p&gt;An array pattern tests the elements it writes and lets the rest through:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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;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-keyword&quot;&gt;is&lt;/span&gt; [&lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;])

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; [first, &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;rest] &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(first, rest)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
1 [2, 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;bindings&quot;&gt;Bindings&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;val&lt;/code&gt; or a &lt;code&gt;var&lt;/code&gt; may take its value apart:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; { title } &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { title&lt;span class=&quot;hl-keyword&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;t&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, extra&lt;span class=&quot;hl-keyword&quot;&gt;:&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; [first, second] &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(title, first, second)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;t 10 20
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;is&quot;&gt;&lt;code&gt;is&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;is&lt;/code&gt; puts a pattern where a condition is wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(v &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, v &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; not &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, v &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&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;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Point)&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;h2 id=&quot;exhaustiveness&quot;&gt;Exhaustiveness&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Exhaustiveness is checked exactly where the value’s shape was written down, and nowhere else.&lt;/strong&gt; slate
is dynamically typed, so for an unannotated subject the set of values a name may hold is not known and
nothing useful can be said.&lt;/p&gt;
&lt;p&gt;What &lt;a href=&quot;/reference/data-types/&quot;&gt;&lt;code&gt;data&lt;/code&gt;&lt;/a&gt; adds is a closed list of variants, so a &lt;code&gt;match&lt;/code&gt; over a subject annotated
with one is checked against it and &lt;strong&gt;every variant left out is named&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;data&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-function&quot;&gt;Rect&lt;/span&gt;(w, h)
    Empty

&lt;span class=&quot;hl-function&quot;&gt;sides&lt;/span&gt;(s&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Shape) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
    Empty &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;sides&lt;/span&gt;(&lt;span class=&quot;hl-function&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;sides&lt;/span&gt;(&lt;span class=&quot;hl-function&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;sides&lt;/span&gt;(Empty))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 4 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A variant left out is named where the &lt;code&gt;match&lt;/code&gt; is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;data&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-function&quot;&gt;Rect&lt;/span&gt;(w, h)
    Empty

&lt;span class=&quot;hl-function&quot;&gt;sides&lt;/span&gt;(s&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Shape) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;this match does not cover
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;_&lt;/code&gt; arm is how a program says it has finished listing.&lt;/p&gt;
&lt;h2 id=&quot;class-and-variant-patterns&quot;&gt;Class and variant patterns&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; name or a &lt;a href=&quot;/reference/data-types/&quot;&gt;data variant&lt;/a&gt; written with fields after it tests and
takes apart in one breath — by position, or by name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; side

&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; radius

&lt;span class=&quot;hl-keyword&quot;&gt;class&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; w
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h

&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;a square of side &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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    Circle { radius&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; r } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;a circle of &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;r&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    Rect { w, h } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;w&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;h&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-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-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;(&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Square&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;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Circle&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;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&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;5&lt;/span&gt;)))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;tell&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-output&quot;&gt;a square of side 3
a circle of 7
2 by 5
something else
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The positional order is the constructor’s&lt;/strong&gt;, and holds by construction: the field list a pattern is
checked against &lt;em&gt;is&lt;/em&gt; the parameter list of the &lt;code&gt;new&lt;/code&gt; the class was given.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Naming the class is also what lets a misspelled field be caught.&lt;/strong&gt; A bare &lt;code&gt;{ raduis: r }&lt;/code&gt; is a legal
pattern that never matches — any object may lack any field — so the arm is silently dead. Written
after a class name there is a declaration to check it against, and it is refused where it stands.&lt;/p&gt;
&lt;p&gt;Both forms nest, both take an &lt;code&gt;@&lt;/code&gt; binding, and the test is the &lt;strong&gt;proto walk&lt;/strong&gt; — so a pattern written
for a base class takes an object of a class descended from it apart.&lt;/p&gt;
&lt;h2 id=&quot;types-in-patterns&quot;&gt;Types in patterns&lt;/h2&gt;
&lt;p&gt;A &lt;a href=&quot;/reference/types/&quot;&gt;&lt;code&gt;type&lt;/code&gt;&lt;/a&gt; name in pattern position is replaced by the pattern the type declared, while the
program is compiled:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Point)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Point)&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;Nothing of a type’s structure exists at run time&lt;/strong&gt;, so a type costs no instruction. A type may not
bind a name — &lt;code&gt;type Tagged = { x: n }&lt;/code&gt; is refused — for the reason &lt;code&gt;|&lt;/code&gt; may not.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Packages</title>
    <link href="https://slatelang.dev/reference/packages/"/>
    <id>https://slatelang.dev/reference/packages/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>A package is named by an unquoted specifier:</summary>
    <content type="html">&lt;h1 id=&quot;packages&quot;&gt;Packages&lt;/h1&gt;
&lt;p&gt;A package is named by an &lt;strong&gt;unquoted&lt;/strong&gt; specifier:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { mount } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath              &lt;span class=&quot;hl-comment&quot;&gt;// the package&apos;s own `main`&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { domHost } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath&lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt;dom        &lt;span class=&quot;hl-comment&quot;&gt;// one of its other modules&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;$ slate add github.com/slate-language/lath
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-manifest&quot;&gt;The manifest&lt;/h2&gt;
&lt;p&gt;A project or a package is a directory holding a &lt;strong&gt;&lt;code&gt;package.sl&lt;/code&gt;&lt;/strong&gt;, which is a slate object literal:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;{
    name&lt;span class=&quot;hl-keyword&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;lath&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,
    version&lt;span class=&quot;hl-keyword&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;0.2.0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,

    &lt;span class=&quot;hl-comment&quot;&gt;// What a bare `import ... from lath` reaches.&lt;/span&gt;
    main&lt;span class=&quot;hl-keyword&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;lath.slx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,

    &lt;span class=&quot;hl-comment&quot;&gt;// The other modules a consumer may name, `lath/&amp;lt;key&amp;gt;`.&lt;/span&gt;
    modules&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; {
        dom&lt;span class=&quot;hl-keyword&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;dom.slx&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;,
    },

    dependencies&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; {
        pg&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { git&lt;span class=&quot;hl-keyword&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;github.com/slate-language/pg&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, version&lt;span class=&quot;hl-keyword&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;0.2.0&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; },
    },

    &lt;span class=&quot;hl-comment&quot;&gt;// What this package&apos;s own tests and examples need. A consumer never resolves these.&lt;/span&gt;
    devDependencies&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; {
        logger&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { git&lt;span class=&quot;hl-keyword&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;github.com/slate-language/logger&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, version&lt;span class=&quot;hl-keyword&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;0.1.0&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 keys are &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;modules&lt;/code&gt;, &lt;code&gt;dependencies&lt;/code&gt; and &lt;code&gt;devDependencies&lt;/code&gt;, and nothing else —
an unknown one is named. &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt; are required; a dependency takes &lt;code&gt;git&lt;/code&gt; and &lt;code&gt;version&lt;/code&gt;, both
required. Comments are &lt;code&gt;//&lt;/code&gt;, as everywhere else, which is most of why the format is slate’s rather than
JSON’s.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;devDependencies&lt;/code&gt; differs from &lt;code&gt;dependencies&lt;/code&gt; in who resolves it and in nothing else.&lt;/strong&gt; It is fetched,
hashed and pinned in &lt;code&gt;slate.sum&lt;/code&gt; exactly as any other dependency when it is &lt;em&gt;your&lt;/em&gt; project being built —
and a package you depend on has its own second section skipped, however deep it sits. So a package’s suite
may reach for whatever it likes without every consumer paying for it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A package is in one section or the other&lt;/strong&gt;, and both &lt;code&gt;slate add&lt;/code&gt; and the manifest reader refuse a name
in both: two packages cannot share an import name, and one package cannot be in two places. A file
written by hand that names one twice is a file saying two contradictory things, and it is answered with a
caret rather than resolved twice.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;slate deps&lt;/code&gt; marks the ones a consumer would not get:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  parsing 0.4.0 (github.com/sysl-lang/parsing)
  logger 0.1.0 (github.com/slate-language/logger) -- dev
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;slate add --dev github.com/slate-language/logger
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The format is slate’s own syntax because slate’s value model already is the config model&lt;/strong&gt; — null,
booleans, two kinds of number, strings, arrays and records, and nothing else. What decided it is not the
grammar: a manifest gets a &lt;strong&gt;span and a report&lt;/strong&gt;, so a file that is wrong is answered with the same
source-quoting, caret-drawing diagnostic a program that is wrong gets.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The file is parsed and never run&lt;/strong&gt;, and that is the whole design. A resolver working out what to fetch
is reading a file that arrived &lt;em&gt;with&lt;/em&gt; the thing it is deciding whether to fetch; a manifest that ran would
make that a code-execution step. So the reader is a restriction pass over an ordinary slate expression:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A lambda, a call, a name and an operator are each refused by what they are&lt;/strong&gt; — “the name &lt;code&gt;b&lt;/code&gt;“, “a
call”, “a &lt;code&gt;+&lt;/code&gt; between two things” — rather than as “not a literal”, which is true of all of them and
names none.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;-&lt;/code&gt; in front of a numeric literal is allowed&lt;/strong&gt;, the lexer having no signed literal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A key is a name or a string&lt;/strong&gt;, so the manifest syntax is a superset of JSON’s.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A repeated key is refused&lt;/strong&gt; rather than resolved. First-wins and last-wins both silently discard
something a person wrote.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The walk carries on after a refusal&lt;/strong&gt;, so a manifest with three mistakes reports three.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-a-package-exposes&quot;&gt;What a package exposes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Its &lt;code&gt;main&lt;/code&gt;, and whatever its own manifest lists under &lt;code&gt;modules&lt;/code&gt;&lt;/strong&gt; — which is what the slash names.&lt;/p&gt;
&lt;p&gt;It is a list rather than a search. Resolving &lt;code&gt;lath/dom&lt;/code&gt; by trying &lt;code&gt;dom.slx&lt;/code&gt; and then &lt;code&gt;dom.sl&lt;/code&gt; would make
every private helper in every package importable by accident, and would turn a renamed file into a broken
consumer with no way for the author to have said otherwise.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A package’s entry file is its own manifest’s &lt;code&gt;main&lt;/code&gt;.&lt;/strong&gt; That is optional for a project, which may simply
be run by naming a file, and &lt;strong&gt;required for anything imported&lt;/strong&gt; — there being nothing else that says which
of a package’s files is the package.&lt;/p&gt;
&lt;h2 id=&quot;where-things-are&quot;&gt;Where things are&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The project is found by walking up from the entry file&lt;/strong&gt;, so a program works wherever it sits and
wherever it is run from. &lt;strong&gt;A file under no project is not an error&lt;/strong&gt;: a single file that imports nothing is
a perfectly good slate program.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The cache is &lt;code&gt;$HOME/.slate/pkg&lt;/code&gt;&lt;/strong&gt;, overridable by &lt;code&gt;SLATE_CACHE&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;slatesum&quot;&gt;&lt;code&gt;slate.sum&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;slate.sum&lt;/code&gt; records what was fetched. &lt;strong&gt;The hash is over the extracted tree, not over the download&lt;/strong&gt;, so
it is a statement about the code a build actually compiled rather than about one particular archive of it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It records the WHOLE graph and not the packages the project happens to name.&lt;/strong&gt; A package reached
through another one is compiled exactly as one the manifest wrote, so it is pinned exactly as one.
That takes saying because a package’s own dependencies are written in its own manifest, which arrives
&lt;em&gt;with&lt;/em&gt; the package: &lt;code&gt;slate add&lt;/code&gt; and &lt;code&gt;slate fetch&lt;/code&gt; resolve, fetch, and then resolve again — until a
round arrives with nothing new — because the first pass over an empty cache can only see what the
project itself declared.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Objects</title>
    <link href="https://slatelang.dev/reference/objects/"/>
    <id>https://slatelang.dev/reference/objects/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>An object is a collection of fields.</summary>
    <content type="html">&lt;h1 id=&quot;objects&quot;&gt;Objects&lt;/h1&gt;
&lt;p&gt;An object is a collection of fields.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ name&lt;span class=&quot;hl-keyword&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;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, born&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1815&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;two words&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;{name: &amp;quot;ada&amp;quot;, born: 1815}
{&amp;quot;two words&amp;quot;: 1}
{}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every field is written &lt;code&gt;key: value&lt;/code&gt;.&lt;/strong&gt; There is no &lt;code&gt;{ name }&lt;/code&gt; shorthand in a literal — that spelling
belongs to an &lt;a href=&quot;/reference/patterns/&quot;&gt;object pattern&lt;/a&gt;, where it means &lt;em&gt;bind the field &lt;code&gt;name&lt;/code&gt; to the name &lt;code&gt;name&lt;/code&gt;&lt;/em&gt;,
and a literal reading it the other way round would make one notation mean two things.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A key in a literal is a name or a string&lt;/strong&gt;, and nothing else — a number there is a parse error. A key
written through an index may be &lt;strong&gt;any value&lt;/strong&gt;, and stays that value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; q &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; {}

q[&lt;span class=&quot;hl-number&quot;&gt;42&lt;/span&gt;] &lt;span class=&quot;hl-keyword&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;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;print&lt;/span&gt;(q, q[&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-output&quot;&gt;{42: &amp;quot;answer&amp;quot;} answer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is why &lt;a href=&quot;/library/globals/&quot;&gt;&lt;code&gt;toJSON&lt;/code&gt;&lt;/a&gt; refuses a non-string key rather than rendering it: &lt;code&gt;{ 1: &amp;quot;a&amp;quot; }&lt;/code&gt;
and &lt;code&gt;{ &amp;quot;1&amp;quot;: &amp;quot;a&amp;quot; }&lt;/code&gt; are two objects and would be one document.&lt;/p&gt;
&lt;p&gt;Objects are reference types and &lt;a href=&quot;/reference/values/&quot;&gt;compare by their contents&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;keys(o)&lt;/code&gt;, &lt;code&gt;values(o)&lt;/code&gt;, &lt;code&gt;entries(o)&lt;/code&gt; and &lt;code&gt;has(o, k)&lt;/code&gt; are how a program walks one; &lt;code&gt;entries&lt;/code&gt; is what
makes a destructuring &lt;code&gt;for&lt;/code&gt; head worth having:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; o &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&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;keys&lt;/span&gt;(o), &lt;span class=&quot;hl-function&quot;&gt;values&lt;/span&gt;(o), &lt;span class=&quot;hl-function&quot;&gt;has&lt;/span&gt;(o, &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;for&lt;/span&gt; [k, v] &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;entries&lt;/span&gt;(o)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(k, v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;] [1, 2] true
a 1
b 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;o with { f: v }&lt;/code&gt; answers a &lt;strong&gt;copy&lt;/strong&gt; with &lt;code&gt;f&lt;/code&gt; changed. There is no spread in a literal — &lt;code&gt;with&lt;/code&gt; is it.&lt;/p&gt;
&lt;h2 id=&quot;proto&quot;&gt;&lt;code&gt;proto&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;proto&lt;/code&gt; is an ordinary field, and a lookup that misses carries on into it:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; Shape &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; {
    describe&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; self &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;kind&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; with area &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;area&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;,
    kind&lt;span class=&quot;hl-keyword&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;shape&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; Square &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;hl-keyword&quot;&gt;proto&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Shape, kind&lt;span class=&quot;hl-keyword&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;square&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, area&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; self &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side }

&lt;span class=&quot;hl-function&quot;&gt;square&lt;/span&gt;(side) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { side&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; side, &lt;span class=&quot;hl-keyword&quot;&gt;proto&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Square }

&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;4&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;square with area 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;No syntax and no new kind of value.&lt;/strong&gt; A proto may have a proto, so chains and overriding come free;
&lt;code&gt;describe&lt;/code&gt; lives on &lt;code&gt;Shape&lt;/code&gt; and calls &lt;code&gt;area&lt;/code&gt;, which only the concrete shapes have, so the call goes back
down to whichever object it started from. That is dispatch, and it needed no keyword.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is also what makes objects affordable.&lt;/strong&gt; Three methods written as captured closures cost three
closures &lt;em&gt;per instance&lt;/em&gt;; on a proto they cost three once.&lt;/p&gt;
&lt;p&gt;An &lt;a href=&quot;/reference/patterns/&quot;&gt;object pattern&lt;/a&gt; counts a field a proto supplies, a pattern asking whether the value
&lt;em&gt;has&lt;/em&gt; the field — which is the question &lt;code&gt;.&lt;/code&gt; answers. (JavaScript splits the same seam and puts &lt;code&gt;in&lt;/code&gt; on
this side of it.)&lt;/p&gt;
&lt;h2 id=&quot;the-receiver-rule&quot;&gt;The receiver rule&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A method reached through a proto is handed the object it was found on.&lt;/strong&gt; One &lt;code&gt;describe&lt;/code&gt; serves every
shape, so it cannot have captured a particular one — it has to be told, and &lt;code&gt;self&lt;/code&gt; is an ordinary first
parameter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A method stored on the object itself has already captured what it needs and is given nothing extra:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counter&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-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-keyword&quot;&gt;=&lt;/span&gt; {}

    c&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;bump &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; () &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
        n &lt;span class=&quot;hl-keyword&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        n

    c

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(c&lt;span class=&quot;hl-keyword&quot;&gt;.&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-function&quot;&gt;bump&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;That is not two rules but one: &lt;strong&gt;captured methods take no receiver, shared ones must.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Only &lt;code&gt;o.m(...)&lt;/code&gt; passes a receiver.&lt;/strong&gt; &lt;code&gt;o.m&lt;/code&gt; on its own hands back the bare function, so taking a method
off an object and calling it later is allowed and gives you what you took.&lt;/p&gt;
&lt;h2 id=&quot;operator-hooks&quot;&gt;Operator hooks&lt;/h2&gt;
&lt;p&gt;An object may answer for an operator. The word is the method’s name, and a &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; body
writes one with the definition syntax it already has:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Money&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cents

    &lt;span class=&quot;hl-function&quot;&gt;plus&lt;/span&gt;(self, o)    &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&lt;/span&gt;(self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; o&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents)
    &lt;span class=&quot;hl-function&quot;&gt;times&lt;/span&gt;(self, n)   &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&lt;/span&gt;(self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; n)
    &lt;span class=&quot;hl-function&quot;&gt;negated&lt;/span&gt;(self)    &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents)
    &lt;span class=&quot;hl-function&quot;&gt;compare&lt;/span&gt;(self, o) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt; o&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents      &lt;span class=&quot;hl-comment&quot;&gt;// `&amp;lt;`, `&amp;lt;=`, `&amp;gt;` and `&amp;gt;=` read its sign&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;toString&lt;/span&gt;(self)   &lt;span class=&quot;hl-keyword&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;$&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&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;(a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b, a &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt;a)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; b, a &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&lt;/span&gt; b)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;$2 $3 $-1
false true
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;hook&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;plus&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;minus&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;times&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;dividedBy&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;remainder&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;negated&lt;/code&gt;&lt;/td&gt;&lt;td&gt;prefix &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;compare&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;lt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&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;equals&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;hash&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a table key&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Ordering is one hook and not four&lt;/strong&gt;, so a type cannot order inconsistently with itself. &lt;code&gt;==&lt;/code&gt; keeps
&lt;code&gt;equals&lt;/code&gt;, because a type whose ordering is coarser than its equality is an ordinary thing to want.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The left operand decides and the right is never asked&lt;/strong&gt; — &lt;code&gt;equals&lt;/code&gt;‘s rule already — so there is no
reflected form and &lt;code&gt;2 * money&lt;/code&gt; is a fault.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A hook is the last thing tried&lt;/strong&gt;, so none can shadow what an operator means.&lt;/p&gt;
&lt;p&gt;A type that writes &lt;code&gt;equals&lt;/code&gt; should write &lt;code&gt;hash&lt;/code&gt; beside it, or two equal values will not find each other
in a table.&lt;/p&gt;
&lt;h2 id=&quot;tostring-and-tojson&quot;&gt;&lt;code&gt;toString&lt;/code&gt; and &lt;code&gt;toJSON&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A class may say how it &lt;strong&gt;prints&lt;/strong&gt; and how it &lt;strong&gt;encodes&lt;/strong&gt;, which is what a value object needs to stop
leaking the fields it is made of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Money&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; cents

    &lt;span class=&quot;hl-function&quot;&gt;toString&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&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;$&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)
    &lt;span class=&quot;hl-function&quot;&gt;toJSON&lt;/span&gt;(self)   &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;cents &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;100&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Money&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-function&quot;&gt;toJSON&lt;/span&gt;({ paid&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Money&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;150&lt;/span&gt;) }))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;$1
{&amp;quot;paid&amp;quot;:&amp;quot;1&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Both replace everything below them at every depth&lt;/strong&gt;, so a value inside an array or a response body
renders the way its class says rather than only when printed on its own.&lt;/p&gt;
&lt;p&gt;Without &lt;code&gt;toJSON&lt;/code&gt;, a class instance and a &lt;a href=&quot;/reference/data-types/&quot;&gt;data variant&lt;/a&gt; encode as their own fields —
&lt;code&gt;Circle(3)&lt;/code&gt; is &lt;code&gt;{&amp;quot;r&amp;quot;:3}&lt;/code&gt; — and never as the chain they hang from.&lt;/p&gt;
&lt;h2 id=&quot;identity&quot;&gt;Identity&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The proto is the identity&lt;/strong&gt;, and &lt;a href=&quot;/reference/classes/&quot;&gt;&lt;code&gt;class&lt;/code&gt;&lt;/a&gt; is what lets &lt;code&gt;is&lt;/code&gt; ask about it. Written by
hand, &lt;code&gt;p.proto == Point&lt;/code&gt; is the closest an object literal gets — and it is not quite &lt;code&gt;instanceof&lt;/code&gt;: &lt;code&gt;==&lt;/code&gt;
on objects is deep, so it answers true for anything holding the same fields, and it looks exactly one
link up the chain.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:nghttp2</title>
    <link href="https://slatelang.dev/library/nghttp2/"/>
    <id>https://slatelang.dev/library/nghttp2/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>HTTP/2: the framing layer, and HPACK on its own.</summary>
    <content type="html">&lt;h1 id=&quot;slatenghttp2&quot;&gt;&lt;code&gt;slate:nghttp2&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;HTTP/2: the framing layer, and HPACK on its own.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { h2Client, h2Server, h2Receive, h2Send, h2Next, h2Request, h2Respond, h2Close } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:nghttp2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;DRAIN &lt;code&gt;h2Next&lt;/code&gt; AFTER &lt;code&gt;h2Send&lt;/code&gt;, NOT ONLY AFTER &lt;code&gt;h2Receive&lt;/code&gt;.&lt;/strong&gt; A session queues an event when it
&lt;em&gt;writes&lt;/em&gt; as much as when it reads: the last frame of a request going out is what ends that stream, so
&lt;code&gt;streamClose&lt;/code&gt; is waiting in the session the moment the write is made. A loop shaped as &lt;em&gt;receive,
drain, write&lt;/em&gt; — which is the shape a socket callback naturally takes — leaves that event sitting
until the peer happens to send something else. Where the peer has nothing more to say, nothing ever
arrives to shake it out and the program waits forever.&lt;/p&gt;
&lt;p&gt;It is the client still uploading when its answer comes back that meets this, because that is the one
whose stream ends on a write rather than on a read. &lt;strong&gt;Alternate until neither side has anything&lt;/strong&gt;:
drain, write, drain again, and stop when a drain yields no event and a write yields no bytes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nothing here touches a socket.&lt;/strong&gt; Bytes that arrived go in at &lt;code&gt;h2Receive&lt;/code&gt;, bytes to write come out of
&lt;code&gt;h2Send&lt;/code&gt;, and what happened in between is read off with &lt;code&gt;h2Next&lt;/code&gt;. HTTP/2 is a &lt;em&gt;transformation&lt;/em&gt;, so how
bytes reach the wire stays your program’s business — which is why the whole protocol can be driven
between two sessions in memory, with no port and nothing that can hang:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { h2Client, h2Server, h2Receive, h2Send, h2Next, h2Request, h2Respond, h2Close } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:nghttp2

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Client&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Server&lt;/span&gt;()

&lt;span class=&quot;hl-comment&quot;&gt;// Whatever one end wants to write, handed to the other.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;pump&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt;, to)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; bytes &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Send&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt;)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(bytes) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&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-function&quot;&gt;h2Receive&lt;/span&gt;(to, bytes)

&lt;span class=&quot;hl-comment&quot;&gt;// Everything the peer did since last time.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;seen&lt;/span&gt;(who)
    &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-keyword&quot;&gt;loop&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Next&lt;/span&gt;(who)

        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&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;push&lt;/span&gt;(out, e)

    out

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; stream &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Request&lt;/span&gt;(c, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:method&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;GET&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;:scheme&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;https&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;:authority&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;example.test&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-keyword&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;/things&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; })

&lt;span class=&quot;hl-function&quot;&gt;pump&lt;/span&gt;(c, s)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;seen&lt;/span&gt;(s)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;kind &lt;span class=&quot;hl-keyword&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;headers&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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;asked for&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;headers[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])

&lt;span class=&quot;hl-function&quot;&gt;h2Respond&lt;/span&gt;(s, stream, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;200&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;content-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;:&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/plain&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;hello from h2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;pump&lt;/span&gt;(s, c)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;seen&lt;/span&gt;(c)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;kind &lt;span class=&quot;hl-keyword&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;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;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;bytes)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)

&lt;span class=&quot;hl-function&quot;&gt;h2Close&lt;/span&gt;(c)
&lt;span class=&quot;hl-function&quot;&gt;h2Close&lt;/span&gt;(s)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;asked for [&amp;quot;:path&amp;quot;, &amp;quot;/things&amp;quot;]
hello from h2
&lt;/code&gt;&lt;/pre&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;h2Client(options?)&lt;/code&gt; / &lt;code&gt;h2Server(options?)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a session&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Receive(session, bytes)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;null&lt;/code&gt;, or &lt;code&gt;{ error }&lt;/code&gt; where the peer spoke nonsense&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Send(session)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the bytes to write, as an array&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Next(session)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the next event, or &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Request(session, headers, body?)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a client’s; answers the stream number&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Respond(session, stream, headers, body?)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a server’s&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2RequestStream(session, headers)&lt;/code&gt; / &lt;code&gt;h2RespondStream(session, stream, headers)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same two with the body written afterwards&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Push(session, stream, piece)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;more of a body that is still open; &lt;code&gt;{ error }&lt;/code&gt; where the peer gave up&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Finish(session, stream, trailers?)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the body is complete and the stream ends&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Settings(session, { … })&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Goaway(session, lastStream, code?)&lt;/code&gt; / &lt;code&gt;h2Reset(session, stream, code)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;giving up&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2WindowUpdate(session, stream, by)&lt;/code&gt; / &lt;code&gt;h2Consume(session, stream, bytes)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;flow control&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Ping(session)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Wants(session)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;{ read, write }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;h2Close(session)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hpackDeflater(maxTable?)&lt;/code&gt; / &lt;code&gt;hpackInflater()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;HPACK on its own&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hpackDeflate(encoder, headers)&lt;/code&gt; / &lt;code&gt;hpackInflate(decoder, bytes)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hpackClose(x)&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;which-version-a-connection-is&quot;&gt;Which version a connection is&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;HTTP/2 over TLS is chosen by ALPN and by nothing else&lt;/strong&gt; — no upgrade handshake, no version header.
That half is &lt;a href=&quot;/library/net/&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;&lt;/a&gt;‘s: a listener offers a list, a client offers one, and
&lt;code&gt;alpnProtocol(conn)&lt;/code&gt; says what the two settled on. A server taking both versions on one port asks it
and hands the connection to whichever it is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;listen&lt;/span&gt;({ port&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;8443&lt;/span&gt;, cert&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pem, key&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; keyPem, alpn&lt;span class=&quot;hl-keyword&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;h2&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;http/1.1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;] }, conn &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;alpnProtocol&lt;/span&gt;(conn) &lt;span class=&quot;hl-keyword&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;h2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;speakHttp2&lt;/span&gt;(conn)
    &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;hl-function&quot;&gt;speakHttp1&lt;/span&gt;(conn))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;h2c&lt;/code&gt; — HTTP/2 with no TLS at all — needs nothing extra&lt;/strong&gt;, a session neither knowing nor caring
where its bytes come from. What is not here is the HTTP/1.1 &lt;code&gt;Upgrade:&lt;/code&gt; dance that converts an existing
connection; prior-knowledge &lt;code&gt;h2c&lt;/code&gt;, which is what one speaks to a service one controls, is the ordinary
case and works today.&lt;/p&gt;
&lt;h2 id=&quot;events&quot;&gt;Events&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;h2Next&lt;/code&gt; answers one at a time, in the order they happened, and &lt;code&gt;null&lt;/code&gt; when there are no more. Every
event has a &lt;code&gt;kind&lt;/code&gt;, and the rest of its fields depend on it:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;code&gt;kind&lt;/code&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;headers&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;headers&lt;/code&gt;, and &lt;code&gt;of&lt;/code&gt; — &lt;code&gt;&amp;quot;request&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;response&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;trailer&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;bytes&lt;/code&gt; — &lt;strong&gt;one event per DATA frame&lt;/strong&gt;, not one per stream&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;streamEnd&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt; — the peer will send no more, and may still be reading&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;streamClose&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt; — finished at both ends&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;settings&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the peer’s settings arrived and are in force&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;goaway&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;lastStream&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;rstStream&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;code&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;windowUpdate&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;, &lt;code&gt;increment&lt;/code&gt; — &lt;code&gt;stream&lt;/code&gt; is 0 for the connection&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;ping&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;ack&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Events rather than callbacks&lt;/strong&gt;, and that is the design decision this module turns on: nghttp2 calls
back from inside &lt;code&gt;receive&lt;/code&gt;, which is a place your code has no business running — it cannot submit
frames there without reentering the library, and a closure it registered would have to be kept alive
by the session. What you write instead is a loop.&lt;/p&gt;
&lt;h2 id=&quot;headers&quot;&gt;Headers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Write them as an object, or as pairs where order and duplicates matter.&lt;/strong&gt; An object is what a
program writes nine times in ten; two &lt;code&gt;set-cookie&lt;/code&gt; headers are legal and an object has one key.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h2Respond&lt;/span&gt;(s, stream, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;200&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;content-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;:&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; }, body)

&lt;span class=&quot;hl-function&quot;&gt;h2Respond&lt;/span&gt;(s, stream, [[&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;: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;200&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;set-cookie&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=1&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;set-cookie&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=2&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;They always arrive as pairs.&lt;/strong&gt; Two headers of one name are legal, and an object would silently keep
one of them — which is the shape of defect that makes request smuggling possible. A program that wants
an object folds the list itself, knowing what it discarded.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A third element marks a field never-indexed&lt;/strong&gt;, which is a wire decision rather than a comment: an
attacker who can insert requests on a connection learns a secret header’s value one character at a
time by watching whether his guess compressed, and keeping it out of the dynamic table is the defence.
&lt;code&gt;authorization&lt;/code&gt; and &lt;code&gt;cookie&lt;/code&gt; are the fields that want it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h2Request&lt;/span&gt;(c, [[&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:method&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;GET&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;:scheme&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;https&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;/&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;authorization&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;Bearer …&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A header value is text and a number is refused rather than converted&lt;/strong&gt;, because a value is a string
on the wire — and converting silently would make &lt;code&gt;true&lt;/code&gt; a header value too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { h2Client, h2Request } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:nghttp2

&lt;span class=&quot;hl-function&quot;&gt;h2Request&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;h2Client&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-keyword&quot;&gt;:&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-error&quot;&gt;a header value is text
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-a-session-refuses-and-how&quot;&gt;What a session refuses, and how&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Bytes the peer got wrong are an ANSWER&lt;/strong&gt;, because a peer that speaks nonsense is the ordinary thing
a server deals with and a fault would take the server down with the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { h2Server, h2Receive } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:nghttp2

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Server&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;h2Receive&lt;/span&gt;(s, &lt;span class=&quot;hl-function&quot;&gt;toBytes&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;GET / HTTP/1.1&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r\n\r\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;.&lt;/span&gt;error &lt;span class=&quot;hl-keyword&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;/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;A handle you have closed is a defect in the program&lt;/strong&gt;, exactly as a closed socket is, so that one
faults — and says what was closed rather than naming an integer.&lt;/p&gt;
&lt;h2 id=&quot;a-body-written-a-piece-at-a-time&quot;&gt;A body written a piece at a time&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;h2Request&lt;/code&gt; and &lt;code&gt;h2Respond&lt;/code&gt; take the bytes they are to send, which is right for a body a program
already has. &lt;strong&gt;A body produced as it goes — an event stream, a proxied response, a file read in
pieces — is the other pair&lt;/strong&gt;, and the difference on the wire is &lt;em&gt;when the head goes out&lt;/em&gt;: a response
whose source never ends still has to say &lt;code&gt;200&lt;/code&gt; before its first byte of body exists.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;h2RespondStream&lt;/span&gt;(s, stream, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;200&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;content-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;:&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/event-stream&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; })

&lt;span class=&quot;hl-comment&quot;&gt;// … whenever there is something to say:&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;h2Push&lt;/span&gt;(s, stream, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;data: hello&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-comment&quot;&gt;// … and at the end, which for an event stream may be never:&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;h2Finish&lt;/span&gt;(s, stream)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;h2Push&lt;/code&gt; answers &lt;code&gt;{ error }&lt;/code&gt; where the stream has no open body&lt;/strong&gt;, which is the ordinary way a
program learns the peer gave up: a reset or a close drops the body, so the next push says so rather
than writing into nothing. Trailers may be named at &lt;code&gt;h2Finish&lt;/code&gt; and nowhere else — what was unknown
until the body ended is exactly what a trailer is for.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;h2RequestStream&lt;/code&gt; is the same on the client side, and it is what an upload of unknown length is.&lt;/p&gt;
&lt;h2 id=&quot;flow-control-and-back-pressure&quot;&gt;Flow control, and back-pressure&lt;/h2&gt;
&lt;p&gt;A session extends its own windows as bytes arrive, which is right for a program that deals with a body
as fast as it reads one. A program that queues bodies, writes them to disk or hands them to something
slower wants the credit returned when the work is &lt;strong&gt;done&lt;/strong&gt; — and that is what &lt;code&gt;h2Consume&lt;/code&gt; is for. It
needs a session made for it, since a session that extends its own windows has nothing to report:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; s &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;h2Server&lt;/span&gt;({ autoWindowUpdate&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt; })

&lt;span class=&quot;hl-comment&quot;&gt;// … a body arrives, is written away, and only then:&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;h2Consume&lt;/span&gt;(s, stream, &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(bytes))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;hpack-on-its-own&quot;&gt;HPACK on its own&lt;/h2&gt;
&lt;p&gt;The header-compression tier needs no session, and it is worth having by itself: it is the
security-relevant half of HTTP/2, identical whoever drives the frames, and a decoder that trusts its
input is a decompression bomb waiting for somebody to send it one.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { hpackDeflater, hpackInflater, hpackDeflate, hpackInflate, hpackClose } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:nghttp2

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; enc &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hpackDeflater&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; dec &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hpackInflater&lt;/span&gt;()

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; block &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hpackDeflate&lt;/span&gt;(enc, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;200&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;content-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;:&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/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;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hpackInflate&lt;/span&gt;(dec, block))

&lt;span class=&quot;hl-comment&quot;&gt;// The dynamic table is what makes the second block of the same headers a fraction of the first.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; again &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hpackDeflate&lt;/span&gt;(enc, { &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;:status&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;200&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;content-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;:&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/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;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(again) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(block))

&lt;span class=&quot;hl-function&quot;&gt;hpackClose&lt;/span&gt;(enc)
&lt;span class=&quot;hl-function&quot;&gt;hpackClose&lt;/span&gt;(dec)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[[&amp;quot;:status&amp;quot;, &amp;quot;200&amp;quot;], [&amp;quot;content-type&amp;quot;, &amp;quot;text/plain&amp;quot;]]
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A deflater and an inflater are each a conversation, not a function.&lt;/strong&gt; The dynamic table is built from
every block that has gone through, so blocks must be given to one inflater &lt;strong&gt;in the order they
arrived&lt;/strong&gt; — that is HPACK’s design, and it is what makes the second request on a connection cost five
bytes where the first cost thirty-eight. A block that will not decode is an answer, &lt;code&gt;{ error }&lt;/code&gt;, for
the reason a session’s refusal is.&lt;/p&gt;
&lt;h2 id=&quot;where-this-sits&quot;&gt;Where this sits&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The module is named for the library and its names for the protocol&lt;/strong&gt;, which is
&lt;a href=&quot;/library/llhttp/&quot;&gt;&lt;code&gt;slate:llhttp&lt;/code&gt;&lt;/a&gt;‘s arrangement exactly — that one is &lt;code&gt;llhttp&lt;/code&gt; and exports &lt;code&gt;httpParser&lt;/code&gt; and
&lt;code&gt;httpFeed&lt;/code&gt;. What the two have in common is the tier, a door onto somebody else’s state machine, and
naming them the same way is what says so. It also leaves HTTP/2’s own short name free for whatever a
program eventually wants to import, which is the reason the HTTP server is &lt;code&gt;slate:http&lt;/code&gt; and not
&lt;code&gt;slate:llhttp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:nghttp2&lt;/code&gt; is &lt;a href=&quot;/library/llhttp/&quot;&gt;&lt;code&gt;slate:llhttp&lt;/code&gt;&lt;/a&gt;‘s sibling&lt;/strong&gt;, and it is public for the same reason:
&lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; is the server a program wants, and these are the layers under whatever speaks
HTTP next. A server that takes both versions on one port, a client that keeps its connections, a
proxy, a gRPC endpoint — every one of those is an ordinary package rather than a change to slate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The protocol itself is &lt;a href=&quot;https://github.com/sysl-lang/nghttp2&quot;&gt;&lt;code&gt;sh.sysl.nghttp2&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;, the library
curl, Apache and Envoy use. slate adds no HTTP/2 of its own: what is here converts values at the
boundary and nothing else, which is the same arrangement &lt;code&gt;slate:redis&lt;/code&gt; and &lt;code&gt;slate:llhttp&lt;/code&gt; have with
their own bindings.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:net</title>
    <link href="https://slatelang.dev/library/net/"/>
    <id>https://slatelang.dev/library/net/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>TCP, and TLS at both ends.</summary>
    <content type="html">&lt;h1 id=&quot;slatenet&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;TCP, and TLS at both ends.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { listen, connect, onData, onError, send, close, localPort, startTls } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:net

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;listen&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;, conn &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;onData&lt;/span&gt;(conn, chunk &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; chunk &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;
            &lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(conn)
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;hl-function&quot;&gt;send&lt;/span&gt;(conn, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;echo: &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; chunk)))

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; client &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;connect&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;127.0.0.1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;localPort&lt;/span&gt;(server)))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

    &lt;span class=&quot;hl-function&quot;&gt;onData&lt;/span&gt;(client, chunk &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; chunk &lt;span class=&quot;hl-keyword&quot;&gt;!=&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;(chunk)
            &lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(client)
            &lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;(server))

    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;send&lt;/span&gt;(client, &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;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&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;listen(port, fn)&lt;/code&gt; or &lt;code&gt;listen({ port, cert, key, alpn }, fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a server&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;connect(host, port)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of a result&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;onData(sock, fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;each chunk as text, and &lt;code&gt;null&lt;/code&gt; at the end&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;onBytes(sock, fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same reader for something that is not text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;onError(sock, fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a sentence, &lt;em&gt;instead of&lt;/em&gt; that &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;send(sock, v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of a result; an &lt;strong&gt;array is sent as bytes&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;close(sock)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;localPort(server)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;remoteAddress(conn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the IP at the other end, or &lt;code&gt;null&lt;/code&gt; where there is no other end&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;startTls(sock, options)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise that settles when the handshake finishes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;alpnProtocol(conn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;which application protocol was agreed, or &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Under &lt;a href=&quot;/reference/javascript/&quot;&gt;&lt;code&gt;slate js&lt;/code&gt;&lt;/a&gt; this is node’s own TCP&lt;/strong&gt;, and everything above is the
same. TLS is the exception: &lt;code&gt;startTls&lt;/code&gt;, and a &lt;code&gt;listen&lt;/code&gt; given a &lt;code&gt;cert&lt;/code&gt; and a &lt;code&gt;key&lt;/code&gt;, both refuse there
naming TLS. A browser has no sockets at all and says so.&lt;/p&gt;
&lt;h2 id=&quot;promises-and-callbacks&quot;&gt;Promises and callbacks&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;send&lt;/code&gt; answer promises of a result; &lt;code&gt;listen&lt;/code&gt;, &lt;code&gt;onData&lt;/code&gt; and &lt;code&gt;onBytes&lt;/code&gt; take callbacks.&lt;/strong&gt;
That split is not a matter of taste: a connect and a send are each one attempt with one outcome, which is
what a promise is, and a listener does not have one connection any more than a connection has one chunk.&lt;/p&gt;
&lt;p&gt;A refused connection is the ordinary thing a client handles, so it comes back as &lt;code&gt;{ ok: false, error: … }&lt;/code&gt;
rather than stopping the program.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;onData&lt;/code&gt; hands over &lt;code&gt;null&lt;/code&gt; once the peer has finished sending&lt;/strong&gt; — the end of a stream is a value here
rather than a failure, because a peer closing its half is how a request ordinarily ends. &lt;strong&gt;Calling either
reader a second time replaces the function&lt;/strong&gt; rather than adding one, which is what makes a protocol that
changes what it expects halfway through writable at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A socket that fails ends its stream — it does not stop the program.&lt;/strong&gt; A connection reset is something any
peer can produce, so it arrives as the same &lt;code&gt;null&lt;/code&gt; a peer that finished sends: &lt;code&gt;if chunk == null then close(c)&lt;/code&gt; is right either way. &lt;code&gt;onError&lt;/code&gt; is how a program tells the two apart, and one that never registers
a handler never hears about it. It is a registration of its own rather than a third argument to &lt;code&gt;onData&lt;/code&gt;
&lt;strong&gt;because &lt;code&gt;onData&lt;/code&gt; replaces its callback&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;ports-and-names&quot;&gt;Ports and names&lt;/h2&gt;
&lt;p&gt;A port of &lt;code&gt;0&lt;/code&gt; asks the kernel to pick one and &lt;code&gt;localPort&lt;/code&gt; says which.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;remoteAddress&lt;/code&gt; says who connected&lt;/strong&gt;, as the text a person would read it as — &lt;code&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/code&gt;,
&lt;code&gt;&amp;quot;::1&amp;quot;&lt;/code&gt;. A listener has no other end and answers &lt;code&gt;null&lt;/code&gt;, which is an answer rather than a failure:
asking a socket who is at the far end of it is asking about a thing that may not be there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An IPv4 client of a dual-stack server is written the way it dialled.&lt;/strong&gt; &lt;code&gt;listen&lt;/code&gt; binds &lt;code&gt;::&lt;/code&gt; so that
a client asking for &lt;code&gt;localhost&lt;/code&gt; reaches the server, and the kernel then reports every IPv4 peer in
the mapped form &lt;code&gt;::ffff:127.0.0.1&lt;/code&gt;. The prefix is taken off here, or an allow-list written against
&lt;code&gt;127.0.0.1&lt;/code&gt; would match nothing on a machine with IPv6.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;connect&lt;/code&gt; takes a name or an address&lt;/strong&gt;, resolving through libuv’s resolver on its thread pool. A name that
does not resolve settles the promise the way a refused connection does, rather than raising.&lt;/p&gt;
&lt;h2 id=&quot;lifetime&quot;&gt;Lifetime&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A socket keeps the program alive, exactly as a timer does&lt;/strong&gt;, so &lt;code&gt;close&lt;/code&gt; is not optional; a program that
leaves one open never exits. &lt;strong&gt;Closing twice is fine&lt;/strong&gt;, which is what lets a server close its connections
while a read callback closes its own.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A closed socket is not whatever opens next.&lt;/strong&gt; The value a program holds carries the generation that
claimed its slot, so a socket held across a &lt;code&gt;close&lt;/code&gt; never comes to mean its successor.&lt;/p&gt;
&lt;h2 id=&quot;tls&quot;&gt;TLS&lt;/h2&gt;
&lt;p&gt;A listener told a certificate hands out connections whose bytes are already decrypted, so
&lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; — and any other protocol written over these sockets — is an HTTPS server without
learning that TLS exists:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;listen&lt;/span&gt;({ port&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;8443&lt;/span&gt;, cert&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pem, key&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; keyPem }, conn &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; …)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;TLS is a transport and not an HTTP concern&lt;/strong&gt;, which is why it goes under &lt;code&gt;listen&lt;/code&gt; rather than beside
&lt;code&gt;serve&lt;/code&gt;. node splits it the other way, with an &lt;code&gt;https&lt;/code&gt; module beside &lt;code&gt;http&lt;/code&gt;; node’s &lt;code&gt;https&lt;/code&gt; is literally
&lt;code&gt;http&lt;/code&gt; over a &lt;code&gt;tls.Server&lt;/code&gt;, and putting the seam one layer down is that arrangement with the duplication
left out. &lt;code&gt;alpn&lt;/code&gt; beside them offers a protocol list.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The other end is &lt;code&gt;startTls&lt;/code&gt;, which upgrades a socket that is already open:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; db &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;connect&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;db.example.com&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;5432&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

    &lt;span class=&quot;hl-function&quot;&gt;onBytes&lt;/span&gt;(db, read)

    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; up &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;startTls&lt;/span&gt;(db, { host&lt;span class=&quot;hl-keyword&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;db.example.com&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, trust&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; authority })

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;!&lt;/span&gt;up&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(up&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;alpn-which-is-how-http2-is-chosen&quot;&gt;ALPN, which is how HTTP/2 is chosen&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A client offers a list of protocol names and the server picks one&lt;/strong&gt;, and for HTTP/2 that is the
whole of the negotiation — there is no upgrade handshake and no version header. Both ends say what
they will take, and both read the answer off the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;listen&lt;/span&gt;({ port&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;8443&lt;/span&gt;, cert&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pem, key&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; keyPem, alpn&lt;span class=&quot;hl-keyword&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;h2&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;http/1.1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;] }, conn &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;alpnProtocol&lt;/span&gt;(conn) &lt;span class=&quot;hl-keyword&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;h2&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;speakHttp2&lt;/span&gt;(conn) &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;speakHttp1&lt;/span&gt;(conn))

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; up &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;startTls&lt;/span&gt;(sock, { host&lt;span class=&quot;hl-keyword&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;example.com&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, alpn&lt;span class=&quot;hl-keyword&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;h2&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;http/1.1&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;alpnProtocol&lt;/span&gt;(sock))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The server’s own order decides&lt;/strong&gt;, because it is the end that knows which protocol it serves well.
&lt;strong&gt;&lt;code&gt;alpnProtocol&lt;/code&gt; answers &lt;code&gt;null&lt;/code&gt; for three ordinary cases and no failure&lt;/strong&gt;: a plain socket, a peer that
offered nothing, and a handshake that has not finished — a server reads it inside its connection
callback, by which time the handshake is long done.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/library/nghttp2/&quot;&gt;&lt;code&gt;slate:nghttp2&lt;/code&gt;&lt;/a&gt; is what frames the bytes once &lt;code&gt;h2&lt;/code&gt; is what was agreed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An upgrade rather than a flag on &lt;code&gt;connect&lt;/code&gt;, because that is what protocols actually do.&lt;/strong&gt; TLS from byte
zero is one case and not the general one: PostgreSQL sends eight bytes in the clear and reads one back
before any handshake, SMTP has &lt;code&gt;STARTTLS&lt;/code&gt;, IMAP and FTP have their own, and a WebSocket over TLS is HTTPS
first. It is also the weaker primitive — TLS from the start is &lt;code&gt;connect&lt;/code&gt; and then this — so one builtin
covers both where a flag would have covered neither.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A server upgrades its end the same way&lt;/strong&gt;, with the certificate and key &lt;code&gt;listen&lt;/code&gt; would have taken:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;startTls&lt;/span&gt;(conn, { cert&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pem, key&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; keyPem })&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There is no third argument saying which end this is: a client has a name to check and a server has a
certificate to present, and neither object could be mistaken for the other.&lt;/p&gt;
&lt;p&gt;Everything after the handshake is unchanged: &lt;code&gt;send&lt;/code&gt; takes plaintext, the reader is handed plaintext, and a
program that writes before awaiting has its bytes queued rather than lost.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The name is checked against the certificate and there is no way to say otherwise.&lt;/strong&gt; It goes out as SNI,
without which a shared host does not know which certificate to send, and it is what the certificate’s names
are verified against. An address works too and is checked against the certificate’s addresses rather than
its names — which is why &lt;code&gt;connect&lt;/code&gt; resolving matters here rather than being a convenience: verify against
the name the program was looking for, not the address the resolver happened to answer with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;trust&lt;/code&gt; is added to the machine’s own store rather than put in place of it&lt;/strong&gt;, so naming a private
authority does not stop verifying everything else the program talks to.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Modules</title>
    <link href="https://slatelang.dev/reference/modules/"/>
    <id>https://slatelang.dev/reference/modules/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>A file is a module. What another file can see is what it writes export in front of:</summary>
    <content type="html">&lt;h1 id=&quot;modules&quot;&gt;Modules&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;A file is a module.&lt;/strong&gt; What another file can see is what it writes &lt;code&gt;export&lt;/code&gt; in front of:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; greeting &lt;span class=&quot;hl-keyword&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;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;export&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(x) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;secret&lt;/span&gt;() &lt;span class=&quot;hl-keyword&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;no other file can reach 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;(greeting, &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;secret&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello 42 no other file can reach this
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and a file takes what it needs by name, or takes the whole module under one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { double, greeting as hi } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./util.sl&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; as util &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./util.sl&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;(hi, &lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt;), util&lt;span class=&quot;hl-keyword&quot;&gt;.&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;go&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;export&lt;/code&gt; goes in front of a &lt;code&gt;val&lt;/code&gt;, a &lt;code&gt;var&lt;/code&gt;, a definition, a &lt;code&gt;type&lt;/code&gt;, a &lt;code&gt;class&lt;/code&gt; or a &lt;code&gt;data&lt;/code&gt;. A &lt;code&gt;type&lt;/code&gt;,
&lt;code&gt;class&lt;/code&gt; or &lt;code&gt;data&lt;/code&gt; crosses as &lt;strong&gt;both halves at once&lt;/strong&gt; — the value the name binds and the declaration the
compiler resolves.&lt;/p&gt;
&lt;h2 id=&quot;the-three-kinds-of-specifier&quot;&gt;The three kinds of specifier&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { helper } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./util.sl&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;      &lt;span class=&quot;hl-comment&quot;&gt;// a quoted path  -- a file&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { mount } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath              &lt;span class=&quot;hl-comment&quot;&gt;// a bare word    -- a package&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { domHost } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath&lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt;dom        &lt;span class=&quot;hl-comment&quot;&gt;// ... and one of that package&apos;s other modules&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;, now } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time    &lt;span class=&quot;hl-comment&quot;&gt;// slate:name     -- one of slate&apos;s own&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A path is relative to the file the import is written in&lt;/strong&gt;, so a directory of files that import each
other works wherever the program is run from.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bare &lt;code&gt;util.sl&lt;/code&gt; is refused rather than guessed at&lt;/strong&gt;: an unquoted specifier is how a package is named,
and a language that resolved it as a file could not tell the two apart. The two are different syntax
rather than two readings of one string, which is further from node’s rule than a &lt;code&gt;./&lt;/code&gt; prefix would have
been and is the point — nothing already written changes meaning, and no reader has to work out whether a
leading &lt;code&gt;./&lt;/code&gt; was optional.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;/reference/packages/&quot;&gt;Packages&lt;/a&gt; for what a bare name resolves to, and &lt;a href=&quot;/library/&quot;&gt;the library&lt;/a&gt;
for the &lt;code&gt;slate:&lt;/code&gt; modules.&lt;/p&gt;
&lt;h2 id=&quot;importing-a-file-that-is-not-slate&quot;&gt;Importing a file that is not slate&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A quoted path naming anything but &lt;code&gt;.sl&lt;/code&gt; or &lt;code&gt;.slx&lt;/code&gt; is an asset, and one name takes the whole of it as
a string:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; styles &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./button.css&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; template &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./welcome.html&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;len&lt;/span&gt;(styles))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The file is read while the program is compiled and travels inside it&lt;/strong&gt;, so nothing has to sit beside
the binary at run time and nothing is read twice — six files importing one stylesheet is one string.
It is the same on both back ends: under &lt;code&gt;slate js&lt;/code&gt; the text is written into the emitted program, byte
for byte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The extension decides, never what the writer meant.&lt;/strong&gt; &lt;code&gt;&amp;quot;./util.sl&amp;quot;&lt;/code&gt; is a module and &lt;code&gt;&amp;quot;./button.css&amp;quot;&lt;/code&gt;
is an asset, and each is refused in the other’s form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { helper } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;./styles.css&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 slate source, so there are no names in it to take
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and a bare name asked of slate source says the same thing the other way round — &lt;strong&gt;slate has no
default export&lt;/strong&gt;, and a file that does have names in it is imported by naming them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A package’s assets are the package’s own.&lt;/strong&gt; A &lt;code&gt;.css&lt;/code&gt; shipped beside a &lt;code&gt;.slx&lt;/code&gt; is imported by that
file, relatively, and handed on as an ordinary exported value — so nothing about the
&lt;a href=&quot;/reference/packages/&quot;&gt;package&lt;/a&gt; system had to learn what an asset is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two things are refused, both before the program runs.&lt;/strong&gt; A file that is not there is named beside the
file that asked for it. And a file that is &lt;strong&gt;not UTF-8 text&lt;/strong&gt; is refused rather than mangled: slate has
one text type, so there is no value a PNG could arrive as, and a program that wants bytes wants
&lt;a href=&quot;/library/fs/&quot;&gt;&lt;code&gt;readBytes&lt;/code&gt;&lt;/a&gt; — which reads them while the program runs, where their size is not the
program’s size.&lt;/p&gt;
&lt;h2 id=&quot;imports-are-resolved-before-anything-runs&quot;&gt;Imports are resolved before anything runs&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The machine never sees an import.&lt;/strong&gt; That is not a preference: slate’s file surface is promise-shaped,
so an import resolved at run time would need either a blocking read carved out as a special case or an
&lt;code&gt;import&lt;/code&gt; that answers a promise — and the second forces top-level &lt;code&gt;await&lt;/code&gt;, which slate refuses, on every
program that imports anything at all.&lt;/p&gt;
&lt;p&gt;What it costs is that &lt;strong&gt;a path cannot be computed&lt;/strong&gt;, which is the same bargain sysl takes and is what
makes the set of files a program is made of knowable by reading it.&lt;/p&gt;
&lt;h2 id=&quot;a-module-is-an-object&quot;&gt;A module is an object&lt;/h2&gt;
&lt;p&gt;So there is no new kind of value and nothing new for the collector to trace — &lt;code&gt;util.double&lt;/code&gt; is the field
selection a program writes for itself.&lt;/p&gt;
&lt;p&gt;It follows that &lt;strong&gt;a module’s exports are a snapshot&lt;/strong&gt; taken when its file finishes: an &lt;code&gt;export var&lt;/code&gt; the
module changes afterwards is not seen changing from outside, which is where this parts company with
TypeScript’s live bindings.&lt;/p&gt;
&lt;h2 id=&quot;what-is-refused-and-when&quot;&gt;What is refused, and when&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A circle of imports&lt;/strong&gt;, with the chain named. node allows one and initialises half a module, which is
a famous source of confusion; refusing can be relaxed later, and half-built modules cannot be
un-shipped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Asking for a name a file does not export&lt;/strong&gt; — before the program runs, and the message says what the
file &lt;em&gt;does&lt;/em&gt; export. Left to run time it would arrive as an absent field, and the message would be about
a name bound to nothing: true, and about the wrong thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A name nothing has bound&lt;/strong&gt;, likewise before it runs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Every complaint is drawn against the file it is about.&lt;/strong&gt; A fault carries the file its span belongs to
rather than looking one up when it is reported, because a signal outlives the statement that raised it.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:lmdb</title>
    <link href="https://slatelang.dev/library/lmdb/"/>
    <id>https://slatelang.dev/library/lmdb/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>An ordered key-value store in a memory-mapped file — the one place a slate server can keep something across a restart without a second process being up.</summary>
    <content type="html">&lt;h1 id=&quot;slatelmdb&quot;&gt;&lt;code&gt;slate:lmdb&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;An ordered key-value store in a memory-mapped file — the one place a slate server can keep something
across a restart without a second process being up.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { lmdbOpen, lmdbWrite, lmdbRead, lmdbDb, lmdbPut, lmdbGet, lmdbCommit, lmdbAbort } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:lmdb

&lt;span class=&quot;hl-comment&quot;&gt;// The directory has to exist; LMDB writes `data.mdb` and `lock.mdb` into it.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; store &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbOpen&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/var/db/sessions&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, { mapSize&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, maxDbs&lt;span class=&quot;hl-keyword&quot;&gt;:&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 &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbWrite&lt;/span&gt;(store)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sessions &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbDb&lt;/span&gt;(w, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;sessions&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;lmdbPut&lt;/span&gt;(w, sessions, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;s:abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;toJSON&lt;/span&gt;({ user&lt;span class=&quot;hl-keyword&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;ed&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; }))
&lt;span class=&quot;hl-function&quot;&gt;lmdbCommit&lt;/span&gt;(w)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbRead&lt;/span&gt;(store)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parseJSON&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;lmdbGet&lt;/span&gt;(r, &lt;span class=&quot;hl-function&quot;&gt;lmdbDb&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;sessions&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;s:abc&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;user)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;lmdbGet&lt;/span&gt;(r, &lt;span class=&quot;hl-function&quot;&gt;lmdbDb&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;sessions&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;s:nothing&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))     &lt;span class=&quot;hl-comment&quot;&gt;// null — a key that is not there&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;lmdbAbort&lt;/span&gt;(r)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The blocks on this page are quoted rather than run&lt;/strong&gt;, which is what every page here does for a
module that needs somewhere on disk of its own: a program that made a store would be picking a path,
and the one it picked would be the suite’s business rather than the reader’s.
&lt;code&gt;dev/slatelang/slate/tests_lmdb.sysl&lt;/code&gt; runs all of this against a real store in a directory of its
own.&lt;/p&gt;
&lt;h2 id=&quot;why-it-is-here&quot;&gt;Why it is here&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Every server slate is aimed at wants the same three things and had nowhere to put them&lt;/strong&gt;: a session
store, a rate-limit bucket per client, and a replay ring for the events a reconnecting browser
missed. Each is small, is read far more often than it is written, and is worthless if it evaporates
when the process restarts — and until this module the answers were a file rewritten by hand or
&lt;a href=&quot;/library/redis/&quot;&gt;&lt;code&gt;slate:redis&lt;/code&gt;&lt;/a&gt;, which is a second process to run and a network hop for a lookup that
should cost a page fault.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A read takes no lock and blocks nothing.&lt;/strong&gt; Readers never block writers, writers never block
readers, and there is exactly one writer at a time across the whole store and across every process
using it. That last part is the trade — this is not the store for a write-heavy queue — and it is
exactly right for the three uses above, where a write is a session being created and a read is every
request after it.&lt;/p&gt;
&lt;h2 id=&quot;a-handle-is-an-integer&quot;&gt;A handle is an integer&lt;/h2&gt;
&lt;p&gt;An environment, a transaction, a database and a cursor are each a number into a table inside slate,
which is what every handle in slate is — a socket, a timer, a compiled pattern, an HTTP/2 session.
So &lt;code&gt;==&lt;/code&gt; compares what slate says it compares, &lt;code&gt;print&lt;/code&gt; has something to say, and a number from one
table handed to a call that wants another is refused rather than misread.&lt;/p&gt;
&lt;h2 id=&quot;the-nineteen-names&quot;&gt;The nineteen names&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;lmdbOpen(path, options)&lt;/code&gt; &lt;code&gt;lmdbClose(env)&lt;/code&gt; &lt;code&gt;lmdbInfo(env)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the store&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lmdbRead(env)&lt;/code&gt; &lt;code&gt;lmdbWrite(env)&lt;/code&gt; &lt;code&gt;lmdbCommit(txn)&lt;/code&gt; &lt;code&gt;lmdbAbort(txn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a transaction&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lmdbDb(txn, name)&lt;/code&gt; &lt;code&gt;lmdbClear(txn, db)&lt;/code&gt; &lt;code&gt;lmdbStat(txn, db)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a database inside it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lmdbGet&lt;/code&gt; &lt;code&gt;lmdbHas&lt;/code&gt; &lt;code&gt;lmdbPut&lt;/code&gt; &lt;code&gt;lmdbDelete&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one key&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;lmdbCursor(txn, db)&lt;/code&gt; &lt;code&gt;lmdbFirst&lt;/code&gt; &lt;code&gt;lmdbNext&lt;/code&gt; &lt;code&gt;lmdbSeek(cur, key)&lt;/code&gt; &lt;code&gt;lmdbCursorClose&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a range&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;A key or a value may be text or bytes, and what comes back is always bytes.&lt;/strong&gt; Text crosses as its
UTF-8, which is what &lt;code&gt;toBytes&lt;/code&gt; would have made of it and what would have gone onto a wire either
way; LMDB records nothing about which of the two it was given, so &lt;code&gt;fromBytes&lt;/code&gt; is how a program that
wrote text reads it back.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A named database is itself a key in the unnamed one&lt;/strong&gt;, which is where LMDB keeps the name-to-handle
mapping — so the unnamed database of a store with three named ones has three keys in it before a
program writes anything. Keep ordinary keys somewhere else, or behind a prefix.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lmdbDb(txn, null)&lt;/code&gt; is the store’s unnamed database&lt;/strong&gt;, which is always there. A named one needs
&lt;code&gt;maxDbs&lt;/code&gt; to have been large enough at &lt;code&gt;lmdbOpen&lt;/code&gt;, and — the first time — a write transaction, since
making it writes. &lt;strong&gt;Whether it is created is decided by which transaction asked&lt;/strong&gt; rather than by an
option: a reader cannot write, so a reader asking for a database that does not exist wanted
&lt;code&gt;lmdbWrite&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-is-an-answer-and-what-is-a-failure&quot;&gt;What is an answer and what is a failure&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A key that is not there is &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt;, and &lt;code&gt;lmdbDelete&lt;/code&gt; on one is &lt;code&gt;false&lt;/code&gt;. A store is asked about
keys it does not have as a matter of course — that is what a session lookup on a first request is —
so the ordinary case must not be the exceptional one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everything else faults with a sentence.&lt;/strong&gt; A store is opened once at start-up and every call after
it is a program touching its own data, so there is no result to thread through every call site; a
&lt;code&gt;catch&lt;/code&gt; is there for the two that a running server really can hit, which are a full map and a disk
that will not take a write.&lt;/p&gt;
&lt;h2 id=&quot;mapsize-is-a-hard-ceiling-and-never-a-hint&quot;&gt;&lt;code&gt;mapSize&lt;/code&gt; is a hard ceiling and never a hint&lt;/h2&gt;
&lt;p&gt;LMDB reserves that much address space when the store is opened and &lt;strong&gt;never grows it&lt;/strong&gt;. A write past
it fails and the store has to be reopened larger — there is no growing it in place, and no amount of
free disk changes that.&lt;/p&gt;
&lt;p&gt;It costs nothing until it is used, the map being sparse, so &lt;strong&gt;naming a figure far larger than the
data is the normal thing to do&lt;/strong&gt;: a gigabyte for a session store is not a gigabyte of anything.
&lt;code&gt;lmdbInfo&lt;/code&gt; answers &lt;code&gt;{ mapSize, used, maxReaders, readers, lastTransaction }&lt;/code&gt;, and &lt;code&gt;used&lt;/code&gt; against
&lt;code&gt;mapSize&lt;/code&gt; is the only meaningful fraction — the number of keys says nothing about how much room is
left.&lt;/p&gt;
&lt;p&gt;The default is 10 MB, which is deliberately small enough to be wrong for anything real. &lt;code&gt;maxDbs&lt;/code&gt;
defaults to 16, which is not LMDB’s own default of &lt;em&gt;none&lt;/em&gt;: a program that asked for a database by
name would otherwise be refused on its very first call.&lt;/p&gt;
&lt;h2 id=&quot;two-readers-at-once-which-is-what-most-bindings-get-wrong&quot;&gt;Two readers at once, which is what most bindings get wrong&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;LMDB’s default gives each thread ONE reader slot&lt;/strong&gt;, and a second read transaction on a thread that
already holds one is refused with &lt;code&gt;MDB_BAD_RSLOT&lt;/code&gt; — whose own message, &lt;em&gt;“Invalid reuse of reader
locktable slot”&lt;/em&gt;, reads as a damaged lock file rather than the design decision it is.&lt;/p&gt;
&lt;p&gt;slate opens every store with &lt;code&gt;MDB_NOTLS&lt;/code&gt;, which moves the slot onto the transaction. Two request
handlers each holding a reader is the ordinary case here, so &lt;strong&gt;there is no option for this&lt;/strong&gt; and a
program cannot turn the refusal back on.&lt;/p&gt;
&lt;h2 id=&quot;a-transaction-that-is-merely-dropped-aborts&quot;&gt;A transaction that is merely dropped aborts&lt;/h2&gt;
&lt;p&gt;That is the safe way round: a handler that throws halfway through a sequence of writes leaves the
store as it was, and one that meant to keep the work has already said so with &lt;code&gt;lmdbCommit&lt;/code&gt;. The end
of a program does the same to everything still open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;lmdbClose&lt;/code&gt; ends every transaction still open on the store&lt;/strong&gt;, cursors first, in the order LMDB
requires — a server shutting down must not be stopped by a handler that was mid-write.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A cursor dies with its transaction.&lt;/strong&gt; LMDB frees the transaction structure when one ends and a
cursor holds a pointer into it, so a cursor used afterwards would be reading pages LMDB has
reclaimed; slate refuses instead. &lt;code&gt;lmdbCursorClose&lt;/code&gt; is for a long-lived reader making many walks,
where the cursors would otherwise pile up until it committed.&lt;/p&gt;
&lt;h2 id=&quot;a-range-is-a-cursor-and-byte-order&quot;&gt;A range is a cursor and byte order&lt;/h2&gt;
&lt;p&gt;Keys come out in byte order, so &lt;strong&gt;a prefix is a contiguous run&lt;/strong&gt;: &lt;code&gt;lmdbSeek(cur, &amp;quot;u:&amp;quot;)&lt;/code&gt; moves to that
key or the first one after it, and &lt;code&gt;lmdbNext&lt;/code&gt; walks from there. That is the whole of a prefix scan,
and it works whether or not &lt;code&gt;u:&lt;/code&gt; is itself a key.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; cur &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbCursor&lt;/span&gt;(r, db)
&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; at &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbSeek&lt;/span&gt;(cur, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;u:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;while&lt;/span&gt; at &lt;span class=&quot;hl-keyword&quot;&gt;!=&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;&amp;amp;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;startsWith&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(at&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;key)&lt;span class=&quot;hl-keyword&quot;&gt;.&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;u:&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;fromBytes&lt;/span&gt;(at&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;key)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)
    at &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;lmdbNext&lt;/span&gt;(cur)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;lmdbFirst&lt;/code&gt; starts at the beginning, and the end of a walk is &lt;code&gt;null&lt;/code&gt;.&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;A session store, a token bucket, a replay ring.&lt;/strong&gt; Each is a key layout and an expiry rule — a
policy — and policy belongs in a package rather than in the compiler. What is here is the store they
are all written over, which is &lt;a href=&quot;/library/llhttp/&quot;&gt;&lt;code&gt;slate:llhttp&lt;/code&gt;&lt;/a&gt;‘s arrangement exactly: the state machine
is slate’s and what is built on it is not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Duplicate-key databases, custom orderings and nested transactions&lt;/strong&gt;, all of which LMDB has. None
has been needed yet, and a comparator that disagrees between two openings of one database corrupts it
silently — a sharp enough edge to want a design rather than a wrapper.&lt;/p&gt;
&lt;h2 id=&quot;the-interpreter-only&quot;&gt;The interpreter only&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;No JavaScript host has LMDB and every name here refuses under &lt;code&gt;slate js&lt;/code&gt;.&lt;/strong&gt; A browser has no
memory-mapped file at all — &lt;code&gt;IndexedDB&lt;/code&gt; and the Origin Private File System are what a page stores
things in, and neither is an ordered B+tree walked with a cursor — and node has no LMDB in its
standard library either: every binding on npm is a native addon, so a compiled program would depend
on something the tool cannot see and did not install.&lt;/p&gt;
&lt;p&gt;So this is a refusal naming LMDB rather than a &lt;code&gt;not in the JavaScript back end yet&lt;/code&gt; stub, which is
&lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt;‘s case and gets its treatment. &lt;code&gt;docs/reference/javascript.md&lt;/code&gt; lists it
with the rest.&lt;/p&gt;
&lt;h2 id=&quot;the-library&quot;&gt;The library&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Not vendored&lt;/strong&gt; — LMDB is the library the machine has: &lt;code&gt;brew install lmdb&lt;/code&gt; on macOS, &lt;code&gt;liblmdb-dev&lt;/code&gt;
on Debian and Ubuntu, &lt;code&gt;lmdb&lt;/code&gt; on Arch. pkg-config finds it on all three.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:llhttp</title>
    <link href="https://slatelang.dev/library/llhttp/"/>
    <id>https://slatelang.dev/library/llhttp/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>The HTTP parser itself — the state machine under slate:http.</summary>
    <content type="html">&lt;h1 id=&quot;slatellhttp&quot;&gt;&lt;code&gt;slate:llhttp&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;The HTTP parser itself — the state machine under &lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { httpParser, httpFeed, httpTake } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:llhttp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;httpParser  httpStream  httpFeed  httpTake  httpTakePart  httpFinish  httpClose  httpUpgraded&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;This is the lowest module slate has, and it is public on purpose.&lt;/strong&gt; &lt;code&gt;slate:http&lt;/code&gt; is the server a program
wants; this is for the programs that want something else — a proxy, a client that keeps its connections, a
test double that has to answer exactly the bytes it was asked about, or a protocol that begins as HTTP and
then stops being it. &lt;strong&gt;Every one of those is an ordinary package&lt;/strong&gt;, where otherwise it would have been a
change to slate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Node hid the same seam and its own client had to route around it&lt;/strong&gt;: undici carries llhttp compiled to
wasm because &lt;code&gt;internalBinding(&apos;http_parser&apos;)&lt;/code&gt; is not reachable. Two parsers in one process is the cost of
that policy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The names keep their &lt;code&gt;http&lt;/code&gt; prefix&lt;/strong&gt; rather than being shortened to fit the module. They are the seam
&lt;code&gt;slate:http&lt;/code&gt; is written against and they are spelled this way inside it, so a reader moving between the
module’s source and a package that uses the same calls sees one vocabulary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Under &lt;a href=&quot;/reference/javascript/&quot;&gt;&lt;code&gt;slate js&lt;/code&gt;&lt;/a&gt; the grammar is written out rather than bound&lt;/strong&gt;, node’s
own parser being unreachable from a program — which is the seam node hid and the reason undici carries
llhttp compiled to wasm. The two readings answer the same things about the same bytes, which is what
&lt;code&gt;tests/js/p26.sl&lt;/code&gt; is for; a browser has no sockets to read from and every name refuses there.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Lexical structure</title>
    <link href="https://slatelang.dev/reference/lexical/"/>
    <id>https://slatelang.dev/reference/lexical/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>What the compiler reads before it reads anything else: files, whitespace, names and literals.</summary>
    <content type="html">&lt;h1 id=&quot;lexical-structure&quot;&gt;Lexical structure&lt;/h1&gt;
&lt;p&gt;What the compiler reads before it reads anything else: files, whitespace, names and literals.&lt;/p&gt;
&lt;h2 id=&quot;files&quot;&gt;Files&lt;/h2&gt;
&lt;p&gt;A slate program is a &lt;strong&gt;&lt;code&gt;.sl&lt;/code&gt;&lt;/strong&gt; file. A file that writes &lt;a href=&quot;/reference/elements/&quot;&gt;elements&lt;/a&gt; is conventionally
&lt;strong&gt;&lt;code&gt;.slx&lt;/code&gt;&lt;/strong&gt;, after &lt;code&gt;.tsx&lt;/code&gt; — but the extension says nothing to the compiler, which parses both the same
way, and elements are read in every file. It is a name for a reader and an editor.&lt;/p&gt;
&lt;p&gt;A file with a &lt;code&gt;#!&lt;/code&gt; line on its first byte is a command. slate skips that line and everything after
the program’s name on the command line belongs to the program:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-comment&quot;&gt;#!/usr/bin/env slate&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { args, exit } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:process

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; args&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;==&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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;usage: greet &amp;lt;name&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;for&lt;/span&gt; name &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; args
    &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; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; name &lt;span class=&quot;hl-keyword&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;!&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: greet &amp;lt;name&amp;gt;...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;#!&lt;/code&gt; is read at the very first byte and nowhere else. &lt;strong&gt;&lt;code&gt;#&lt;/code&gt; is not a comment in slate.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;comments&quot;&gt;Comments&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;//&lt;/code&gt; to the end of the line. There is no block comment.&lt;/p&gt;
&lt;h2 id=&quot;indentation-is-structure&quot;&gt;Indentation is structure&lt;/h2&gt;
&lt;p&gt;slate is off-side ruled, as Python and sysl are. A block is opened by indenting under the line that
introduces it and closed by returning to the outer column.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A newline inside brackets means nothing&lt;/strong&gt;, which is what lets an argument list or an array literal
be split across lines. Two tokens suspend that rule, and only where they end a line: &lt;strong&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/strong&gt; and
&lt;strong&gt;&lt;code&gt;match&lt;/code&gt;&lt;/strong&gt;. Either one at the end of a line opens a block even inside brackets, which is what lets a
callback with a real body be written where it is passed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;forEach&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;], x &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; doubled &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&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;(x, doubled))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2
2 4
3 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An arrow written mid-line would hand the block to whatever line came next, so it does not open one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A block lambda has to be the last argument&lt;/strong&gt;, because its block runs to the end of its last line
and a &lt;code&gt;,&lt;/code&gt; arriving there has nothing to mean.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A trailing operator does not continue a line.&lt;/strong&gt; &lt;code&gt;a +&lt;/code&gt; followed by &lt;code&gt;b&lt;/code&gt; on the next line is two
statements, not a sum. Where an expression has to span lines, brackets are what say so — inside them
the off-side rule is suspended and the continuation is unambiguous:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;isShort&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;isKnown&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&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;ada&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; name &lt;span class=&quot;hl-keyword&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;ada&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; ok &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (
    &lt;span class=&quot;hl-function&quot;&gt;isShort&lt;/span&gt;(name) &lt;span class=&quot;hl-keyword&quot;&gt;||&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;isKnown&lt;/span&gt;(name))

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(ok)&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;h2 id=&quot;end-and-the-closing-words&quot;&gt;&lt;code&gt;end&lt;/code&gt;, and the closing words&lt;/h2&gt;
&lt;p&gt;A block that has grown long enough to want a closing marker takes one: &lt;code&gt;end if&lt;/code&gt;, &lt;code&gt;end while&lt;/code&gt;,
&lt;code&gt;end for&lt;/code&gt;, &lt;code&gt;end loop&lt;/code&gt;, &lt;code&gt;end &amp;lt;name&amp;gt;&lt;/code&gt; for a definition or a class. &lt;strong&gt;&lt;code&gt;end&lt;/code&gt; is a soft word&lt;/strong&gt; — a program
may still call something &lt;code&gt;end&lt;/code&gt; — and so are &lt;code&gt;class&lt;/code&gt;, &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;type&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;names&quot;&gt;Names&lt;/h2&gt;
&lt;p&gt;An identifier is a letter or &lt;code&gt;_&lt;/code&gt; followed by letters, digits and &lt;code&gt;_&lt;/code&gt;. Names are case-sensitive.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The type words are not keywords.&lt;/strong&gt; &lt;code&gt;null&lt;/code&gt;, &lt;code&gt;boolean&lt;/code&gt;, &lt;code&gt;integer&lt;/code&gt;, &lt;code&gt;real&lt;/code&gt;, &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;,
&lt;code&gt;array&lt;/code&gt;, &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;function&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;zone&lt;/code&gt; and the rest of the twenty-one listed in
&lt;a href=&quot;/reference/patterns/&quot;&gt;Patterns&lt;/a&gt; are ordinary names in expression position — &lt;code&gt;val int = 3&lt;/code&gt; and &lt;code&gt;val date = readIt()&lt;/code&gt; both work — and are read as type tests only in
&lt;a href=&quot;/reference/patterns/&quot;&gt;pattern position&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There are no abbreviations.&lt;/strong&gt; It is &lt;code&gt;boolean&lt;/code&gt; and &lt;code&gt;function&lt;/code&gt;, never &lt;code&gt;bool&lt;/code&gt; and &lt;code&gt;fn&lt;/code&gt;; a short form
is refused with the long one named.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A keyword may name a FIELD&lt;/strong&gt;, as it may in JavaScript — after a &lt;code&gt;.&lt;/code&gt;, in an object literal, in a
&lt;code&gt;with&lt;/code&gt;, and as a pattern’s key. A word the grammar happens to use is not a word a program controls:
somebody else’s JSON has an &lt;code&gt;if&lt;/code&gt; in it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; o &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&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; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&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;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt;, o&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt;, (o &lt;span class=&quot;hl-keyword&quot;&gt;with&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; &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt; })&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt;)

&lt;span class=&quot;hl-keyword&quot;&gt;val&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; n } &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; o

&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;1 2 9
2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A keyword still may not name a BINDING&lt;/strong&gt;, so the &lt;code&gt;{ name }&lt;/code&gt; shorthand has nothing to introduce
where the key is one, and says so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; { &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&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 a word the grammar has taken
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;literals&quot;&gt;Literals&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; text &lt;span class=&quot;hl-keyword&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;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;print&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;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-number&quot;&gt;42&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;1_000_000&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0xff&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0b1011&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0o17&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3.14&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2e10&lt;/span&gt;, &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;(&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-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;interpolated &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;text&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-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;0&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;({ a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&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;0&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;..&amp;lt;&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-keyword&quot;&gt;..&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;null true false
42 -7 1000000
255 11 15
3.14 2e+10 0.001
text interpolated it
[1, 2, 3] [0, 0, 0, 0, 0]
{a: 1, b: 2}
0..&amp;lt;3 1..10
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An integer may be written in hexadecimal, binary or octal, and &lt;code&gt;_&lt;/code&gt; may be written between digits of
any of them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Integers and reals are separate values&lt;/strong&gt;, not one numeric type. An integer is 64 bits, wraps, and
divides towards zero.&lt;/p&gt;
&lt;p&gt;Every comma list takes a &lt;strong&gt;trailing comma&lt;/strong&gt;: an array, an object, an argument list, a parameter list.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[v; n]&lt;/code&gt; is an array of &lt;code&gt;n&lt;/code&gt; copies of &lt;code&gt;v&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;strings&quot;&gt;Strings&lt;/h2&gt;
&lt;p&gt;A string literal is double-quoted with the usual escapes (&lt;code&gt;\n&lt;/code&gt;, &lt;code&gt;\t&lt;/code&gt;, &lt;code&gt;\\&lt;/code&gt;, &lt;code&gt;\&amp;quot;&lt;/code&gt;, &lt;code&gt;\u{...}&lt;/code&gt;). There is
no single-quoted form and no character type — &lt;strong&gt;a single character is a string of one&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;An &lt;strong&gt;s-string&lt;/strong&gt; interpolates:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; w &lt;span class=&quot;hl-keyword&quot;&gt;=&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; h &lt;span class=&quot;hl-keyword&quot;&gt;=&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; point &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&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-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-punctuation&quot;&gt;${&lt;/span&gt;w&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;h&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;s&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;w&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)           &lt;span class=&quot;hl-comment&quot;&gt;// the same thing&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-punctuation&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;point&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-comment&quot;&gt;// interpolates `point`, then `.x` is text&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-punctuation&quot;&gt;${&lt;/span&gt;point&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;x&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-comment&quot;&gt;// says the other thing&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;costs 5$&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)           &lt;span class=&quot;hl-comment&quot;&gt;// a `$` that begins no name is just itself&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;&amp;quot;&lt;/span&gt;)                 &lt;span class=&quot;hl-comment&quot;&gt;// a literal `$`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3 by 4
3 by 4
{x: 7}.x
7
costs 5$
$
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A hole that is a single name needs no braces.&lt;/strong&gt; The short form is identifier-only and stops at the
end of the name, which is why &lt;code&gt;$point.x&lt;/code&gt; and &lt;code&gt;${point.x}&lt;/code&gt; differ.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no raw string.&lt;/strong&gt; A backslash in a string is an escape wherever it appears, so a regular
expression written as a literal doubles its backslashes: &lt;code&gt;regex(&amp;quot;\\d+&amp;quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-a-program-never-writes&quot;&gt;What a program never writes&lt;/h2&gt;
&lt;p&gt;There is no &lt;code&gt;undefined&lt;/code&gt;, no &lt;code&gt;NaN&lt;/code&gt; that spreads, and no &lt;code&gt;Invalid Date&lt;/code&gt;. Each of those is a value that
travels through a program silently changing what everything downstream computes, and slate has none
of them: the equivalent situation is either a &lt;code&gt;null&lt;/code&gt; the program can test or a fault it can catch.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:jwt</title>
    <link href="https://slatelang.dev/library/jwt/"/>
    <id>https://slatelang.dev/library/jwt/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>JSON Web Tokens, written in slate.</summary>
    <content type="html">&lt;h1 id=&quot;slatejwt&quot;&gt;&lt;code&gt;slate:jwt&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;JSON Web Tokens, written in slate.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sign, verify, decode } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:jwt

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; token &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sign&lt;/span&gt;({ sub&lt;span class=&quot;hl-keyword&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;alice&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, exp&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; when &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3600&lt;/span&gt; }, secret, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;HS256&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; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;verify&lt;/span&gt;(token, secret, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;HS256&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&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;sign(claims, key, alg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;verify(token, key, alg)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;result&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;decode(token)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the claims, unverified&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;the-algorithm-is-an-argument-because-the-alg-header-is-not-to-be-trusted&quot;&gt;The algorithm is an argument because the &lt;code&gt;alg&lt;/code&gt; header is not to be trusted&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;That is the whole security of the thing.&lt;/strong&gt; A verifier that read the algorithm out of the token it is
checking accepts whatever an attacker wrote there — &lt;code&gt;alg: none&lt;/code&gt; was accepted by most libraries for years,
and the RS256-public-key-used-as-an-HMAC-secret confusion turns a &lt;em&gt;published&lt;/em&gt; key into a signing key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The caller says what it expects, the header is compared against it before a signature is checked at all&lt;/strong&gt;,
and a token that disagrees is refused there.&lt;/p&gt;
&lt;p&gt;HS256/384/512, RS, PS and ES.&lt;/p&gt;
&lt;h2 id=&quot;three-arguments-and-no-options-object&quot;&gt;Three arguments and no options object&lt;/h2&gt;
&lt;p&gt;All three are decisions the caller has to make, and an option is for what has a sensible answer when nobody
says. &lt;strong&gt;Extra header fields — &lt;code&gt;kid&lt;/code&gt;, above all — go in the claims under &lt;code&gt;header&lt;/code&gt;&lt;/strong&gt;, and are taken &lt;em&gt;out&lt;/em&gt;
rather than signed: a claim called &lt;code&gt;header&lt;/code&gt; would be a surprising thing to find in a payload you signed.&lt;/p&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A malformed token, a bad signature and an expired claim are all answers&lt;/strong&gt;, because a program handling
requests wants to say &lt;code&gt;401&lt;/code&gt; and carry on. &lt;strong&gt;A key that is not a key faults&lt;/strong&gt;, being the program’s own
mistake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An HMAC tag is compared in constant time&lt;/strong&gt;, and that is not superstition: a comparison that stops at the
first differing byte tells an attacker how much of a forged tag was right. The asymmetric algorithms need
no such care, verifying a signature not being a comparison.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>JavaScript</title>
    <link href="https://slatelang.dev/reference/javascript/"/>
    <id>https://slatelang.dev/reference/javascript/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>slate js reads the same tree the interpreter walks and writes one self-contained JavaScript file — the runtime, any framework, and the program. There is no bundler, no node_modules, and…</summary>
    <content type="html">&lt;h1 id=&quot;javascript&quot;&gt;JavaScript&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;$ slate js hello.sl -o hello.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;slate js&lt;/code&gt; reads the same tree the interpreter walks and writes &lt;strong&gt;one self-contained JavaScript file&lt;/strong&gt; —
the runtime, any framework, and the program. There is no bundler, no &lt;code&gt;node_modules&lt;/code&gt;, and nothing to
install beside it. The output runs under node, under quickjs, and in a browser.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;slate test --js .&lt;/code&gt; compiles a whole directory into one program and runs it under node, reporting in the
same words &lt;code&gt;slate test&lt;/code&gt; does. &lt;strong&gt;A test is written about the language rather than about an implementation
of it&lt;/strong&gt;, so the same file is the check that the two back ends have not drifted apart — which is worth more
than it sounds, since a test driving the interpreter says nothing whatever about &lt;code&gt;slate js&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-value-model&quot;&gt;The value model&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An integer is a &lt;code&gt;BigInt&lt;/code&gt; and a real is a &lt;code&gt;number&lt;/code&gt;, and every operator goes through the runtime.&lt;/strong&gt; This is
the decision everything else follows from, and it is not caution: slate’s integer is 64 bits, wraps,
divides towards zero and shifts to 63 places, and a double does none of those — nor could it be told from
a real afterwards, so &lt;code&gt;2.5 is integer&lt;/code&gt; would answer whatever the value happened to look like.&lt;/p&gt;
&lt;p&gt;The operators follow because the two languages disagree too often for the exceptions to be worth tracking:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;slate&lt;/th&gt;&lt;th&gt;JavaScript&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;7 / 2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;3.5&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;0&lt;/code&gt; in a condition&lt;/td&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;[1] == [1]&lt;/code&gt;&lt;/td&gt;&lt;td&gt;true&lt;/td&gt;&lt;td&gt;false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;1 &amp;lt;&amp;lt; 40&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2^40&lt;/td&gt;&lt;td&gt;256&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;One thing &lt;code&gt;print&lt;/code&gt; says differently, and it is not closable cheaply.&lt;/strong&gt; A promise prints as
&lt;code&gt;&amp;lt;promise pending&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;promise 5&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;promise failed: …&amp;gt;&lt;/code&gt; in the interpreter and as &lt;code&gt;&amp;lt;promise&amp;gt;&lt;/code&gt;
here: a JavaScript promise does not expose its state synchronously, and wrapping every promise in the
runtime so that &lt;code&gt;print&lt;/code&gt; could read one would cost every &lt;code&gt;await&lt;/code&gt; in every program to improve a
debugging accident. Printing a promise is not something a program’s output should depend on either
way.&lt;/p&gt;
&lt;h2 id=&quot;what-is-not-there-yet&quot;&gt;What is not there yet&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:process&lt;/code&gt;‘s &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;slate:redis&lt;/code&gt;, &lt;code&gt;slate:nghttp2&lt;/code&gt;, and TLS.&lt;/strong&gt; Each is a
name that says &lt;em&gt;“not in the JavaScript back end yet”&lt;/em&gt; when a program reaches it, rather than a name
that is not there — so a program is told which half of the world it is in. &lt;strong&gt;No global is on that
list any more&lt;/strong&gt;; &lt;code&gt;fetch&lt;/code&gt; was the last and has its own section below.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:net&lt;/code&gt; and &lt;code&gt;slate:llhttp&lt;/code&gt; came OFF that list in 0.0.31&lt;/strong&gt;, and they are what everything above
a socket stands on — see the section below. What is still owed of the transport is TLS: &lt;code&gt;startTls&lt;/code&gt;
refuses naming it, and &lt;code&gt;listen&lt;/code&gt; given a &lt;code&gt;cert&lt;/code&gt; and a &lt;code&gt;key&lt;/code&gt; refuses in the same words, so an HTTPS
server is the interpreter’s for now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:zstd&lt;/code&gt; is WHOLE here on node and absent in a browser, which is the same rule read twice.&lt;/strong&gt; node
has carried Zstandard in &lt;code&gt;zlib&lt;/code&gt; since 22.15, so &lt;code&gt;zstd&lt;/code&gt; and &lt;code&gt;unzstd&lt;/code&gt; are the host’s own there; no browser
has a &lt;code&gt;CompressionStream(&amp;quot;zstd&amp;quot;)&lt;/code&gt; and none is coming, so both refuse in a page naming zstd. &lt;strong&gt;The frames
are not compared between the back ends and cannot be&lt;/strong&gt; — node links its own copy of libzstd and the
interpreter links the machine’s, so two encoders at one level may frame the same input differently and
both be right. &lt;code&gt;tests/js/p27.sl&lt;/code&gt; compares the round trip and every refusal instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:image&lt;/code&gt; is NOT on that list either, and its two hosts refuse for two different reasons.&lt;/strong&gt;
node has no image support in its standard library at all — every reader anybody uses is an npm
dependency — so &lt;em&gt;“not yet”&lt;/em&gt; would be a promise nothing can keep without one. A browser &lt;strong&gt;does&lt;/strong&gt;
decode, through &lt;code&gt;createImageBitmap&lt;/code&gt; and &lt;code&gt;OffscreenCanvas&lt;/code&gt;, and is refused anyway: the whole of that
surface answers &lt;strong&gt;promises&lt;/strong&gt; where &lt;code&gt;readImage&lt;/code&gt; and its four siblings answer on the spot, so a browser
half would make the two back ends disagree about what an image is. That is &lt;code&gt;crypto.subtle&lt;/code&gt;‘s rule
again — a host that has a thing only in a different shape does not have it — and it means
&lt;a href=&quot;/library/image/&quot;&gt;&lt;code&gt;slate:image&lt;/code&gt;&lt;/a&gt; is a server’s module.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:crypto&lt;/code&gt;‘s ARGON2 IS node’s OWN AND A BROWSER HAS NONE&lt;/strong&gt;, which is &lt;code&gt;slate:zstd&lt;/code&gt;‘s rule read once
more. node carries Argon2id in its core &lt;code&gt;crypto&lt;/code&gt; — &lt;code&gt;crypto.argon2&lt;/code&gt; — so &lt;code&gt;argon2&lt;/code&gt; and &lt;code&gt;argon2Verify&lt;/code&gt; are the
host’s there, and &lt;strong&gt;the records are compared between the back ends rather than merely round-tripped&lt;/strong&gt;: node
and monocypher derive the same bytes for the same parameters, so &lt;code&gt;tests/js/p30.sl&lt;/code&gt; verifies a record the
interpreter made against a fixed salt and the interpreter verifies one node made. A digest that agreed with
itself and with nothing else would still be caught.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The web platform has no Argon2 at all, and &lt;code&gt;crypto.subtle&lt;/code&gt; is not a near miss.&lt;/strong&gt; Its &lt;code&gt;deriveBits&lt;/code&gt; speaks
PBKDF2 and HKDF, both fast by construction and neither memory-hard — so building the page half on one of
those would be a password hash weaker than the same program gets on a server, under the same name, silently.
Both refuse in a page, naming Argon2 and saying what a browser has instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;argon2NeedsRehash&lt;/code&gt; works everywhere, including in a page.&lt;/strong&gt; It derives nothing — it reads the parameters
out of the record and compares them — so it is a string parse, and a page that stores records it cannot make
can still say which of them are due to be re-made.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:sqlite&lt;/code&gt; is WHOLE here on node and absent in a browser&lt;/strong&gt;, which is &lt;code&gt;slate:zstd&lt;/code&gt;‘s answer read
again. node has carried &lt;code&gt;node:sqlite&lt;/code&gt; since 22.5, so the module’s floor is &lt;code&gt;DatabaseSync&lt;/code&gt; there and the
machine’s libsqlite3 here, with one piece of slate source above both — the same object with the same five
methods either way. A page has no SQLite of any kind (IndexedDB is not this, and Web SQL is long
deprecated), so every name refuses there naming node’s module.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The one thing the JavaScript floor has to compute that the interpreter is told&lt;/strong&gt; is how many parameters
a statement takes: node exposes no &lt;code&gt;sqlite3_bind_parameter_count&lt;/code&gt;, and without it the two would disagree
about the commonest mistake there is — node binds SQL NULL for a &lt;code&gt;?&lt;/code&gt; nobody gave, so &lt;code&gt;where id = ?&lt;/code&gt; called
with nothing runs, matches nothing and says nothing. &lt;code&gt;js_rt_sqlite.sysl&lt;/code&gt; reads the count off the SQL, which
is what lets both back ends refuse it with one sentence. &lt;code&gt;tests/js/p28.sl&lt;/code&gt; compares the storage classes,
the transaction, the full-text search and every refusal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:brotli&lt;/code&gt; is NOT on that list, and the difference matters.&lt;/strong&gt; No JavaScript host has a brotli
encoder and none is coming, so &lt;em&gt;“not yet”&lt;/em&gt; would be a promise nobody can keep. &lt;code&gt;compress&lt;/code&gt; and
&lt;code&gt;decompress&lt;/code&gt; say that they are brotli, that a JavaScript host has none, and that
&lt;a href=&quot;/library/gzip/&quot;&gt;&lt;code&gt;slate:gzip&lt;/code&gt;&lt;/a&gt; is the compression a browser does have. That is &lt;code&gt;abbrev&lt;/code&gt;‘s case
below, drawn the same way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;/library/lmdb/&quot;&gt;&lt;code&gt;slate:lmdb&lt;/code&gt;&lt;/a&gt; is not on that list either, and all nineteen of its names
refuse.&lt;/strong&gt; A browser has no memory-mapped file at all — &lt;code&gt;IndexedDB&lt;/code&gt; and the Origin Private File System
are what a page stores things in, and neither is an ordered B+tree walked with a cursor — and node
has no LMDB in its standard library: every binding on npm is a native addon, so a program compiled by
&lt;code&gt;slate js&lt;/code&gt; would depend on something the tool cannot see and did not install. Each refusal names the
call, says it is LMDB, and says the module runs in the interpreter only.&lt;/p&gt;
&lt;h3 id=&quot;slategzip-is-whole-here-and-the-container-is-read-by-slate-rather-than-by-the-host&quot;&gt;&lt;code&gt;slate:gzip&lt;/code&gt; is whole here, and the container is read by slate rather than by the host&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;This is the module the parity rule was written for.&lt;/strong&gt; A browser has &lt;code&gt;CompressionStream&lt;/code&gt; and
&lt;code&gt;DecompressionStream&lt;/code&gt;, which speak gzip, zlib and raw deflate — so gzip and zlib are compression a
slate program can count on anywhere, where brotli is not.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { gzip, gunzip } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:gzip

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; small &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gzip&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;&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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; back &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gunzip&lt;/span&gt;(small, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&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;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;hl-keyword&quot;&gt;==&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;&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;))

&lt;span class=&quot;hl-function&quot;&gt;main&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;strong&gt;All four names answer promises on BOTH hosts, and that is the whole shape decision.&lt;/strong&gt; A
&lt;code&gt;CompressionStream&lt;/code&gt; is a &lt;code&gt;TransformStream&lt;/code&gt;; there is no synchronous door to it, and slate’s rule is
that a host with a thing only in a different SHAPE does not have it. Nothing held the signature yet —
the module is new — so it was written promise-shaped everywhere rather than synchronous in one place
and refusing in the other. The interpreter compresses with miniz and answers a promise it has already
settled.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The gzip header and trailer are parsed by slate on both back ends&lt;/strong&gt;, and only the deflate body goes
to the host’s stream. That is what makes the refusals the same sentence wherever a program runs: the
magic bytes, the compression method, a header that ends early, the limit, the stated length and the
CRC-32 are all slate’s own checks, and the CRC is computed here rather than taken from anybody.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One sentence is not shared, and it is the body itself.&lt;/strong&gt; miniz says whether a stream that would not
inflate was truncated or corrupt; a host’s decompressor throws one &lt;code&gt;TypeError&lt;/code&gt; for both, and for a
wrong checksum too. So where the interpreter says &lt;em&gt;this compressed stream ends in the middle&lt;/em&gt; or
&lt;em&gt;this is not a compressed stream at all&lt;/em&gt;, a JavaScript host says &lt;em&gt;this compressed stream could not be
read&lt;/em&gt; — a plain statement rather than a guess dressed as a finding. &lt;strong&gt;zlib’s own two-byte header is
checked here as well&lt;/strong&gt;, so the common case — something that is not a zlib stream at all — does read
the same on both.&lt;/p&gt;
&lt;h3 id=&quot;slatecrypto-is-whole-here-and-webcrypto-is-not-how&quot;&gt;&lt;code&gt;slate:crypto&lt;/code&gt; is whole here, and WebCrypto is not how&lt;/h3&gt;
&lt;p&gt;The five digests, &lt;code&gt;hmac&lt;/code&gt;, &lt;code&gt;pbkdf2&lt;/code&gt;, &lt;code&gt;randomBytes&lt;/code&gt; and &lt;code&gt;timingSafeEqual&lt;/code&gt; all work, and answer what the
interpreter answers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { md5, sha1, sha256, sha512, hmac, pbkdf2, randomBytes, timingSafeEqual } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:crypto

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; digits &lt;span class=&quot;hl-keyword&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;0123456789abcdef&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;hex&lt;/span&gt;(bs) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(bs, b &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; digits[b &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;16&lt;/span&gt;] &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; digits[b &lt;span class=&quot;hl-keyword&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;16&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;hex&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sha256&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-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hex&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;md5&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-function&quot;&gt;hex&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sha1&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-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hex&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hmac&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SHA-256&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;key&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;message&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;hex&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;pbkdf2&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SHA-1&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;password&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;salt&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;4096&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-function&quot;&gt;len&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;randomBytes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;32&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;timingSafeEqual&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;), &lt;span class=&quot;hl-function&quot;&gt;timingSafeEqual&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;abd&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;ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
900150983cd24fb0d6963f7d28e17f72 a9993e364706816aba3e25717850c26c9cd0d89d
6e9ef29b75fffc5b7abae527d58fdadb2fe42e7219011976917343065f58ed4a
4b007901b765489abead49d926f721d065a429c1
32 true false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;crypto.subtle&lt;/code&gt; IS NOT USED, AND THAT IS THE DECISION EVERYTHING HERE FOLLOWS FROM.&lt;/strong&gt; The web
platform’s only digest is asynchronous and always has been — there is no synchronous hash in a browser
at all — so a &lt;code&gt;sha256&lt;/code&gt; built on it would answer a &lt;em&gt;promise&lt;/em&gt; here and a byte array under the
interpreter. &lt;strong&gt;Two back ends disagreeing about the shape of an answer is worse than either being
slow&lt;/strong&gt;, and it would have taken a breaking change to the interpreter to fix, over a call that costs
microseconds. So the digests are written out in JavaScript and stay synchronous. &lt;code&gt;md5&lt;/code&gt; would have had
to be anyway — WebCrypto has never carried it — so four asynchronous digests and one synchronous was
never on offer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What that costs, measured on node:&lt;/strong&gt; PBKDF2-HMAC-SHA256 at 100,000 iterations is 176 ms here against
7 ms for a native library, and SHA-256 runs at about 280 MiB/s against 3 GiB/s. Roughly 25× either
way. It matters for exactly one call — &lt;strong&gt;a key derivation, which is the one thing here designed to be
slow&lt;/strong&gt; — so an iteration count is worth choosing with a browser in mind: 600,000, which is OWASP’s
current recommendation for SHA-256, is about a second of a page’s main thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;randomBytes&lt;/code&gt; is the one name that reaches for the host, and the host has it.&lt;/strong&gt;
&lt;code&gt;crypto.getRandomValues&lt;/code&gt; is synchronous everywhere, which is what lets the whole module stay
synchronous — the half of &lt;code&gt;slate:crypto&lt;/code&gt; that cannot be written out at any price is the half a browser
does supply.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The asymmetric half of JWS is the one thing that refuses.&lt;/strong&gt; &lt;code&gt;slate:jwt&lt;/code&gt;‘s &lt;code&gt;HS256&lt;/code&gt;, &lt;code&gt;HS384&lt;/code&gt; and
&lt;code&gt;HS512&lt;/code&gt; are HMAC under a JOSE name and work here in full; &lt;code&gt;RS*&lt;/code&gt;, &lt;code&gt;PS*&lt;/code&gt; and &lt;code&gt;ES*&lt;/code&gt; are RSA and ECDSA,
whose only implementation in a browser is &lt;code&gt;crypto.subtle&lt;/code&gt;‘s and answers a promise where &lt;code&gt;jwsSign&lt;/code&gt;
answers bytes. That refusal names the algorithm and the reason, so a reader knows the fix is a choice
rather than a wait.&lt;/p&gt;
&lt;h3 id=&quot;slatetime-is-whole-except-for-two-things-a-javascript-host-does-not-have&quot;&gt;&lt;code&gt;slate:time&lt;/code&gt; is whole, except for two things a JavaScript host does not have&lt;/h3&gt;
&lt;p&gt;An instant, a duration, the clock that reads one and the arithmetic over both work exactly as they do
under the interpreter:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { epochMillis, epochSeconds, seconds, minutes, hours, now } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; t &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;epochMillis&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1756900000000&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;90&lt;/span&gt;), (t &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)) &lt;span class=&quot;hl-keyword&quot;&gt;-&lt;/span&gt; t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;minutes&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;minutes&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-function&quot;&gt;epochSeconds&lt;/span&gt;(t), &lt;span class=&quot;hl-function&quot;&gt;now&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;instant&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2025-09-03T11:46:40Z
2025-09-03T13:16:40Z 2h
1h 30m 90
1756900000 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;And so does the calendar.&lt;/strong&gt; &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;dateTime&lt;/code&gt;, &lt;code&gt;zone&lt;/code&gt;, &lt;code&gt;zoned&lt;/code&gt; and &lt;code&gt;period&lt;/code&gt; are built over
&lt;code&gt;Intl&lt;/code&gt; — the value model, the arithmetic, &lt;code&gt;startOf&lt;/code&gt;, &lt;code&gt;onOrAfter&lt;/code&gt;, &lt;code&gt;format&lt;/code&gt; and the four parsers — and
answer what the interpreter answers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;date&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;, epochSeconds, days, hours, months, parseDate } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:time

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; toronto &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;zone&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;America/Toronto&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; t &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;epochSeconds&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1719792000&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(toronto)

&lt;span class=&quot;hl-comment&quot;&gt;// The Saturday evening before the clocks go forward, which is where a day and twenty-four hours&lt;/span&gt;
&lt;span class=&quot;hl-comment&quot;&gt;// stop being the same length.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; night &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&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-number&quot;&gt;20&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(toronto)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;year&lt;/span&gt;(), t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;monthName&lt;/span&gt;(), t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;weekday&lt;/span&gt;(), t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;hour&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(t&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;format&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;WWWW, MMMM D, Y |at| h12:mm 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-type&quot;&gt;date&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-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;months&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), night &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;days&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;), night &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hours&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;24&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;dateTime&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2024&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;2&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(toronto)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;parseDate&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;2024-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;.&lt;/span&gt;error)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;2024-06-30T20:00:00-04:00[America/Toronto]
2024 June Sunday 20
Sunday, June 30, 2024 at 8:00 pm
2024-02-29 2024-03-10T20:00:00-04:00[America/Toronto] 2024-03-10T21:00:00-04:00[America/Toronto]
2024-03-10T02:30:00 never happens in America/Toronto -- the clocks go from -05:00 to -04:00 -- say `.at(zone, &amp;quot;after&amp;quot;)` to take the reading past the gap
cannot read &amp;quot;2024-02-30&amp;quot; as a date: day is out of range
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The worry that kept the calendar out was that a zone read from &lt;code&gt;Intl&lt;/code&gt; and a zone read from the IANA
database are two answers to one question, and a program saying what time a meeting is in Toronto may
not get a different answer for having been compiled rather than interpreted. &lt;strong&gt;That was a worry rather
than a measurement, and it has been measured&lt;/strong&gt;: every zone this machine has, 598 of them, at six
instants. The two agree on &lt;strong&gt;all 2985 readings from 2000 through 2025&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Two names still refuse, and neither is owed work — they are things the host does not have.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;abbrev&lt;/code&gt;, because &lt;code&gt;Intl&lt;/code&gt; has no IANA abbreviation at all.&lt;/strong&gt; What its &lt;code&gt;timeZoneName&lt;/code&gt; options carry is
CLDR’s English &lt;em&gt;display&lt;/em&gt; data, which agrees with tzdata for American zones by coincidence and nowhere
else. Measured on one instant:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;zone&lt;/th&gt;&lt;th&gt;IANA&lt;/th&gt;&lt;th&gt;&lt;code&gt;short&lt;/code&gt;&lt;/th&gt;&lt;th&gt;&lt;code&gt;long&lt;/code&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;America/Toronto&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EDT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EDT&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Eastern Daylight Time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Europe/London&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;BST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;GMT+1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;British Summer Time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Asia/Kolkata&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;IST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;GMT+5:30&lt;/code&gt;&lt;/td&gt;&lt;td&gt;India Standard Time&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;Africa/Cairo&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;EEST&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;GMT+3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Eastern European Summer Time&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;67 of 84 readings disagree, and &lt;code&gt;shortGeneric&lt;/code&gt; is worse — “United Kingdom Time”. &lt;code&gt;zzz&lt;/code&gt; in a &lt;code&gt;format&lt;/code&gt;
pattern is the same name under another spelling and refuses with the same sentence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;isDST&lt;/code&gt;, because &lt;code&gt;Intl&lt;/code&gt; exposes no daylight-saving flag&lt;/strong&gt;, and the offset-comparison rule every
JavaScript date library uses instead is unsound in &lt;em&gt;both&lt;/em&gt; directions. Over 3582 readings it is wrong at
31 of them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it &lt;strong&gt;misses&lt;/strong&gt; a zone that is permanently on daylight time. &lt;code&gt;Africa/Casablanca&lt;/code&gt; and &lt;code&gt;Africa/El_Aaiun&lt;/code&gt;
are &lt;code&gt;+01&lt;/code&gt; all year with tzdata’s flag set, and every Argentine zone was in 2000. No comparison of
offsets can see a flag that never changes.&lt;/li&gt;
&lt;li&gt;it &lt;strong&gt;invents&lt;/strong&gt; one for a zone that moved its &lt;em&gt;standard&lt;/em&gt; offset mid-year. &lt;code&gt;Asia/Almaty&lt;/code&gt; and
&lt;code&gt;Asia/Qostanay&lt;/code&gt; went &lt;code&gt;+06&lt;/code&gt; to &lt;code&gt;+05&lt;/code&gt; in March 2024, so January’s offset exceeds May’s and the rule
reads January as daylight time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second half is what settles it: the failure is an ordinary permanent offset change rather than an
exotic zone, so there is no version of the rule that under-reports safely.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The alternative to both — a table of zone rules carried in slate’s own JavaScript runtime — was
considered and refused.&lt;/strong&gt; It would answer them, which is what makes it a decision rather than an
oversight. It is refused because it is a &lt;em&gt;second copy of tzdata&lt;/em&gt;: an authority the runtime would hold
against the one the interpreter reads from the system database, kept in step by hand, in a place nobody
looks until a zone changes and only one of the two back ends notices. The measurement above is exactly
the drift that copy would reintroduce.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One thing the measurement DID find, and it is nobody’s defect.&lt;/strong&gt; The two back ends read two copies of
tzdata — the interpreter reads the host’s &lt;code&gt;/usr/share/zoneinfo&lt;/code&gt; and a JavaScript engine reads the
release bundled into its ICU — and those are not always the same release. On this machine they were
2026c and 2025c, and the seven readings out of 3582 where the offsets disagreed were all at 2038-01-01,
in zones whose &lt;em&gt;future&lt;/em&gt; rules changed in the release between. Each back end reads the database its host
has, which is what both are supposed to do; a program that pins a projected offset decades out is
pinning the skew rather than the calendar.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An instant is a whole number of milliseconds from the clock on both back ends&lt;/strong&gt;, &lt;code&gt;Date.now()&lt;/code&gt; having
nothing finer — the interpreter drops its microseconds to match. An instant a program &lt;em&gt;builds&lt;/em&gt; keeps
every digit: &lt;code&gt;epochMicros(1000000001)&lt;/code&gt; is exact wherever it runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:dom&lt;/code&gt; is the other way round&lt;/strong&gt;: it works only here. Under the interpreter every one of its names
faults with a sentence naming the &lt;em&gt;command&lt;/em&gt; rather than the code, because the same program is correct in a
browser and it is the command that is wrong.&lt;/p&gt;
&lt;h3 id=&quot;slateregex-is-whole-here-and-a-pattern-is-translated-rather-than-handed-over&quot;&gt;&lt;code&gt;slate:regex&lt;/code&gt; is whole here, and a pattern is TRANSLATED rather than handed over&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;RegExp&lt;/code&gt; is not PCRE2. slate’s patterns are Perl’s — that is the whole reason &lt;code&gt;regex.sysl&lt;/code&gt; is on
&lt;code&gt;sh.sysl.pcre2&lt;/code&gt; rather than on POSIX — and a browser has one regular expression engine. So every
pattern is read through a translator on its way in, and what a construct gets depends on how the two
engines differ over it: an exact equivalent is &lt;strong&gt;translated&lt;/strong&gt;, something &lt;code&gt;RegExp&lt;/code&gt; does not have is
&lt;strong&gt;refused naming the construct&lt;/strong&gt;, and something both engines accept while meaning different things is
&lt;strong&gt;translated too&lt;/strong&gt;, because that is the one kind a program could get wrong with nothing refusing it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { &lt;span class=&quot;hl-type&quot;&gt;regex&lt;/span&gt; } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:regex

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&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;(?&amp;lt;y&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;d{4})-(&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;d{2})&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&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;on 2026-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;.&lt;/span&gt;named&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;y)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&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:]]+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&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;42abc!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;text)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;regex&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;p{Greek}+&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&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-variable&quot;&gt;\u{3b1}\u{3b2}&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;.&lt;/span&gt;text)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;regex&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;s&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&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-variable&quot;&gt;\u{a0}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-type&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-keyword&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&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\r&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-type&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-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;w+)@(&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;w+)&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;replace&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 and c@d&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;$2 at $1&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;len&lt;/span&gt;(&lt;span class=&quot;hl-type&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;findAll&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-type&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;.&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;bb&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;join&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;2026
abc
αβ
false true
b at a and d at c
1 |b|b|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Three constructs mean different things in the two engines, and every one is a silent wrong answer
rather than an error.&lt;/strong&gt; They were measured through this project’s own PCRE2 and through node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;\s&lt;/code&gt;.&lt;/strong&gt; PCRE2 here is not in UCP mode, so &lt;code&gt;\s&lt;/code&gt; is the six ASCII spaces; &lt;code&gt;RegExp&lt;/code&gt; reads it as
every Unicode space, twenty-five of them. A record split on &lt;code&gt;\s&lt;/code&gt; would cut on a no-break space in a
browser and not in the interpreter. &lt;code&gt;\s&lt;/code&gt;, &lt;code&gt;\S&lt;/code&gt;, &lt;code&gt;\h&lt;/code&gt;, &lt;code&gt;\H&lt;/code&gt;, &lt;code&gt;\v&lt;/code&gt;, &lt;code&gt;\V&lt;/code&gt; and every POSIX class are
written out as their ranges.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;.&lt;/code&gt;.&lt;/strong&gt; PCRE2’s excludes the newline. &lt;code&gt;RegExp&lt;/code&gt;‘s also excludes the carriage return and the two
Unicode line separators, so it becomes &lt;code&gt;[^\n]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;^&lt;/code&gt; and &lt;code&gt;$&lt;/code&gt; under &lt;code&gt;m&lt;/code&gt;&lt;/strong&gt;, for the same reason and in the same three characters. They become
lookarounds, and &lt;code&gt;RegExp&lt;/code&gt;‘s own &lt;code&gt;m&lt;/code&gt; is never set.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What is refused, and why none of it is work owed.&lt;/strong&gt; A browser’s regular expressions have no
possessive quantifier &lt;code&gt;a*+&lt;/code&gt;, no atomic group &lt;code&gt;(?&amp;gt;…)&lt;/code&gt;, no branch reset &lt;code&gt;(?|…)&lt;/code&gt;, no recursion &lt;code&gt;(?R)&lt;/code&gt;, no
conditional &lt;code&gt;(?(1)…)&lt;/code&gt;, no &lt;code&gt;\K&lt;/code&gt;, &lt;code&gt;\G&lt;/code&gt;, &lt;code&gt;\C&lt;/code&gt; or &lt;code&gt;\X&lt;/code&gt;, and no modifier that runs to the end of a pattern
(&lt;code&gt;(?i)&lt;/code&gt; — the scoped &lt;code&gt;(?i:…)&lt;/code&gt; does work). Each is refused where the pattern is written, in a sentence
naming the construct.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lookbehind is the one place &lt;code&gt;RegExp&lt;/code&gt; is the LOOSER engine&lt;/strong&gt;, and it is refused here so that the two
agree: PCRE2 will not compile a lookbehind whose length is unlimited — &lt;code&gt;(?&amp;lt;=ab*)c&lt;/code&gt; is &lt;em&gt;“length of
lookbehind assertion is not limited”&lt;/em&gt; — and &lt;code&gt;RegExp&lt;/code&gt; takes anything. A &lt;strong&gt;bounded&lt;/strong&gt; one compiles on both,
&lt;code&gt;(?&amp;lt;=ab?)c&lt;/code&gt; and &lt;code&gt;(?&amp;lt;=a{2,3})c&lt;/code&gt; included. The other place &lt;code&gt;RegExp&lt;/code&gt; used to be looser closed itself: a
range with a class at one end, &lt;code&gt;[\d-x]&lt;/code&gt;, is refused by the &lt;code&gt;u&lt;/code&gt; flag exactly as PCRE2 refuses it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;u&lt;/code&gt; is always set, and that is what makes an offset a character.&lt;/strong&gt; Without it &lt;code&gt;RegExp&lt;/code&gt; counts a
subject in UTF-16 code units, so &lt;code&gt;^.$&lt;/code&gt; says an emoji is two and every offset after one is too big;
PCRE2 is in UTF mode and counts characters. The offsets a match reports are converted back in one walk
of the subject, which is what &lt;code&gt;regex.sysl&lt;/code&gt; does for the other back end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Three differences are left standing and are named here rather than closed.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A backreference to a group that took no part in the match&lt;/strong&gt; fails under PCRE2 and matches the empty
string under &lt;code&gt;RegExp&lt;/code&gt; — &lt;code&gt;(?:(?&amp;lt;n&amp;gt;a)|b)\k&amp;lt;n&amp;gt;&lt;/code&gt; is false against &lt;code&gt;&amp;quot;b&amp;quot;&lt;/code&gt; in the interpreter and true here.
It is a property of the run rather than of the pattern text, so nothing could be scanned for; refusing
every pattern with a backreference in it would refuse most real ones.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Under &lt;code&gt;i&lt;/code&gt;, a JavaScript host counts &lt;code&gt;U+017F&lt;/code&gt; and &lt;code&gt;U+212A&lt;/code&gt; as word characters&lt;/strong&gt;, its &lt;code&gt;u&lt;/code&gt; mode folding
them into &lt;code&gt;s&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; where PCRE2’s &lt;code&gt;\w&lt;/code&gt; stays ASCII. That is exactly two code points and only under
&lt;code&gt;i&lt;/code&gt;. Closing it would mean rewriting every character class through the &lt;code&gt;v&lt;/code&gt; flag’s set subtraction,
which is a much newer thing to require of a browser than the difference is worth.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There is no backtracking budget here.&lt;/strong&gt; PCRE2 gives up on a pattern that would backtrack forever and
raises a fault naming it; &lt;code&gt;RegExp&lt;/code&gt; has no such limit in any browser, so &lt;code&gt;(a+)+$&lt;/code&gt; against a subject that
does not match stops answering rather than complaining. That is a thing a JavaScript host does not
have.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;slatenet-is-nodes-own-tcp-and-the-request-parser-is-written-out&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt; is node’s own TCP, and the request parser is written out&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;This is the floor everything else stands on, and it was missing.&lt;/strong&gt; &lt;code&gt;slate:http&lt;/code&gt; is written in slate
over &lt;code&gt;listen&lt;/code&gt;, &lt;code&gt;onBytes&lt;/code&gt;, &lt;code&gt;send&lt;/code&gt; and &lt;code&gt;close&lt;/code&gt;, so a server could not be started under &lt;code&gt;slate js&lt;/code&gt; at
all — and a framework checking its router by rendering a page through a real request had two tests
skipping on every run for want of a listener.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A socket is a slot and a generation, exactly as it is in the interpreter&lt;/strong&gt;, so nothing of node’s
crosses into a slate value: &lt;code&gt;==&lt;/code&gt; compares what slate says it compares, &lt;code&gt;print&lt;/code&gt; answers &lt;code&gt;&amp;lt;socket 3&amp;gt;&lt;/code&gt;,
and a socket held across a &lt;code&gt;close&lt;/code&gt; never comes to mean whatever opens next.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A BROWSER HAS NO SOCKETS AND NEVER WILL&lt;/strong&gt;, so this is node’s half of the JavaScript world. Nothing
in a page may listen and nothing in one may open a TCP connection; the refusal there names the host
rather than promising anything, which is &lt;code&gt;slate:brotli&lt;/code&gt;‘s case and not &lt;code&gt;run&lt;/code&gt;‘s.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The reader is installed at the first &lt;code&gt;onData&lt;/code&gt; or &lt;code&gt;onBytes&lt;/code&gt; and never at accept.&lt;/strong&gt; A node socket is
paused until something listens for &lt;code&gt;data&lt;/code&gt;, and slate’s rule is that a connection handed to a program
is the program’s to read when it is ready — installing earlier would drain the first packets of every
connection into a callback nobody had registered, which is a request lost with nothing to say so.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;alpnProtocol&lt;/code&gt; is here and answers &lt;code&gt;null&lt;/code&gt; for a plain socket&lt;/strong&gt;, which is what the interpreter
answers and is what &lt;code&gt;slate:http&lt;/code&gt; reads at the first byte of every connection to tell HTTP/2 from
HTTP/1.1. A name that refused would make every &lt;code&gt;serve&lt;/code&gt; fault over a question whose answer is &lt;em&gt;no&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;slate:llhttp&lt;/code&gt; is a PARSER here rather than a binding&lt;/strong&gt;, and it is the one place the two back ends
do not share an implementation of something they both have. The interpreter’s is llhttp, a C state
machine generated from a grammar; node’s own is behind &lt;code&gt;internalBinding(&apos;http_parser&apos;)&lt;/code&gt; — the seam
node hid, and the reason undici carries llhttp compiled to wasm. So the HTTP/1.1 request grammar is
written out, and &lt;code&gt;tests/js/p26.sl&lt;/code&gt; is what says the two readings agree: the request line, the
headers, &lt;code&gt;Content-Length&lt;/code&gt; and &lt;code&gt;chunked&lt;/code&gt; framing, pipelining, a head split across two arrivals, an
upgrade and where the HTTP stopped, and the three refusals — &lt;code&gt;400&lt;/code&gt; for bytes that were not HTTP
(including two &lt;code&gt;Content-Length&lt;/code&gt; headers, and one beside a &lt;code&gt;Transfer-Encoding&lt;/code&gt;), &lt;code&gt;431&lt;/code&gt; for a head
over the limit and &lt;code&gt;413&lt;/code&gt; for a body over it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A message’s own error text is the host’s&lt;/strong&gt;, which is the one thing that cannot be made to match: a
refused connection carries node’s &lt;code&gt;ECONNREFUSED: …&lt;/code&gt; where the interpreter carries libuv’s. The
&lt;em&gt;code&lt;/em&gt; is the same word on both, that being the operating system’s.&lt;/p&gt;
&lt;h3 id=&quot;slatews-is-a-client-here-and-the-server-half-is-what-a-browser-cannot-have&quot;&gt;&lt;code&gt;slate:ws&lt;/code&gt; is a CLIENT here, and the server half is what a browser cannot have&lt;/h3&gt;
&lt;p&gt;A browser has no socket, so nothing that listens can exist there: &lt;code&gt;accept&lt;/code&gt; and the upgrade seam it
sits on refuse under &lt;code&gt;slate js&lt;/code&gt;, because &lt;code&gt;listen&lt;/code&gt; does. &lt;strong&gt;What a page can have is a client&lt;/strong&gt;, and it
has one already — the &lt;code&gt;WebSocket&lt;/code&gt; object — so that is what &lt;code&gt;open(url)&lt;/code&gt; becomes here.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is the same &lt;code&gt;Connection&lt;/code&gt; either way&lt;/strong&gt; and the module chooses which implementation answers.
Everything about the protocol that needs no socket is slate’s on both hosts: the framing, the
masking, the fragment reassembly, the accept value and the reading of a url. What differs is only who
owns the bytes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;ping&lt;/code&gt; refuses here, and it is the shape case rather than a missing feature.&lt;/strong&gt; The protocol has a
ping and the browser’s object does not expose one: a page cannot write a control frame at all, the
browser answering the server’s pings on the page’s behalf. So &lt;code&gt;ping&lt;/code&gt; says that, and a program needing
a round trip sends an ordinary message.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;Blob&lt;/code&gt; is never handed to a program.&lt;/strong&gt; A browser’s &lt;code&gt;message&lt;/code&gt; event carries binary as a &lt;code&gt;Blob&lt;/code&gt; by
default and a Blob is read &lt;em&gt;asynchronously&lt;/em&gt;, which would make &lt;code&gt;onBinary&lt;/code&gt; answer at some later turn
here and at once in the interpreter; the connection sets &lt;code&gt;binaryType&lt;/code&gt; to &lt;code&gt;arraybuffer&lt;/code&gt; on the way in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hostHas(name)&lt;/code&gt; is how the module asks, and it is not a name a program can write.&lt;/strong&gt; It is declared
into the scope a built-in module’s source compiles in — the same place &lt;code&gt;sha1&lt;/code&gt; and &lt;code&gt;jwsSign&lt;/code&gt; live — and
answers whether the host provides a thing ITSELF, which is a different question from whether slate has
one. The interpreter answers no to all of them: it speaks WebSocket over its own socket, compresses
with miniz and fetches over OpenSSL, and in each case there is nobody else’s implementation to use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;compression&lt;/code&gt; is two globals and one question.&lt;/strong&gt; A host with a &lt;code&gt;CompressionStream&lt;/code&gt; and no
&lt;code&gt;DecompressionStream&lt;/code&gt; does not compress, so &lt;code&gt;hostHas(&amp;quot;compression&amp;quot;)&lt;/code&gt; wants both.&lt;/p&gt;
&lt;h3 id=&quot;fetch-is-the-hosts-own-and-two-things-about-it-are-the-hosts-too&quot;&gt;&lt;code&gt;fetch&lt;/code&gt; is the host’s own, and two things about it are the host’s too&lt;/h3&gt;
&lt;p&gt;A browser &lt;em&gt;has&lt;/em&gt; &lt;code&gt;fetch&lt;/code&gt;, so this was work owed rather than something the host lacks. What had to be
written is the shaping: the host answers a &lt;code&gt;Response&lt;/code&gt; and slate answers &lt;code&gt;{ ok, value }&lt;/code&gt; with a
&lt;code&gt;status&lt;/code&gt;, a &lt;code&gt;headers&lt;/code&gt; object of lower-cased names, and a &lt;code&gt;body&lt;/code&gt;. A server that cannot be reached is
&lt;code&gt;{ ok: false, error }&lt;/code&gt;, never a rejection — which is &lt;code&gt;fetch&lt;/code&gt;‘s rule in slate whichever host answers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The URL is read here and not left to the host.&lt;/strong&gt; &lt;code&gt;gopher://x/&lt;/code&gt; is a mistake neither host has
anything to do with, so both back ends answer &lt;em&gt;“&lt;code&gt;gopher://x/&lt;/code&gt; is not an http or https URL”&lt;/em&gt; rather
than slate’s sentence in one place and the browser’s in the other. That is &lt;code&gt;slate:ws&lt;/code&gt;‘s rule for
&lt;code&gt;open&lt;/code&gt;, drawn the same way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;trust&lt;/code&gt; refuses&lt;/strong&gt;, and it is the shape case rather than a missing feature. It names a certificate to
trust as well as the machine’s own, and no JavaScript host lets a program add a trust anchor for one
request. A refusal is the only safe answer: a program that believes it pinned a certificate and did
not is worse off than one told it cannot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The redirect rule is the host’s here.&lt;/strong&gt; The interpreter follows at most five and refuses one that
leaves &lt;code&gt;https&lt;/code&gt; for &lt;code&gt;http&lt;/code&gt;. A browser follows redirects itself, and &lt;code&gt;redirect: &amp;quot;manual&amp;quot;&lt;/code&gt; does not hand
a page the location back — a cross-origin redirect comes back opaque, with no status and no headers
to read — so a page cannot implement that rule at all, and doing it on node alone would make the two
JavaScript hosts disagree with each other. This is &lt;code&gt;ping&lt;/code&gt;‘s case in &lt;code&gt;slate:ws&lt;/code&gt;: the host does the
thing and gives the program no way in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A body that is not UTF-8 is &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; on both&lt;/strong&gt;, which took a decision here: a host’s &lt;code&gt;text()&lt;/code&gt; replaces
every bad byte with U+FFFD, so the response would come back as replacement characters here and as
&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; there. The bytes are decoded strictly instead and the failure is caught.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A response header that repeats is joined with &lt;code&gt;&amp;quot;, &amp;quot;&lt;/code&gt; on both, and the interpreter changed to
match.&lt;/strong&gt; It used to keep the last, which silently threw one away — an object has one value per name
and HTTP does not. A &lt;code&gt;Headers&lt;/code&gt; object is what a JavaScript host hands over, already combined and with
no way to ask for the lines back, so combining is the only reading both can give; RFC 9110 allows it
in as many words.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Set-Cookie&lt;/code&gt; is excluded from that by the same section, and is a list of the lines on both.&lt;/strong&gt; A
cookie carries commas of its own, so a joined value cannot be taken apart again; &lt;code&gt;Headers&lt;/code&gt; has
&lt;code&gt;getSetCookie()&lt;/code&gt; for exactly this reason and that is what is read here. &lt;strong&gt;In a browser it is absent
however many arrived&lt;/strong&gt; — &lt;code&gt;Set-Cookie&lt;/code&gt; is a forbidden response-header name and a page never reads one,
though the browser still applies the cookie. That is &lt;code&gt;ping&lt;/code&gt;‘s case again: the host does the thing and
gives the program no way in.&lt;/p&gt;
&lt;p&gt;Which response headers are readable at all in a browser is CORS’s decision and not slate’s.&lt;/p&gt;
&lt;h3 id=&quot;slatedom-has-three-more-doors-and-they-are-the-rule-read-from-the-other-side&quot;&gt;&lt;code&gt;slate:dom&lt;/code&gt; has three more doors, and they are the rule read from the other side&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;location()&lt;/code&gt;, the history calls and &lt;code&gt;localStorage&lt;/code&gt; are things &lt;strong&gt;a browser has and nothing else does&lt;/strong&gt;.
So the interpreter and node both refuse them — naming &lt;em&gt;which&lt;/em&gt; of the three, because they are three
different mistakes — where everything else in this file is a name a browser has that slate had not
yet reached.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No history state object&lt;/strong&gt;, and that is a measurement rather than a simplification: &lt;code&gt;pushState&lt;/code&gt;
structured-clones what it is given, and &lt;code&gt;structuredClone&lt;/code&gt; strips the prototype, so a slate object put
in comes back a plain object carrying a &lt;code&gt;fields&lt;/code&gt; map that nothing in the language could read. The url
is the whole of the state.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A push does not raise &lt;code&gt;onNavigate&lt;/code&gt;&lt;/strong&gt; — a browser raises &lt;code&gt;popstate&lt;/code&gt; for a movement the user made and
never for one the program made itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A browser’s &lt;code&gt;print&lt;/code&gt; is the print dialog&lt;/strong&gt;, and the runtime used to reach for &lt;code&gt;globalThis.print&lt;/code&gt; as
its writer, so a page’s every &lt;code&gt;print(&amp;quot;hi&amp;quot;)&lt;/code&gt; asked which printer to use and wrote nothing. quickjs is
why that global is looked at at all — it is quickjs’s writer and has no relation to the window method
of the same name — and &lt;strong&gt;a document is what tells the two apart&lt;/strong&gt;. &lt;code&gt;check/&lt;/code&gt; in slate’s own repo drives
all of this against jsdom.&lt;/p&gt;
&lt;h3 id=&quot;and-four-that-read-the-page-for-a-program-adopting-markup-it-did-not-write&quot;&gt;And four that READ the page, for a program adopting markup it did not write&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;children(node)&lt;/code&gt;, &lt;code&gt;tagName(node)&lt;/code&gt;, &lt;code&gt;nodeText(node)&lt;/code&gt; and &lt;code&gt;attribute(node, name)&lt;/code&gt; are the read side, and
they refuse under the interpreter exactly as the write side does and for the same reason. They exist
because &lt;strong&gt;hydration cannot be written without them&lt;/strong&gt;: a framework adopting a server’s markup has to
walk what is there and ask what it found, and until 0.0.28 &lt;code&gt;slate:dom&lt;/code&gt; could build a page and could
not read one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A handle for an element the program never created is not new&lt;/strong&gt; — &lt;code&gt;byId&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; have minted one
since the module shipped — so what these add is the walk rather than a kind of value. &lt;code&gt;parent&lt;/code&gt;, the
siblings and an &lt;code&gt;innerHTML&lt;/code&gt; reader are deliberately absent: a page is walked downwards from something
the program already holds, and the rest is a general traversal API.&lt;/p&gt;
&lt;h3 id=&quot;case-whitespace-and-the-normal-forms-are-one-operation-and-that-took-proving&quot;&gt;Case, whitespace and the normal forms are one operation, and that took proving&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Nothing in this section is a difference&lt;/strong&gt;, which is worth saying in a chapter that is otherwise a
list of them. &lt;code&gt;upper&lt;/code&gt;, &lt;code&gt;lower&lt;/code&gt; and &lt;code&gt;normalize&lt;/code&gt; are the host’s own here — &lt;code&gt;toUpperCase&lt;/code&gt;,
&lt;code&gt;toLowerCase&lt;/code&gt; and &lt;code&gt;String.prototype.normalize&lt;/code&gt; — and the interpreter’s side was written to reach the
same answers rather than defensible ones: every code point there is was run through both back ends
and compared. So &lt;code&gt;upper(&amp;quot;ß&amp;quot;)&lt;/code&gt; is &lt;code&gt;SS&lt;/code&gt; on each, &lt;code&gt;İ&lt;/code&gt; lowercases to two characters on each, and a sigma
ending a word is &lt;code&gt;ς&lt;/code&gt; on each.&lt;/p&gt;
&lt;p&gt;That is not what a per-character walk over a case table gives. A hundred and two characters uppercase
to more than one, so the interpreter carries a table for those; &lt;code&gt;İ&lt;/code&gt; and the final sigma are the two
cases going the other way, and the second is context rather than a table.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;trim&lt;/code&gt; calls neither host’s own&lt;/strong&gt;, and it is the one of the four that could have. ECMAScript’s
whitespace is not the database’s &lt;code&gt;White_Space&lt;/code&gt;: it takes &lt;code&gt;U+FEFF&lt;/code&gt; off, which the database does not
call a space at all, and leaves &lt;code&gt;U+0085&lt;/code&gt; on, which it does. Both back ends spell the twenty-five
characters out instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;casefold&lt;/code&gt; is written out here&lt;/strong&gt;, no JavaScript host having case folding at all. It is
&lt;code&gt;NFC(fold(NFD(s)))&lt;/code&gt; — the standard’s own caseless match — and what stands between it and
&lt;code&gt;toLowerCase&lt;/code&gt; is a table of two hundred and nine code points: the ones that fold to more than one
character, the ones that fold &lt;em&gt;across&lt;/em&gt; an alphabet rather than down it (&lt;code&gt;µ&lt;/code&gt; to a Greek mu, &lt;code&gt;ſ&lt;/code&gt; to
&lt;code&gt;s&lt;/code&gt;, a combining iota to a letter), and Cherokee, the one script in the database whose fold is to
&lt;strong&gt;upper&lt;/strong&gt; case.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tests/js/p25.sl&lt;/code&gt; is the corpus that keeps all of this honest, and it is a corpus rather than a set
of expectations for the reason every file under &lt;code&gt;tests/js/&lt;/code&gt; is: it is run by both and diffed.&lt;/p&gt;
&lt;h3 id=&quot;onsignal-needs-a-process-so-node-has-it-and-a-browser-does-not&quot;&gt;&lt;code&gt;onSignal&lt;/code&gt; needs a process, so node has it and a browser does not&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;slate:process&lt;/code&gt;‘s signals are &lt;code&gt;process.on&lt;/code&gt; and &lt;code&gt;process.off&lt;/code&gt; here, with the interpreter’s own list of
names and its own refusal of &lt;code&gt;SIGKILL&lt;/code&gt; and &lt;code&gt;SIGSTOP&lt;/code&gt;. A host with no &lt;code&gt;process&lt;/code&gt; is not a thing that
can be signalled, and says so in those words rather than installing a handler nothing will ever call.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;stat&lt;/code&gt; answers &lt;code&gt;modified&lt;/code&gt; here as it does under the interpreter — an instant in microseconds, from
node’s &lt;code&gt;mtimeMs&lt;/code&gt;. It was missing for one release, which nothing noticed until a program walking a
directory tree asked a file for its modification time and reached a field that was not there.&lt;/p&gt;
&lt;h3 id=&quot;arity-is-checked-here-too-and-until-0028-it-was-not&quot;&gt;Arity is checked here too, and until 0.0.28 it was not&lt;/h3&gt;
&lt;p&gt;A JavaScript function ignores an argument it was not expecting and binds &lt;code&gt;undefined&lt;/code&gt; for one it was
not given. slate refuses both, and the interpreter always has — so an emitted &lt;code&gt;f(1, 2)&lt;/code&gt; for a
one-parameter &lt;code&gt;f&lt;/code&gt; quietly dropped the &lt;code&gt;2&lt;/code&gt; and ran, where the same program under the interpreter
faulted. &lt;strong&gt;That is a disagreement about what a program means, not about how a complaint is worded.&lt;/strong&gt;
A call with too &lt;em&gt;few&lt;/em&gt; failed further in, with a sentence about &lt;code&gt;undefined&lt;/code&gt; not being passable that
named neither the function nor the count.&lt;/p&gt;
&lt;p&gt;Every slate call goes through one place in the runtime, and the signature the emitter already
attaches for named arguments is what the check reads — a length comparison per call. A function
taking &lt;strong&gt;no&lt;/strong&gt; parameters carried no signature at all, which is why a component given props it does
not declare was the silent case; it carries one now.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A callback is trimmed rather than refused&lt;/strong&gt;, on both back ends — see
&lt;a href=&quot;/reference/functions/#callbacks-take-as-many-arguments-as-they-declare&quot;&gt;Functions&lt;/a&gt;. The document’s &lt;code&gt;on&lt;/code&gt;, the
WebSocket handlers and the timers all go through that path here, so &lt;code&gt;on(node, &amp;quot;click&amp;quot;, () -&amp;gt; …)&lt;/code&gt; is
what a page writes and what it has always written; what changed is that the two hosts now agree
about it for the same reason rather than by accident.&lt;/p&gt;
&lt;h3 id=&quot;a-diagnostic-about-a-function-names-it-and-the-emitter-says-what-to-call-it&quot;&gt;A diagnostic about a function names it, and the emitter says what to call it&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;`Counter` takes 0 arguments and was given 1&lt;/code&gt; rather than &lt;em&gt;“this function”&lt;/em&gt;. The caret is on the
&lt;strong&gt;call&lt;/strong&gt;, which is very often somewhere the reader has never opened — a framework invoking a
component, a sort given a comparison — so a sentence with nothing to grep for left them stranded.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lambda, a method and a generated &lt;code&gt;new&lt;/code&gt; have no name to give&lt;/strong&gt;, all three being compiled as
lambdas, and all three say &lt;em&gt;“this function”&lt;/em&gt;. That takes saying here because the two hosts would
otherwise offer two different wrong names: the interpreter’s chunk is called &lt;code&gt;a function&lt;/code&gt;, which is
what &lt;code&gt;print&lt;/code&gt; calls a function value, and a JavaScript function’s own &lt;code&gt;name&lt;/code&gt; is the emitter’s
temporary — &lt;code&gt;$t21&lt;/code&gt;, a name nobody wrote. So the emitter states the name to show alongside the
signature it already attaches, and says nothing for those three.&lt;/p&gt;
&lt;h2 id=&quot;a-builtin-is-a-parameter-not-a-name-taken-from-the-host&quot;&gt;A builtin is a parameter, not a name taken from the host&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The emitted program is a function whose parameters are the builtins&lt;/strong&gt;, applied to the runtime’s own
table. It is not a script that installs two hundred names into the host’s global scope, which is what
it used to be.&lt;/p&gt;
&lt;p&gt;That change is a browser-parity decision rather than a tidying. A page’s other scripts and the
browser’s own APIs share &lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;fetch&lt;/code&gt; and &lt;code&gt;close&lt;/code&gt;; a slate program that took those names took
them from everybody, for as long as the page lived. &lt;strong&gt;node’s own &lt;code&gt;WebSocket&lt;/code&gt; is what found it&lt;/strong&gt;: its
handshake calls &lt;code&gt;setTimeout&lt;/code&gt; and calls &lt;code&gt;.unref()&lt;/code&gt; on what comes back, and slate answers its own
integer id — which has no such method, so the socket never opened and nothing anywhere named a timer.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A program may still declare a name a builtin has.&lt;/strong&gt; The builtins are the outer function’s parameters
and the program is an inner function, so &lt;code&gt;val print = 1&lt;/code&gt; shadows exactly as it did when the names were
globals — two scopes are what keeps that from being a redeclaration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The names come from the same scope the interpreter’s builtins are installed into&lt;/strong&gt;, so a builtin
added to the language is a parameter on the next build and there is no second list to go stale.&lt;/p&gt;
&lt;h2 id=&quot;blocks-and-order&quot;&gt;Blocks and order&lt;/h2&gt;
&lt;p&gt;JavaScript has no block expression, so &lt;code&gt;val x = if c then 1 else 2&lt;/code&gt; becomes an &lt;code&gt;if&lt;/code&gt; statement over a
temporary. &lt;strong&gt;An immediately-called function would have been the other way and is wrong&lt;/strong&gt;: &lt;code&gt;return&lt;/code&gt;,
&lt;code&gt;break&lt;/code&gt;, &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;yield&lt;/code&gt; all mean the enclosing function, and a wrapper takes every one of them away.
The one place a wrapper is written is a default parameter, where there is no statement position to hoist
into and nothing of the enclosing function to lose.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:image</title>
    <link href="https://slatelang.dev/library/image/"/>
    <id>https://slatelang.dev/library/image/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Photographs and avatars — decoding what somebody uploaded, scaling it down, and writing it back out.</summary>
    <content type="html">&lt;h1 id=&quot;slateimage&quot;&gt;&lt;code&gt;slate:image&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Photographs and avatars — decoding what somebody uploaded, scaling it down, and writing it back out.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { readImage, imageShape, resizeImage, encodePNG, encodeJPEG, encodeWebP } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:image

&lt;span class=&quot;hl-comment&quot;&gt;// An image is a record. Four pixels, three channels, rows packed and the top row first.&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; square &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { width&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, height&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, channels&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;,
    pixels&lt;span class=&quot;hl-keyword&quot;&gt;:&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-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;255&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-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;] }

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; png &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;encodePNG&lt;/span&gt;(square)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(png[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], png[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], png[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], png[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])        &lt;span class=&quot;hl-comment&quot;&gt;// the PNG signature&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; back &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(png)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width, back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height, back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;channels)

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; bigger &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;resizeImage&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value, &lt;span class=&quot;hl-number&quot;&gt;4&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;(bigger&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width, bigger&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height, &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(bigger&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;pixels))

&lt;span class=&quot;hl-comment&quot;&gt;// The shape without decoding anything, which is what to ask of an upload.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;imageShape&lt;/span&gt;(png)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width, &lt;span class=&quot;hl-function&quot;&gt;imageShape&lt;/span&gt;(png)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height)

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;toBytes&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 an image&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;137 80 78 71
true 2 2 3
4 4 48
2 2
false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;an-image-is-a-record-not-a-handle&quot;&gt;An image is a record, not a handle&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;{ width, height, channels, pixels }&lt;/code&gt;, where &lt;code&gt;pixels&lt;/code&gt; is a byte array of &lt;code&gt;width * height * channels&lt;/code&gt;
— rows packed with no padding, the top row first, and the channels interleaved. Every name here
either answers one or takes one, so a thumbnail is one expression:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; small &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;encodeJPEG&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;resizeImage&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(upload)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value, &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;), &lt;span class=&quot;hl-number&quot;&gt;80&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing in the middle is a resource to give back, and the pixels are ordinary slate values: a program
can read them, store them, send them, or build an image itself and encode that — which is what the
runnable program above does.&lt;/p&gt;
&lt;h2 id=&quot;what-it-reads-and-what-it-writes&quot;&gt;What it reads and what it writes&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;read&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;PNG, JPEG, GIF (first frame), WebP, BMP, TGA, PSD, PIC, PNM, Radiance&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;write&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;PNG, JPEG, WebP&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The format is recognised from the bytes&lt;/strong&gt;, so there is nothing to tell &lt;code&gt;readImage&lt;/code&gt; what to expect
and a file with the wrong extension is read correctly anyway. A GIF decodes to its &lt;strong&gt;first frame&lt;/strong&gt;;
there is no animation.&lt;/p&gt;
&lt;h2 id=&quot;webp-which-is-what-a-browser-writes&quot;&gt;WebP, which is what a browser writes&lt;/h2&gt;
&lt;p&gt;Everything above but WebP is Sean Barrett’s &lt;code&gt;stb_image&lt;/code&gt;, which has never read one — WebP is VP8 in a
RIFF container, a video codec’s worth of code. WebP is libwebp, and it is here because it is what a
modern browser produces: a page that re-encodes a photograph before uploading it usually writes one,
so without it the commonest upload a form meets would be the one &lt;code&gt;readImage&lt;/code&gt; refuses.&lt;/p&gt;
&lt;p&gt;Nothing about the call changes. The header says which decoder answers, and &lt;code&gt;channels&lt;/code&gt; comes back as
3 or 4 — a WebP carries RGB or RGBA and there is no greyscale form of the file, though
&lt;code&gt;readImage(bytes, 1)&lt;/code&gt; converts one for you exactly as it does a PNG.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { readImage, imageShape, encodeWebP } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:image

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; src &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { width&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, height&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, channels&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;,
    pixels&lt;span class=&quot;hl-keyword&quot;&gt;:&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-number&quot;&gt;0&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-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;0&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-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;255&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;128&lt;/span&gt;] }

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; file &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;encodeWebP&lt;/span&gt;(src, { lossless&lt;span class=&quot;hl-keyword&quot;&gt;:&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;(file[&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])       &lt;span class=&quot;hl-comment&quot;&gt;// &amp;quot;RIFF&amp;quot;&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(file[&lt;span class=&quot;hl-number&quot;&gt;8&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;], file[&lt;span class=&quot;hl-number&quot;&gt;11&lt;/span&gt;])     &lt;span class=&quot;hl-comment&quot;&gt;// &amp;quot;WEBP&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;shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;imageShape&lt;/span&gt;(file)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value

&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-keyword&quot;&gt;.&lt;/span&gt;width, &lt;span class=&quot;hl-type&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height, &lt;span class=&quot;hl-type&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;channels)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(file)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;pixels &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; src&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;pixels)

&lt;span class=&quot;hl-comment&quot;&gt;// A quality instead of a record is the lossy coder, which keeps the alpha either way.&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;encodeWebP&lt;/span&gt;(src, &lt;span class=&quot;hl-number&quot;&gt;40&lt;/span&gt;)) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;encodeWebP&lt;/span&gt;(src, &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;82 73 70 70
87 69 66 80
2 2 4
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An animated WebP is refused&lt;/strong&gt;, and says which library reading one would take. Its frames live in
&lt;code&gt;ANMF&lt;/code&gt; chunks that only &lt;code&gt;libwebpdemux&lt;/code&gt; walks, and that is a second library nothing here binds:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; anim &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(bytes)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;!&lt;/span&gt;anim&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(anim&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)
&lt;span class=&quot;hl-comment&quot;&gt;// &amp;quot;this is an animated WebP; reading one needs libwebpdemux, which this package does not bind&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A truncated WebP says it is truncated&lt;/strong&gt; rather than that it is damaged, which is the difference
between an upload worth asking for again and one that is not:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(partial)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)   &lt;span class=&quot;hl-comment&quot;&gt;// &amp;quot;the WebP data stops before the image does&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;channels-and-asking-for-a-different-number&quot;&gt;&lt;code&gt;channels&lt;/code&gt;, and asking for a different number&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;readImage(bytes)&lt;/code&gt; converts nothing: &lt;code&gt;channels&lt;/code&gt; comes back as 1, 2, 3 or 4 depending on what the file
held. &lt;code&gt;readImage(bytes, 4)&lt;/code&gt; converts on the way out, which is the call an avatar pipeline makes —
uploads arrive greyscale, RGB and RGBA in whatever mixture the people using a site happened to have,
and code that composites or scales them wants one shape.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; avatar &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(upload, &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value    &lt;span class=&quot;hl-comment&quot;&gt;// always RGBA, whatever arrived&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;readImage&lt;/code&gt; and &lt;code&gt;imageShape&lt;/code&gt; answer a result; &lt;code&gt;resizeImage&lt;/code&gt; and the three encoders fault.&lt;/strong&gt;
That is the rule the whole library follows: bytes from somewhere else are an answer the caller has to
look at — a corrupt JPEG is a &lt;code&gt;400&lt;/code&gt; to send, not a defect in the program reading it — and a value the
program built itself is a fault. So a mismatched &lt;code&gt;pixels&lt;/code&gt;, a width of zero, or a quality of 200 stops
the program where it is written.&lt;/p&gt;
&lt;h2 id=&quot;imageshape-is-the-size-guard-and-that-is-why-it-exists&quot;&gt;&lt;code&gt;imageShape&lt;/code&gt; is the size guard, and that is why it exists&lt;/h2&gt;
&lt;p&gt;A decoded image is &lt;code&gt;width * height * channels&lt;/code&gt; bytes &lt;strong&gt;however small the file was&lt;/strong&gt;. A PNG of four
kilobytes can say it is 20,000 by 20,000, which is 1.2 GB the moment anything decodes it — the same
shape of attack a compression bomb is, wearing a picture’s clothes. &lt;code&gt;imageShape&lt;/code&gt; reads the width,
height and channel count out of the header without decoding anything, so a handler can answer &lt;code&gt;413&lt;/code&gt;
instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;shape&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;imageShape&lt;/span&gt;(body)

&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &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-keyword&quot;&gt;.&lt;/span&gt;ok &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;return&lt;/span&gt; { status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;400&lt;/span&gt;, text&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-keyword&quot;&gt;.&lt;/span&gt;error }
&lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width &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-keyword&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;40_000_000&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; { status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;413&lt;/span&gt; }

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; img &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readImage&lt;/span&gt;(body)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;scaling&quot;&gt;Scaling&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;resizeImage(image, width, height)&lt;/code&gt; answers the same image at another size, eight bits a channel, and
keeps the channel count it was given. &lt;strong&gt;The filtering happens in sRGB space&lt;/strong&gt;, which is the right
answer for every 8-bit image a page holds: averaging two sRGB bytes as though they were quantities of
light is what makes a naively downscaled photograph come out too dark.&lt;/p&gt;
&lt;p&gt;Nothing here preserves the aspect ratio for you — the two numbers are what the answer will be — so
work them out from the shape you read:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; wide &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;max&lt;/span&gt;(img&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width, img&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; thumb &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;resizeImage&lt;/span&gt;(img, &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;(img&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; wide), &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;(img&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; wide))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-quality-is-written-at-every-call&quot;&gt;The quality is written at every call&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;encodeJPEG(image, quality)&lt;/code&gt; takes a number from 1 to 100 and there is no default, for
&lt;a href=&quot;/library/zstd/&quot;&gt;&lt;code&gt;slate:zstd&lt;/code&gt;&lt;/a&gt;‘s reason and &lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt;‘s: it is the one number a caller has
to think about, and no single value is right often enough to be the quiet one. 80 is a photograph on
a page, 60 a thumbnail, 95 something that will be edited again.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;encodePNG&lt;/code&gt; takes no such number — PNG is lossless, and it is what to reach for unless the image
really is a photograph. The encoder is stb’s baseline JPEG writer: no progressive mode and no
subsampling control, which is small, fast, and read by everything.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;encodeWebP&lt;/code&gt; takes &lt;strong&gt;either&lt;/strong&gt;, and that is the one signature here with two forms:&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;encodeWebP(image, quality)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;lossy, 1 to 100, roughly a quarter smaller than a JPEG at the same quality — &lt;strong&gt;and it keeps an alpha channel&lt;/strong&gt;, which JPEG cannot&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;encodeWebP(image, { lossless: true })&lt;/code&gt;&lt;/td&gt;&lt;td&gt;nothing thrown away, and about a fifth smaller than the PNG of the same image&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two forms rather than two names, because the second argument is what a caller has to think about
either way and lossless is a value it can take. &lt;code&gt;{ lossless: false }&lt;/code&gt; is refused rather than read as
“lossy”, since a lossy encode needs a number nobody wrote.&lt;/p&gt;
&lt;p&gt;A one- or two-channel image is widened to RGB or RGBA on the way out — there is no greyscale WebP —
which is what a browser decoding the file would have shown anyway.&lt;/p&gt;
&lt;h2 id=&quot;not-in-the-javascript-back-end-on-either-host&quot;&gt;Not in the JavaScript back end, on either host&lt;/h2&gt;
&lt;p&gt;All six names refuse under &lt;code&gt;slate js&lt;/code&gt;, and the two hosts refuse for different reasons. &lt;strong&gt;node has no
image support in its standard library at all&lt;/strong&gt; — there is no &lt;code&gt;zlib&lt;/code&gt;-shaped module for pictures, and
every reader anybody uses is an npm dependency. &lt;strong&gt;A browser does decode&lt;/strong&gt;, through
&lt;code&gt;createImageBitmap&lt;/code&gt; and &lt;code&gt;OffscreenCanvas&lt;/code&gt; — WebP as readily as PNG — but the whole of that surface
answers &lt;strong&gt;promises&lt;/strong&gt;, where these six answer on the spot, so a browser half would make the two back
ends disagree about what an image even is. That is the same rule &lt;code&gt;crypto.subtle&lt;/code&gt; is held to: a host
that has a thing only in a different shape does not have it.&lt;/p&gt;
&lt;p&gt;So this is a server’s module. Resize and re-encode where the interpreter runs, and send the browser
the answer.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:http</title>
    <link href="https://slatelang.dev/library/http/"/>
    <id>https://slatelang.dev/library/http/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>An HTTP server, written in slate over slate:net.</summary>
    <content type="html">&lt;h1 id=&quot;slatehttp&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;An HTTP server, written in slate over &lt;a href=&quot;/library/net/&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { serve, close } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:http

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; server &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;8080&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&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-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;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;serve(port, handler, onUpgrade = null)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the whole request, body included&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;serveStream(port, handler, onUpgrade = null)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the head, then the body in pieces&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;close(server)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;stop serving, and end the connections&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;router()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;files(root, options = {})&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a handler serving a directory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;setCookie(name, value, options = {})&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a header value&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;parseQuery(s)&lt;/code&gt;, &lt;code&gt;parseForm(body)&lt;/code&gt;, &lt;code&gt;parseCookies(header)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;encodeComponent(s)&lt;/code&gt;, &lt;code&gt;percentDecode(s, plusIsSpace)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;/library/url/&quot;&gt;&lt;code&gt;slate:url&lt;/code&gt;&lt;/a&gt;‘s, forwarded&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;Request&lt;/code&gt;, &lt;code&gt;Response&lt;/code&gt; and &lt;code&gt;Router&lt;/code&gt; are exported as &lt;a href=&quot;/reference/types/&quot;&gt;types&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;parseQuery&lt;/code&gt;, &lt;code&gt;encodeComponent&lt;/code&gt; and &lt;code&gt;percentDecode&lt;/code&gt; are &lt;a href=&quot;/library/url/&quot;&gt;&lt;code&gt;slate:url&lt;/code&gt;&lt;/a&gt;‘s&lt;/strong&gt; and are exported
here as well, so nothing written against this module changed. &lt;strong&gt;Import them from &lt;code&gt;slate:url&lt;/code&gt; in
anything that is not a server&lt;/strong&gt; — a browser page importing this module to reach them grows by 239 KB,
which is a file server and an HTTP/2 speaker downloaded to read a query string.&lt;/p&gt;
&lt;p&gt;The third argument to either server is for a protocol upgrade — see &lt;a href=&quot;/library/ws/&quot;&gt;&lt;code&gt;slate:ws&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTPS is &lt;code&gt;listen&lt;/code&gt; told a certificate&lt;/strong&gt;, so &lt;code&gt;serve&lt;/code&gt; did not have to change: TLS lives one layer down.&lt;/p&gt;
&lt;h2 id=&quot;closeserver&quot;&gt;&lt;code&gt;close(server)&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Closing a server stops it accepting, closes every idle connection it had accepted at once, and lets a
connection with a request in flight finish that response before closing it.&lt;/strong&gt; There is no keep-alive
after &lt;code&gt;close&lt;/code&gt;: a second request on a connection that was busy is not served, and the connection ends
with the response it was writing.&lt;/p&gt;
&lt;p&gt;That is what makes &lt;code&gt;close&lt;/code&gt; the thing that lets a program exit. A connection is a handle the event loop
waits on, so closing only the listening socket would leave a program that had shut everything down
still waiting — on connections whose clients may already be gone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A connection nobody is using is closed by the server anyway, after five seconds&lt;/strong&gt;, over either
version. A client may keep a connection and then simply go away, and without that clock the socket
would be held for the life of the server.&lt;/p&gt;
&lt;h2 id=&quot;the-request&quot;&gt;The request&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt; (the raw text after the &lt;code&gt;?&lt;/code&gt;), &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;cookies&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;,
&lt;code&gt;body&lt;/code&gt; and &lt;code&gt;bytes&lt;/code&gt; where the server read one, &lt;code&gt;keepAlive&lt;/code&gt;, &lt;code&gt;upgrade&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;body&lt;/code&gt; is the text and &lt;code&gt;bytes&lt;/code&gt; is what arrived&lt;/strong&gt;, and both are there on every request &lt;code&gt;serve&lt;/code&gt;
answers. A body that is not UTF-8 — a PNG, a zip, a binary part of a &lt;code&gt;multipart/form-data&lt;/code&gt; upload —
decodes to nothing, so &lt;code&gt;body&lt;/code&gt; is &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; and &lt;code&gt;bytes&lt;/code&gt; is exact. Until 0.0.30 there was only &lt;code&gt;body&lt;/code&gt;, and
such an upload was the same value as a request that carried no body at all: no header, no status,
no fault. &lt;strong&gt;A large upload still wants &lt;code&gt;serveStream&lt;/code&gt;&lt;/strong&gt;, which hands the bytes over as they arrive
rather than holding the whole of them twice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;address&lt;/code&gt; is the IP that connected&lt;/strong&gt;, or &lt;code&gt;null&lt;/code&gt; where the socket cannot say. It is
&lt;a href=&quot;/library/net/&quot;&gt;&lt;code&gt;slate:net&lt;/code&gt;‘s &lt;code&gt;remoteAddress&lt;/code&gt;&lt;/a&gt; asked of this request’s connection, so an IPv4 client of a
dual-stack server reads as &lt;code&gt;127.0.0.1&lt;/code&gt; rather than as &lt;code&gt;::ffff:127.0.0.1&lt;/code&gt;. &lt;strong&gt;What a proxy wrote is
still a header&lt;/strong&gt;: &lt;code&gt;x-forwarded-for&lt;/code&gt; is what a server behind one must read, and this is who actually
opened the socket.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;search&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; are the URL API’s two names.&lt;/strong&gt; A program wanting the raw text still has it —
which matters because &lt;strong&gt;a repeated name in &lt;code&gt;query&lt;/code&gt; is the last one&lt;/strong&gt;. That is a decision: an array where
a name repeats makes the &lt;em&gt;type&lt;/em&gt; of &lt;code&gt;q.name&lt;/code&gt; depend on what a client sent, so a program that read it as a
string works until somebody sends the field twice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;params&lt;/code&gt; and &lt;code&gt;cookies&lt;/code&gt; are &lt;code&gt;{}&lt;/code&gt; rather than absent&lt;/strong&gt;, because a field that is there only sometimes is
one every handler must test for.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Percent-decoding works over bytes&lt;/strong&gt;, &lt;code&gt;%C3%A9&lt;/code&gt; being two bytes that are one character, and answers its
input unchanged where the bytes are not text — a query string is something a peer wrote, and a fault
there would let any peer stop a program.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-answer&quot;&gt;The answer&lt;/h2&gt;
&lt;p&gt;A handler answers a string, an object, or an &lt;strong&gt;array of bytes&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&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-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;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; { status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;201&lt;/span&gt;, headers&lt;span class=&quot;hl-keyword&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;X-Kind&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;note&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; }, body&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toJSON&lt;/span&gt;(v) })
&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; { headers&lt;span class=&quot;hl-keyword&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;Content-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;:&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;image/png&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; }, body&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pngBytes })&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;An array body is sent as it stands&lt;/strong&gt;, which is what serves an image, a font or a pre-compressed asset.
&lt;code&gt;toJSON(xs)&lt;/code&gt; is what an array of data has to be.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A header whose value is an array is written once per element&lt;/strong&gt;, which is the only way to say
&lt;code&gt;Set-Cookie&lt;/code&gt; twice: an object has one value per name and HTTP does not. &lt;code&gt;Link&lt;/code&gt;, &lt;code&gt;Vary&lt;/code&gt; and &lt;code&gt;Via&lt;/code&gt; all
repeat.&lt;/p&gt;
&lt;h2 id=&quot;servestream&quot;&gt;&lt;code&gt;serveStream&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The handler is called as soon as a request’s &lt;strong&gt;head&lt;/strong&gt; is complete and is given the body as it arrives, so
the memory a request costs stops depending on how big the request is:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;serveStream&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; (req) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; total &lt;span class=&quot;hl-keyword&quot;&gt;=&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; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; chunk &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; req
        total &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; total &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(chunk)

    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;that was &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(total) &lt;span class=&quot;hl-keyword&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; bytes&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;&lt;code&gt;for await&lt;/code&gt; is the shape to reach for&lt;/strong&gt;, and &lt;code&gt;req.each(fn)&lt;/code&gt; is the same bytes pushed instead of
pulled — it answers a promise for the byte count, which is the one number an upload handler usually
wants:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;serveStream&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; (req) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;counted&lt;/span&gt;(c) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; c

    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; req&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;each&lt;/span&gt;(counted)

    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;that was &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&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; bytes&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;Two exports rather than one with an option&lt;/strong&gt;, because the two differ by &lt;em&gt;what the handler is given&lt;/em&gt;
rather than by what the server was told — a streamed request having no &lt;code&gt;body&lt;/code&gt; and answering &lt;code&gt;each&lt;/code&gt;
instead. Everything else about the connection is the same server: the same keep-alive rule, the same
order, the same clock.&lt;/p&gt;
&lt;h2 id=&quot;a-response-that-arrives-in-pieces&quot;&gt;A response that arrives in pieces&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A handler may answer a source&lt;/strong&gt; — a generator, or anything with a &lt;code&gt;next()&lt;/code&gt;, which is what
&lt;a href=&quot;/reference/asynchrony/&quot;&gt;&lt;code&gt;for await&lt;/code&gt;&lt;/a&gt; drives — and the server writes it as chunked transfer as
the pieces arrive:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counting&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&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;yield&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-keyword&quot;&gt;yield&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;

app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&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;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counting&lt;/span&gt;())
app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&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;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; { status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;202&lt;/span&gt;, headers&lt;span class=&quot;hl-keyword&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;X-Kind&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-keyword&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;report&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; }, body&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;rows&lt;/span&gt;() })&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No &lt;code&gt;Content-Length&lt;/code&gt; and no compression.&lt;/strong&gt; Both are facts about the last piece, and a server that
buffered the body to find them out would be undoing what streaming is for.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A piece may be text or bytes&lt;/strong&gt;, exactly as a whole body may.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A source that faults mid-stream ends the response and the fault is put back.&lt;/strong&gt; The client sees a
chunked body with no terminator, which is the only thing HTTP can say once the status line has
gone, and the defect stops the program as any other does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Both versions carry one.&lt;/strong&gt; Over HTTP/1.1 the pieces are chunks and over HTTP/2 they are DATA
frames, and nothing a handler wrote says which.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;a-source-is-told-when-its-reader-has-gone&quot;&gt;A source is told when its reader has gone&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A source may have a &lt;code&gt;close&lt;/code&gt;, and the server calls it where the response ends with the source
unexhausted&lt;/strong&gt; — the client hung up, the socket was closed under the response, the peer reset the
stream, or the source itself faulted. A source that ran to &lt;code&gt;done&lt;/code&gt; is told nothing, having finished.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;subscribe&lt;/span&gt;(topic)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; q &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;queue&lt;/span&gt;()

    &lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;pull&lt;/span&gt;()
        { done&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; q&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;take&lt;/span&gt;() }

    &lt;span class=&quot;hl-function&quot;&gt;shut&lt;/span&gt;()
        &lt;span class=&quot;hl-function&quot;&gt;forget&lt;/span&gt;(topic, q)

    { next&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pull, close&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; shut }

app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/events&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sse&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;subscribe&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;orders&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;It is optional and is asked for exactly as &lt;code&gt;next&lt;/code&gt; is&lt;/strong&gt;, so every source already written keeps
working: a generator has no &lt;code&gt;close&lt;/code&gt; and is left alone, and so is an object that does not name one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Without it, a subscription outlives its reader for the life of the program.&lt;/strong&gt; That is the shape a
source usually has — a topic, a query, a tail of a file — and a writer that simply stopped pulling
left the thing behind it holding a reader that would never read again. &lt;code&gt;sse&lt;/code&gt; forwards the message to
the source it was given, so an event stream gets it through the wrapper.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It is called once.&lt;/strong&gt; There are several ways a streamed response can end early, and a source that
counted its own readers would go wrong if any of them said so twice.&lt;/p&gt;
&lt;h2 id=&quot;ssesource&quot;&gt;&lt;code&gt;sse(source)&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Server-sent events, which is a streamed response with one format on top of it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sse } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:http

app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/events&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sse&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ticks&lt;/span&gt;()))
app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&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;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sse&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;ticks&lt;/span&gt;(), { heartbeat&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; }))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A piece may be a &lt;strong&gt;string&lt;/strong&gt;, which is its data, or an &lt;strong&gt;object&lt;/strong&gt; naming any of &lt;code&gt;event&lt;/code&gt;, &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;retry&lt;/code&gt;
and &lt;code&gt;data&lt;/code&gt; — and a &lt;code&gt;data&lt;/code&gt; that is not a string is JSON, which is what a browser’s
&lt;code&gt;JSON.parse(e.data)&lt;/code&gt; wants anyway. &lt;strong&gt;Every line of the data is prefixed&lt;/strong&gt;, a bare newline inside one
being what would otherwise end the event.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;heartbeat&lt;/code&gt; is a member of the response, not something the server guesses.&lt;/strong&gt; &lt;code&gt;sse&lt;/code&gt; sets it to 15
seconds; the writer sends &lt;code&gt;: keep-alive&lt;/code&gt; on that interval while nothing else is going down the
stream, which is what keeps a proxy from closing an idle connection. &lt;code&gt;0&lt;/code&gt; turns it off, and any
streamed response may ask for one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;{ status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;200&lt;/span&gt;, headers&lt;span class=&quot;hl-keyword&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;Content-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;:&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/plain&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; }, heartbeat&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;30&lt;/span&gt;, body&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;rows&lt;/span&gt;() }&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;http2&quot;&gt;HTTP/2&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A server that was given a certificate and an &lt;code&gt;alpn&lt;/code&gt; list speaks either version, and the handler is
written once.&lt;/strong&gt; What decides is ALPN and nothing else: &lt;code&gt;h2&lt;/code&gt; and &lt;code&gt;http/1.1&lt;/code&gt; arrive on one port over one
socket, and HTTP/2’s own preface is bytes a malformed HTTP/1.1 request could also begin with.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;({ port&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;8443&lt;/span&gt;, cert&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; pem, key&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; keyPem, alpn&lt;span class=&quot;hl-keyword&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;h2&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;http/1.1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;] }, app)&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The &lt;code&gt;Request&lt;/code&gt; is the same value.&lt;/strong&gt; &lt;code&gt;method&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;search&lt;/code&gt;, &lt;code&gt;query&lt;/code&gt;, &lt;code&gt;cookies&lt;/code&gt;, &lt;code&gt;params&lt;/code&gt; and
&lt;code&gt;headers&lt;/code&gt; are all filled in the same way, and a reply may be a string, an object or an array of
bytes exactly as before — the same compression rule and the same header rules apply.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;:authority&lt;/code&gt; arrives as &lt;code&gt;host&lt;/code&gt;&lt;/strong&gt;, so a handler reading &lt;code&gt;req.headers.host&lt;/code&gt; need not know which
version it was spoken to over.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repeated &lt;code&gt;cookie&lt;/code&gt; fields are joined with &lt;code&gt;&amp;quot;; &amp;quot;&lt;/code&gt;&lt;/strong&gt;, which RFC 9113 §8.2.3 asks for: HTTP/2 lets a
client split its cookies one per field so that each compresses on its own, and browsers do. Every
other repeated header name keeps the last, which is what the HTTP/1.1 path does with one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A body is bounded by the same megabyte the HTTP/1.1 server applies&lt;/strong&gt;, and one past it is answered
&lt;code&gt;413&lt;/code&gt; — the limit a program thinks it has is the same limit on both versions of one listener.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;keepAlive&lt;/code&gt; is always &lt;code&gt;true&lt;/code&gt;&lt;/strong&gt; and there is no pipelining question: a connection carries many
streams at once and each is answered on its own.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A header name goes out lowercased&lt;/strong&gt;, an upper-case field name being malformed in HTTP/2 rather
than merely unconventional. On HTTP/1.1 what you wrote is what is sent.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A streamed response goes out as a DATA frame per piece&lt;/strong&gt;, and &lt;code&gt;sse&lt;/code&gt; works with its heartbeat —
the head is sent before the source is asked for anything, which is what lets a response whose
source never ends say &lt;code&gt;200&lt;/code&gt; at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;serveStream&lt;/code&gt; hands the body over as it lands&lt;/strong&gt;, one arrival per DATA frame, and a stream the
peer resets ends the body the handler is reading rather than leaving it waiting.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Without a certificate there is no ALPN and nothing changes&lt;/strong&gt; — &lt;code&gt;h2c&lt;/code&gt;, which is HTTP/2 in the clear,
is not spoken here. The framing layer on its own is &lt;a href=&quot;/library/nghttp2/&quot;&gt;&lt;code&gt;slate:nghttp2&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;router&quot;&gt;&lt;code&gt;router()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A router is an ordinary object holding functions, and &lt;code&gt;serve&lt;/code&gt; asks an object for its &lt;code&gt;handle&lt;/code&gt;&lt;/strong&gt; — so
&lt;code&gt;serve(3000, app)&lt;/code&gt; works and nothing in the server knows what routing is.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; app &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;router&lt;/span&gt;()

app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;get&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/notes/:id&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;find&lt;/span&gt;(req&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;params&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;id))
app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;post&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/notes&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;create&lt;/span&gt;(req&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;body))
app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-type&quot;&gt;any&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/health&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, req &lt;span class=&quot;hl-keyword&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-string&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
app&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;notFound&lt;/span&gt;(req &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; { status&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;404&lt;/span&gt;, body&lt;span class=&quot;hl-keyword&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;nothing here&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; })

&lt;span class=&quot;hl-function&quot;&gt;serve&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3000&lt;/span&gt;, app)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;get&lt;/code&gt;, &lt;code&gt;post&lt;/code&gt;, &lt;code&gt;put&lt;/code&gt;, &lt;code&gt;patch&lt;/code&gt;, &lt;code&gt;delete&lt;/code&gt;, &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;options&lt;/code&gt;, &lt;code&gt;any&lt;/code&gt;, and &lt;code&gt;notFound&lt;/code&gt;. Patterns take &lt;code&gt;:name&lt;/code&gt;
and &lt;code&gt;*rest&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Routes are tried in the order they were added&lt;/strong&gt;, the only rule a reader can predict.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A path that is there under another method is &lt;code&gt;405&lt;/code&gt; with an &lt;code&gt;Allow&lt;/code&gt;&lt;/strong&gt;, not &lt;code&gt;404&lt;/code&gt; — the difference
between a client being told what to send and being told the thing is not there.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No middleware, and that is a decision.&lt;/strong&gt; A chain each link may short-circuit is a control flow of its
own to learn; &lt;code&gt;app.get(&amp;quot;/x&amp;quot;, authed(handler))&lt;/code&gt; says what it does at the site that needs it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;filesroot&quot;&gt;&lt;code&gt;files(root)&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Serves a directory.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ETag&lt;/code&gt; and &lt;code&gt;If-None-Match&lt;/code&gt;, deliberately not &lt;code&gt;Last-Modified&lt;/code&gt;.&lt;/strong&gt; A validator a client never received is
one it can never send, so the two are not both needed — and the older pair costs an HTTP date, a
rendering in English of a moment in one zone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The tag is the size and the modification time, not a hash of the contents.&lt;/strong&gt; Hashing a file per request
is what a static server exists not to do.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A missing file and a directory with no index answer the same &lt;code&gt;404&lt;/code&gt;&lt;/strong&gt;, telling a client which is
which mapping out the disk for it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;what-it-refuses-and-why-refusing-rather-than-repairing&quot;&gt;What it refuses, and why refusing rather than repairing&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A path that climbs out is refused and not sanitised.&lt;/strong&gt; Such a request is not a request with a mistake
in it, and quietly rewriting the name would hide what was attempted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Every part of the path is percent-decoded before it is judged&lt;/strong&gt;, which is the whole of the rule: &lt;code&gt;..&lt;/code&gt;
is a climb however it was spelled, and &lt;code&gt;/%2e%2e/x&lt;/code&gt; and &lt;code&gt;/..%2fx&lt;/code&gt; are the same request as &lt;code&gt;/../x&lt;/code&gt;.
A request is answered &lt;code&gt;403&lt;/code&gt; when any part of it, &lt;em&gt;after decoding&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;is &lt;code&gt;..&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;carries a &lt;code&gt;/&lt;/code&gt;, a &lt;code&gt;\&lt;/code&gt; or a NUL byte. An encoded separator is one part naming two, and a NUL ends a
name at the system call rather than here — so &lt;code&gt;/logo.png%00.txt&lt;/code&gt; is a request for one file wearing
another’s extension;&lt;/li&gt;
&lt;li&gt;came from a &lt;code&gt;%&lt;/code&gt; that is not followed by two hexadecimal digits. A browser reads a stray &lt;code&gt;%&lt;/code&gt; as a
literal &lt;code&gt;%&lt;/code&gt; and so does &lt;a href=&quot;/library/url/&quot;&gt;&lt;code&gt;percentDecode&lt;/code&gt;&lt;/a&gt;, which is right for something a person typed into a
query string; a path is the one place where taking that guess makes the guess a file name.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An empty part and a &lt;code&gt;.&lt;/code&gt; part are dropped, so &lt;code&gt;//a&lt;/code&gt;, &lt;code&gt;/./a&lt;/code&gt; and &lt;code&gt;a&lt;/code&gt; are one path. The path that comes
out is then normalised and checked to be under the root a second time, so a mistake in the part rules
is a &lt;code&gt;403&lt;/code&gt; rather than a file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A symlink is followed like any other file, and that is the operator’s choice.&lt;/strong&gt; The check is on the
name the request asked for and not on what the file system would make of it, so a link &lt;em&gt;inside&lt;/em&gt; the
root pointing outside it serves what it points at — nginx answers the same way. A root that must not
be escaped that way is one with no such links in it.&lt;/p&gt;
&lt;h2 id=&quot;compression&quot;&gt;Compression&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A response is compressed without asking the handler.&lt;/strong&gt; Every browser sends &lt;code&gt;Accept-Encoding: zstd, br&lt;/code&gt;
before &lt;code&gt;gzip&lt;/code&gt;, and a server that made this a per-handler choice would be making everybody write the same
three lines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;/library/zstd/&quot;&gt;zstd&lt;/a&gt; at level 3 where the client takes it, and &lt;a href=&quot;/library/brotli/&quot;&gt;brotli&lt;/a&gt; at quality 5
otherwise.&lt;/strong&gt; The order is the only decision: zstd at 3 compresses about as well as brotli at 5 in a
fraction of the time, which is what matters for a body being encoded on the way out rather than built
ahead of time. &lt;code&gt;Content-Encoding&lt;/code&gt; says which one it was.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Over a kilobyte.&lt;/strong&gt; Below that either encoding usually makes a body &lt;em&gt;larger&lt;/em&gt;, having a frame to write.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A body that does not get smaller is sent as it was.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Vary: Accept-Encoding&lt;/code&gt; goes on whether or not this one was compressed&lt;/strong&gt;, on every response that
consulted the header. What a cache must not do is hand a compressed body to a client that did not ask,
and it cannot know that unless the response says so.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The escape hatch is to set &lt;code&gt;Content-Encoding&lt;/code&gt; yourself&lt;/strong&gt;, which says the body is already encoded. It is
the only one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Accept-Encoding&lt;/code&gt; is split into tokens&lt;/strong&gt; rather than searched for two letters, so &lt;code&gt;br;q=0&lt;/code&gt; is a client
saying it would rather not — which is not the same as not mentioning it. &lt;strong&gt;It is asked once per name&lt;/strong&gt;,
so &lt;code&gt;zstd;q=0, br&lt;/code&gt; gets brotli rather than nothing.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>slate:gzip</title>
    <link href="https://slatelang.dev/library/gzip/"/>
    <id>https://slatelang.dev/library/gzip/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>gzip and zlib — the compression a program has wherever slate runs, including a browser.</summary>
    <content type="html">&lt;h1 id=&quot;slategzip&quot;&gt;&lt;code&gt;slate:gzip&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;gzip and zlib — the compression a program has wherever slate runs, including a browser.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { gzip, gunzip, deflate, inflate } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:gzip

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; page &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toBytes&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;&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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; small &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gzip&lt;/span&gt;(page)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; back &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gunzip&lt;/span&gt;(small, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)        &lt;span class=&quot;hl-comment&quot;&gt;// the limit is not optional&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(small) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(page))
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(page)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)

    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; zipped &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;deflate&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 same text, wrapped as zlib instead&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; flat &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;inflate&lt;/span&gt;(zipped, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&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-function&quot;&gt;fromBytes&lt;/span&gt;(flat&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;((&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;gunzip&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;toBytes&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 gzip stream&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-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;))&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true true
the same text, wrapped as zlib instead
false
&lt;/code&gt;&lt;/pre&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;gzip(data)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of the bytes, wrapped as a gzip member&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;gunzip(data, limit)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of &lt;code&gt;{ ok, value }&lt;/code&gt; — the bytes, or why not&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;deflate(data)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of the bytes, wrapped as zlib&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;inflate(data, limit)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of &lt;code&gt;{ ok, value }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt; is text or bytes; text crosses as its UTF-8, which is what goes on a wire either way.&lt;/p&gt;
&lt;h2 id=&quot;which-of-the-two-wrappers&quot;&gt;Which of the two wrappers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;gzip&lt;/code&gt; is the file format&lt;/strong&gt; — the one &lt;code&gt;gzip&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;Content-Encoding: gzip&lt;/code&gt; all mean, with a
ten-byte header and a trailer carrying a length and a CRC-32.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;deflate&lt;/code&gt; is zlib&lt;/strong&gt; — two bytes of header and an adler-32, which is what &lt;code&gt;Content-Encoding: deflate&lt;/code&gt;
means in practice and what every HTTP client expects under that name, despite what the name says.&lt;/p&gt;
&lt;p&gt;Neither is the bare deflate stream that sits inside both. A program that needs &lt;em&gt;that&lt;/em&gt; is writing a
container of its own, and has to say so byte by byte anyway.&lt;/p&gt;
&lt;h2 id=&quot;every-one-of-them-answers-a-promise&quot;&gt;Every one of them answers a promise&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A browser’s compression is a stream, and there is no synchronous way to ask it.&lt;/strong&gt; So the surface is
promise-shaped on every host rather than being synchronous in the interpreter and absent in a browser —
which is the trade this module exists to avoid making. Nothing is waiting for a network here; on the
interpreter the answer is a promise that has already been settled.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/library/brotli/&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/a&gt; is synchronous and stays so: its signature was written before there was a
second host, and a program already holds it.&lt;/p&gt;
&lt;h2 id=&quot;the-limit-is-required&quot;&gt;The limit is required&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A deflate stream carries no length, and a crafted few hundred bytes expands without bound.&lt;/strong&gt; So the two
that read say how large an answer the caller is prepared to hold, and there is no form that omits it.&lt;/p&gt;
&lt;p&gt;For a gzip stream the trailer states the length, so the refusal happens before a byte is allocated. For a
zlib stream there is nothing to state it, so the output is counted as it arrives.&lt;/p&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Compressing faults and decompressing answers a result&lt;/strong&gt;, which is the rule everywhere in slate: a value
the program built cannot fail to be compressed, and bytes that came from somewhere else can be anything.&lt;/p&gt;
&lt;p&gt;The sentences are about the container — &lt;em&gt;this does not begin with gzip’s two magic bytes&lt;/em&gt;, &lt;em&gt;this expands
past the N bytes it was allowed&lt;/em&gt;, &lt;em&gt;this gzip stream’s checksum does not match its contents&lt;/em&gt; — and slate
reads that container itself on both back ends, so they are the same words wherever the program runs.
&lt;a href=&quot;/reference/javascript/&quot;&gt;The JavaScript back end&lt;/a&gt; names the one sentence that is not.&lt;/p&gt;
&lt;h2 id=&quot;what-compresses-to-what-is-not-promised&quot;&gt;What compresses to what is not promised&lt;/h2&gt;
&lt;p&gt;Two deflate implementations agree about the format and not about the stream. The same text packed by the
interpreter and by a browser is a different length and a different set of bytes, and both are correct —
so a program may compare what came &lt;em&gt;back&lt;/em&gt;, and never the compressed bytes themselves.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; compresses a response without asking the handler; that page says what the rules
are.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Globals</title>
    <link href="https://slatelang.dev/library/globals/"/>
    <id>https://slatelang.dev/library/globals/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>The names a program has in scope with no import.</summary>
    <content type="html">&lt;h1 id=&quot;globals&quot;&gt;Globals&lt;/h1&gt;
&lt;p&gt;The names a program has in scope with no import.&lt;/p&gt;
&lt;h2 id=&quot;printing-and-tests&quot;&gt;Printing and tests&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;print(…)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;any number of values, separated by a space&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assert(condition)&lt;/code&gt;, &lt;code&gt;assert(condition, message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;raises where the condition is false&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;assertEq(got, wanted)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;renders both sides, quoting a string&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The two assertions raise rather than answer, because a failed assertion is not a condition the test was
going to handle. See &lt;a href=&quot;/reference/tests/&quot;&gt;Tests&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;kinds-and-conversions&quot;&gt;Kinds and conversions&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;string  number  integer  real  boolean  len&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The type words are the conversions&lt;/strong&gt;, and the same word &lt;a href=&quot;/reference/patterns/&quot;&gt;tests in a pattern&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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-number&quot;&gt;123&lt;/span&gt;) &lt;span class=&quot;hl-keyword&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;!&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-type&quot;&gt;number&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-type&quot;&gt;number&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nonsense&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-type&quot;&gt;integer&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2.9&lt;/span&gt;))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-type&quot;&gt;boolean&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;))           &lt;span class=&quot;hl-comment&quot;&gt;// only false and null are false&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&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;日本語&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))        &lt;span class=&quot;hl-comment&quot;&gt;// in characters&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;123!
42 null
2
true
3
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;text&quot;&gt;Text&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;chars  split  join  contains  indexOf  lastIndexOf  startsWith  endsWith&lt;/code&gt;
&lt;code&gt;trim  trimStart  trimEnd  upper  lower  normalize  casefold  replace  repeat&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Every position is &lt;strong&gt;in characters&lt;/strong&gt;, never in bytes.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;indexOf&lt;/code&gt; answers &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; rather than &lt;code&gt;-1&lt;/code&gt;, because slate has a null and the operators that go with
it: &lt;code&gt;indexOf(s, x) ?? 0&lt;/code&gt; says what a sentinel makes a reader work out.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A search may be told where to start.&lt;/strong&gt; &lt;code&gt;indexOf(s, x, from)&lt;/code&gt; and &lt;code&gt;lastIndexOf(s, x, from)&lt;/code&gt; take a
third position, and a negative one counts back from the end.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;split&lt;/code&gt; on an empty separator splits into characters.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Case is the whole Unicode database&lt;/strong&gt;, so &lt;code&gt;upper(&amp;quot;Straße&amp;quot;)&lt;/code&gt; is &lt;code&gt;STRASSE&lt;/code&gt; and &lt;code&gt;lower(&amp;quot;ΟΔΟΣ&amp;quot;)&lt;/code&gt; ends in
a final sigma. A case mapping may change a string’s length; both back ends answer the same thing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;trim&lt;/code&gt; is Unicode’s &lt;code&gt;White_Space&lt;/code&gt;&lt;/strong&gt;, so a no-break space comes off and a zero-width no-break space
— which the database does not call a space — stays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;normalize(s, form)&lt;/code&gt; takes one of &lt;code&gt;&amp;quot;NFC&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;NFD&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;NFKC&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;NFKD&amp;quot;&lt;/code&gt;&lt;/strong&gt; and faults on anything
else rather than falling to a default.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;casefold&lt;/code&gt; is not &lt;code&gt;lower&lt;/code&gt;.&lt;/strong&gt; It is the key to store beside a name somebody will search for: &lt;code&gt;ß&lt;/code&gt;
folds to &lt;code&gt;ss&lt;/code&gt;, folding is idempotent, and what it answers is composed.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;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;Straße&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;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;ΟΔΟΣ&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;casefold&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;STRASSE&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;casefold&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;Straße&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;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;STRASSE&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;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;Straße&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;normalize&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;hl-variable&quot;&gt;\u{301}&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;NFC&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&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;é&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;STRASSE οδος
true false
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As methods, a string answers: &lt;code&gt;len chars split contains indexOf lastIndexOf startsWith endsWith trim trimStart trimEnd upper lower normalize casefold replace repeat number integer real boolean string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;numbers&quot;&gt;Numbers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;abs  floor  ceil  round  trunc  sqrt  pow  min  max&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The four roundings leave an integer alone&lt;/strong&gt;, an integer already being whole.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt; take as many arguments as they are given&lt;/strong&gt; and answer an integer when every one of
them was — a &lt;code&gt;min&lt;/code&gt; that answered a real for two integers would make every use of it in an index a
conversion.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pow&lt;/code&gt; of two integers with a non-negative exponent answers an &lt;strong&gt;integer&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As methods, a number answers: &lt;code&gt;abs floor ceil round trunc sqrt integer real boolean string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;arrays&quot;&gt;Arrays&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;push  pop  shift  unshift  insert  removeAt  clear&lt;/code&gt;
&lt;code&gt;map  filter  flatMap  forEach  reduce  find  findIndex  findLast  findLastIndex  every  some&lt;/code&gt;
&lt;code&gt;sort  sorted  reverse  reversed  slice  at  concat  flat  sum  join  contains  indexOf  lastIndexOf&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&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;3&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;sorted&lt;/span&gt;()&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;slice&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;flatMap&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; [n, n])&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&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;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;.&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;flat&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;indexOf&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;9&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;find&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;], n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&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;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;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;at&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&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;3&lt;/span&gt;]&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;reversed&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;3
6 [1, 2, [3]]
null 2
3 [3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where slate parts from JavaScript it is &lt;strong&gt;to remove a case rather than add one&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A mutator answers nothing&lt;/strong&gt;, so &lt;code&gt;sort&lt;/code&gt; and &lt;code&gt;unshift&lt;/code&gt; cannot be mistaken for the copying forms
&lt;code&gt;sorted&lt;/code&gt; and &lt;code&gt;concat&lt;/code&gt;. The bare verb changes the array and the participle answers a new one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nothing answers absence.&lt;/strong&gt; &lt;code&gt;pop&lt;/code&gt;, &lt;code&gt;shift&lt;/code&gt; and &lt;code&gt;at&lt;/code&gt; &lt;strong&gt;fault&lt;/strong&gt; where there is nothing there, while
&lt;code&gt;find&lt;/code&gt; and &lt;code&gt;indexOf&lt;/code&gt; answer &lt;strong&gt;&lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; — a search that found nothing is an answer, and reaching past
the end is a mistake.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;at&lt;/code&gt; and &lt;code&gt;slice&lt;/code&gt; count back from the end&lt;/strong&gt; where the position is negative, which is the whole reason
JavaScript grew &lt;code&gt;at&lt;/code&gt; beside &lt;code&gt;xs[i]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A comparator answers a number&lt;/strong&gt; whose sign orders the pair, as &lt;code&gt;compare&lt;/code&gt; does.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;objects&quot;&gt;Objects&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;keys  values  entries  has  without&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; o &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&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;keys&lt;/span&gt;(o), &lt;span class=&quot;hl-function&quot;&gt;values&lt;/span&gt;(o), &lt;span class=&quot;hl-function&quot;&gt;has&lt;/span&gt;(o, &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;without&lt;/span&gt;(o, &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;), o)

&lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; [k, v] &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;entries&lt;/span&gt;(o)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(k, v)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;] [1, 2] true
{b: 2} {a: 1, b: 2}
a 1
b 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;without&lt;/code&gt; answers a NEW object&lt;/strong&gt;, which is &lt;code&gt;with&lt;/code&gt;‘s rule read the other way: a slate object’s shape
is not a thing one name changes under another’s feet. A key that is not there is not an error, so a
table forgetting something it is unsure of is one line — and a copy of a &lt;a href=&quot;/reference/data-types/&quot;&gt;data value&lt;/a&gt;
is a data value, as &lt;code&gt;with&lt;/code&gt;‘s is.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;proto&lt;/code&gt; a declaration wrote is not a field these report.&lt;/strong&gt; A class instance and a data variant
reach what they are through it, so &lt;code&gt;keys&lt;/code&gt;, &lt;code&gt;values&lt;/code&gt;, &lt;code&gt;entries&lt;/code&gt;, &lt;code&gt;has&lt;/code&gt;, &lt;code&gt;len&lt;/code&gt; and &lt;code&gt;without&lt;/code&gt; all pass
over it — which is what &lt;code&gt;print&lt;/code&gt; has always done. A &lt;code&gt;proto&lt;/code&gt; a &lt;em&gt;program&lt;/em&gt; wrote on a plain object is an
ordinary field and is reported like any other.&lt;/p&gt;
&lt;p&gt;An object answers &lt;strong&gt;no&lt;/strong&gt; methods of its own — its names belong to the program, and a builtin &lt;code&gt;o.keys&lt;/code&gt;
would give every object a field nothing put there. The &lt;a href=&quot;/library/&quot;&gt;four universal methods&lt;/a&gt; are the
exception, and a field the program wrote wins over those.&lt;/p&gt;
&lt;h2 id=&quot;json&quot;&gt;JSON&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;parseJSON(text)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;result&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;toJSON(v)&lt;/code&gt;, &lt;code&gt;toJSON(v, indent)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a string; &lt;strong&gt;faults&lt;/strong&gt; where the value has no JSON form&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;The two directions use the two channels&lt;/strong&gt;, and they genuinely differ: text from a file, a socket or a
person is a condition every caller was going to handle, and a function or a circle in a value the program
built itself is a defect in that program. &lt;code&gt;JSON.parse&lt;/code&gt; and &lt;code&gt;JSON.stringify&lt;/code&gt; both throw, so node treats the
two alike.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A value with no JSON form is named rather than dropped.&lt;/strong&gt; &lt;code&gt;JSON.stringify&lt;/code&gt; drops a function silently
from an object and turns it into &lt;code&gt;null&lt;/code&gt; inside an array, so a request body goes out with a field missing
and nothing says which.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A non-string key is refused&lt;/strong&gt;, rendering it as text would make &lt;code&gt;{ 1: &amp;quot;a&amp;quot; }&lt;/code&gt; and &lt;code&gt;{ &amp;quot;1&amp;quot;: &amp;quot;a&amp;quot; }&lt;/code&gt; one
document.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A class says what it encodes as with &lt;code&gt;toJSON(self)&lt;/code&gt;&lt;/strong&gt; — see &lt;a href=&quot;/reference/objects/&quot;&gt;Objects&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The parse error is the whole rendering&lt;/strong&gt;, not one sentence. A JSON document is usually
machine-written and long, so &lt;em&gt;“expected a string”&lt;/em&gt; on its own says nothing a person can act on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;bytes&quot;&gt;Bytes&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;toBytes(s)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an array of numbers&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fromBytes(bs)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a &lt;strong&gt;result&lt;/strong&gt; — arbitrary bytes are not text&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;len(toBytes(s))&lt;/code&gt; is the byte count, so there is no third name. These are the one place a slate program
sees UTF-8, and two things need them: a &lt;code&gt;Content-Length&lt;/code&gt;, and a read where a character may be split across
two arrivals.&lt;/p&gt;
&lt;h2 id=&quot;timers&quot;&gt;Timers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;setTimeout(fn, ms)  setInterval(fn, ms)  clearTimeout(id)  clearInterval(id)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The callback comes first, which is node’s order. Both &lt;code&gt;ms&lt;/code&gt; forms also take a
&lt;a href=&quot;/library/time/&quot;&gt;duration&lt;/a&gt;. &lt;strong&gt;A timer keeps the program alive.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;promises&quot;&gt;Promises&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;sleep  resolve  reject  pending  settle  fail&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;generators&quot;&gt;Generators&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;next(g)&lt;/code&gt;, which is &lt;code&gt;g.next()&lt;/code&gt; — see &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fetch&quot;&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;fetch&lt;/span&gt;(url, options)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;node’s name and the browser’s, and it &lt;strong&gt;answers a result&lt;/strong&gt; rather than throwing — which is slate’s rule
for anything that reaches the network, not a disagreement with either. It is native because HTTPS needs
OpenSSL; the &lt;em&gt;server&lt;/em&gt; half is &lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; and is written in slate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It works on both back ends&lt;/strong&gt;, over the host’s own &lt;code&gt;fetch&lt;/code&gt; under &lt;code&gt;slate js&lt;/code&gt; — a status, a headers
object with lower-cased names, and a body. Nothing in this file says &lt;em&gt;“not in the JavaScript back end
yet”&lt;/em&gt; any more.&lt;/p&gt;
&lt;p&gt;Two things differ there and &lt;a href=&quot;/reference/javascript/&quot;&gt;JavaScript&lt;/a&gt; says why: &lt;strong&gt;&lt;code&gt;trust&lt;/code&gt; refuses&lt;/strong&gt;,
no JavaScript host letting a program add a certificate authority for one request, and &lt;strong&gt;the redirect
rule is the host’s&lt;/strong&gt; — the interpreter follows at most five and refuses one that leaves &lt;code&gt;https&lt;/code&gt; for
&lt;code&gt;http&lt;/code&gt;, where a browser follows them itself and gives a page no way in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A response header that repeats is joined with &lt;code&gt;&amp;quot;, &amp;quot;&lt;/code&gt;&lt;/strong&gt;, on both. An object has one value per name
and HTTP does not: &lt;code&gt;Link&lt;/code&gt;, &lt;code&gt;Vary&lt;/code&gt; and &lt;code&gt;Via&lt;/code&gt; all repeat, and combining them is what RFC 9110 allows
and what a browser’s &lt;code&gt;Headers&lt;/code&gt; hands over already done.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;Set-Cookie&lt;/code&gt; is the exception and is a LIST&lt;/strong&gt;, of the lines as they arrived, absent when there were
none. The same section of RFC 9110 excludes it and the reason is arithmetic: a cookie carries commas
inside itself — &lt;code&gt;Expires=Wed, 21 Oct 2026 07:28:00 GMT&lt;/code&gt; — so two cookies joined by commas cannot be
taken apart again by anything. In a browser it is absent however many arrived: &lt;code&gt;Set-Cookie&lt;/code&gt; is a
forbidden response-header name, so a page never reads one. The browser still applies the cookie.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A body that is not UTF-8 is &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;&lt;/strong&gt; rather than a string of replacement characters, which is the same
answer &lt;code&gt;run&lt;/code&gt; gives and for the same reason: slate has no byte value for it to be.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Functions</title>
    <link href="https://slatelang.dev/reference/functions/"/>
    <id>https://slatelang.dev/reference/functions/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>There is no keyword on a function. The shape is what identifies it: a name, a parameter list in brackets, and then either = and an expression or an indented…</summary>
    <content type="html">&lt;h1 id=&quot;functions&quot;&gt;Functions&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;There is no keyword on a function.&lt;/strong&gt; The shape is what identifies it: a name, a parameter list in
brackets, and then either &lt;code&gt;=&lt;/code&gt; and an expression or an indented block.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(x) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a, b)
    a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b

&lt;span class=&quot;hl-function&quot;&gt;grade&lt;/span&gt;(mark)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; mark &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;=&lt;/span&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;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-keyword&quot;&gt;end&lt;/span&gt; grade

&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;add&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;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;20&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 3 A C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A block’s value is its trailing expression, so &lt;code&gt;return&lt;/code&gt; is for leaving early and nothing else.&lt;/p&gt;
&lt;p&gt;Functions are values. A definition binds a name in the scope it is written in, so a nested definition
is a closure over that scope:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; count &lt;span class=&quot;hl-keyword&quot;&gt;=&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-keyword&quot;&gt;=&lt;/span&gt; count &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
        count

    bump

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;c&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;c&lt;/span&gt;(), &lt;span class=&quot;hl-function&quot;&gt;c&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;h2 id=&quot;lambdas&quot;&gt;Lambdas&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; with the parameters on its left:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; double &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&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; add &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; (a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; zero &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; () &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;double&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;21&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;2&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;zero&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;42 3 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; is the one right-associative operator, so &lt;code&gt;x -&amp;gt; y -&amp;gt; x + y&lt;/code&gt; is a function answering a function.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lambda’s body may be a block, written where the lambda is passed.&lt;/strong&gt; A newline inside brackets
normally means nothing, so a callback would otherwise have to be lifted out and named before the call
that wanted it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;forEach&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;], x &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; doubled &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&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;(x, doubled))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1 2
2 4
3 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt; are the two tokens that suspend the bracket rule, and only where they end a line.
&lt;strong&gt;A block lambda has to be the last argument&lt;/strong&gt;, because its block runs to the end of its last line and
a &lt;code&gt;,&lt;/code&gt; arriving there has nothing to mean. Every callback slate itself takes is last for that reason;
&lt;code&gt;setTimeout(fn, ms)&lt;/code&gt; keeps node’s order and so takes a one-line function.&lt;/p&gt;
&lt;p&gt;A lambda’s parameters may be annotated; its result may not, the arrow already standing between the
parameters and the body. What it answers is read off that body — see &lt;a href=&quot;/reference/types/&quot;&gt;Types&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;_-a-lambda-with-its-parameter-left-out&quot;&gt;&lt;code&gt;_&lt;/code&gt;, a lambda with its parameter left out&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;_&lt;/code&gt; where a value goes is the parameter of a function nobody wrote. What that function’s &lt;em&gt;body&lt;/em&gt; is
is the smallest thing around the &lt;code&gt;_&lt;/code&gt;: a call’s argument, a bracketed group, or the value of a
binding, an assignment or a &lt;code&gt;return&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; ns &lt;span class=&quot;hl-keyword&quot;&gt;=&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;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-function&quot;&gt;map&lt;/span&gt;(ns, &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&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;filter&lt;/span&gt;(ns, &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;&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;map&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-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;upper&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[2, 4, 10, 18]
[5, 9]
[&amp;quot;ADA&amp;quot;, &amp;quot;GRACE&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Every &lt;code&gt;_&lt;/code&gt; is a parameter of its own, left to right.&lt;/strong&gt; Two of them make a function of two
parameters, which is exactly what a comparator wants:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; people &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; [{ name&lt;span class=&quot;hl-keyword&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;grace&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, age&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;45&lt;/span&gt; }, { name&lt;span class=&quot;hl-keyword&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;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, age&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;36&lt;/span&gt; }]

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sorted&lt;/span&gt;(people, &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;age &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;age), &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;name))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[&amp;quot;ada&amp;quot;, &amp;quot;grace&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;That rule is also this notation’s one surprise.&lt;/strong&gt; &lt;code&gt;_ &amp;gt; 3 &amp;amp;&amp;amp; _ &amp;lt; 9&lt;/code&gt; is a function of &lt;em&gt;two&lt;/em&gt;
parameters and not one test of one number, so it is refused where a callback taking one was wanted.
Write the parameter out when you mean to mention it twice: &lt;code&gt;n -&amp;gt; n &amp;gt; 3 &amp;amp;&amp;amp; n &amp;lt; 9&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lone &lt;code&gt;_&lt;/code&gt; is handed outward to the thing around it&lt;/strong&gt;, which is what makes &lt;code&gt;f(_)&lt;/code&gt; a way of naming
&lt;code&gt;f&lt;/code&gt; rather than a way of handing it an identity — and what makes &lt;code&gt;add(_, 1)&lt;/code&gt; the partial application
it reads as. Where there is nothing around it, a &lt;code&gt;_&lt;/code&gt; on its own is the identity function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;add&lt;/span&gt;(a, b) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map&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;add&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;_&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; id &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;_&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[2, 3, 4]
7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A &lt;code&gt;_&lt;/code&gt; with no argument, no group and no right-hand side around it has nothing for its function to
be, and is refused where it stands:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;length&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`_` stands for the parameter of a function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;_&lt;/code&gt; in a pattern is untouched.&lt;/strong&gt; A match arm’s &lt;code&gt;_&lt;/code&gt;, a destructuring’s and the name in &lt;code&gt;val _ = f()&lt;/code&gt; all mean the wildcard they always did — the notation here is about &lt;code&gt;_&lt;/code&gt; standing where a
&lt;em&gt;value&lt;/em&gt; goes.&lt;/p&gt;
&lt;h2 id=&quot;type-parameters&quot;&gt;Type parameters&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;[T]&lt;/code&gt; after the name says the definition is generic over a type, and the answer is said in terms of
what the call was given:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;first[T](xs&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;array&lt;/span&gt; of T) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; T &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(&lt;span class=&quot;hl-function&quot;&gt;first&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-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;first&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;ada 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are no type arguments at a call — they are solved from the arguments, and every argument has to
fit the type the parameter was solved to, so &lt;code&gt;pair(1, &amp;quot;x&amp;quot;)&lt;/code&gt; for &lt;code&gt;pair[T](a: T, b: T)&lt;/code&gt; is refused.
&lt;a href=&quot;/reference/types/&quot;&gt;Types&lt;/a&gt; says how the answer is picked and what a union does.&lt;/p&gt;
&lt;h2 id=&quot;defaults&quot;&gt;Defaults&lt;/h2&gt;
&lt;p&gt;A parameter may carry what it is when nobody gives one, on a definition, a lambda, a method, or a
class’s &lt;code&gt;new&lt;/code&gt;. The annotation comes first and the default after it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(name, greeting &lt;span class=&quot;hl-keyword&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;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;=&lt;/span&gt; greeting &lt;span class=&quot;hl-keyword&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;, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; name
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(n&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; n

&lt;span class=&quot;hl-function&quot;&gt;print&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;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;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;ada&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;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;(&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-number&quot;&gt;7&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;hello, ada
hi, ada
0 7
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The default is worked out at the call, not where the function was written.&lt;/strong&gt; Everything else follows
from that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;f(xs = [])&lt;/code&gt; gives every call an array of its own.&lt;/li&gt;
&lt;li&gt;A default may read the parameters to its left: &lt;code&gt;slice(xs, from, to = len(xs))&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A default that would fault costs nothing to a call that gave the argument.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;A parameter that may be left out has to come last&lt;/strong&gt;, or leaving it out would slide every later
argument one place left. The parser says so where it is written, and an arity complaint then names a
&lt;strong&gt;range&lt;/strong&gt; rather than only its upper end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A parameter nobody gave is not bound at all&lt;/strong&gt;, which is why there is no sentinel: slate refuses to
store absence, so there is no “given, and the value was absence” to tell from “not given”. &lt;code&gt;f(1, null)&lt;/code&gt;
therefore passes &lt;code&gt;null&lt;/code&gt; and does &lt;strong&gt;not&lt;/strong&gt; take the default — which is the simpler rule, JavaScript’s
&lt;code&gt;f(1, undefined)&lt;/code&gt; doing the opposite.&lt;/p&gt;
&lt;h2 id=&quot;named-arguments&quot;&gt;Named arguments&lt;/h2&gt;
&lt;p&gt;An argument may say which parameter it fills, which is what makes a default in the &lt;em&gt;middle&lt;/em&gt; reachable:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(name, greeting &lt;span class=&quot;hl-keyword&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;hello&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, punct &lt;span class=&quot;hl-keyword&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;!&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; greeting &lt;span class=&quot;hl-keyword&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;, &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; name &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; punct

&lt;span class=&quot;hl-function&quot;&gt;print&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;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;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;ada&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, punct &lt;span class=&quot;hl-keyword&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;?&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))            &lt;span class=&quot;hl-comment&quot;&gt;// greeting skipped&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;greet&lt;/span&gt;(greeting &lt;span class=&quot;hl-keyword&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;, name &lt;span class=&quot;hl-keyword&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;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;hello, ada!
hello, ada?
hi, ada!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;=&lt;/code&gt; and not &lt;code&gt;:&lt;/code&gt;&lt;/strong&gt;, because the declaration already writes the default after an equals. Assignment is
a statement in slate, so &lt;code&gt;=&lt;/code&gt; never appears inside an expression and there is nothing for it to be
confused with; &lt;code&gt;==&lt;/code&gt; is its own token, so &lt;code&gt;f(ok == true)&lt;/code&gt; is an ordinary positional argument.&lt;/p&gt;
&lt;p&gt;A name comes after every positional argument, and it may pick out any parameter. A class’s &lt;code&gt;new&lt;/code&gt; and a
data variant’s maker are ordinary functions, so &lt;code&gt;Rect(h = 4, w = 3)&lt;/code&gt; and &lt;code&gt;Circle(r = 7)&lt;/code&gt; read the same
way. &lt;strong&gt;A method names its parameters and not its receiver.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Naming a parameter twice, naming one the function does not have, naming an argument to a builtin, or
naming one to a function that gathers with &lt;code&gt;...&lt;/code&gt; are each refused with their own sentence — the second
lists the parameters it does have.&lt;/p&gt;
&lt;h2 id=&quot;rest&quot;&gt;&lt;code&gt;...rest&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A function may gather what is left over:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;total&lt;/span&gt;(first, &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;others) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;reduce&lt;/span&gt;(others, (a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; b, first)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;=&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-function&quot;&gt;total&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;total&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-function&quot;&gt;total&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;xs))         &lt;span class=&quot;hl-comment&quot;&gt;// the spread it is the counterpart of&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
6
6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;...rest&lt;/code&gt; is always bound&lt;/strong&gt;, to an empty array where a call gave nothing past the fixed parameters,
so there is no absence to test for. It must be last and takes no default — one could never fire. A
default &lt;em&gt;before&lt;/em&gt; it is fine.&lt;/p&gt;
&lt;h2 id=&quot;callbacks-take-as-many-arguments-as-they-declare&quot;&gt;Callbacks take as many arguments as they declare&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A call the program writes is strict&lt;/strong&gt;: &lt;code&gt;f(1, 2)&lt;/code&gt; where &lt;code&gt;f&lt;/code&gt; takes one argument is refused, and so is
&lt;code&gt;f()&lt;/code&gt; where it takes one. The count is a claim you made, and getting it wrong is a mistake.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A callback is different.&lt;/strong&gt; Where a builtin calls a function &lt;em&gt;you&lt;/em&gt; supplied, it passes as many
arguments as that function declares and no more:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map&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;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;))          &lt;span class=&quot;hl-comment&quot;&gt;// the element is there and this one ignores it&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;map&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;], (v) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;))     &lt;span class=&quot;hl-comment&quot;&gt;// and this one reads it&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;forEach&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;-&amp;gt;&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;span class=&quot;hl-function&quot;&gt;setTimeout&lt;/span&gt;(() &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;later&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[9, 9, 9]
[2, 4, 6]
tick
tick
later
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is what a handler wants to look like — &lt;code&gt;on(node, &amp;quot;click&amp;quot;, () -&amp;gt; setCount(n + 1))&lt;/code&gt; for one that
does not read the event, &lt;code&gt;onData(socket, () -&amp;gt; stop())&lt;/code&gt; for a reader that does not care what arrived
— and it is the rule everywhere a native calls back: array walks, &lt;code&gt;sorted&lt;/code&gt;, timers, sockets,
WebSocket handlers, &lt;a href=&quot;/library/dom/&quot;&gt;the document&lt;/a&gt;‘s events.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declaring more than the caller has is still a fault, and it names the caller&lt;/strong&gt;, because your
function is not the thing that is wrong:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;map&lt;/span&gt;([&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;], (a, b) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; a)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`map` takes (integer) -&amp;gt; any here, and this is (integer, any) -&amp;gt; integer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is the checker, which knows what &lt;code&gt;map&lt;/code&gt; hands over. Reached through a value it cannot see, the
machine says the same thing in its own words — &lt;em&gt;“&lt;code&gt;map&lt;/code&gt; calls this with 1 argument and it takes 2
arguments”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;TypeScript draws the line in nearly the same place, and the difference is worth knowing: there a
function of fewer parameters is usable wherever more are supplied, &lt;em&gt;including&lt;/em&gt; through a type you
declared yourself, because the call that follows ignores the extra argument. &lt;strong&gt;A slate call does
not&lt;/strong&gt; — it passes what you wrote — so the relaxation holds only where the caller is a builtin that
adapts to the callee. A parameter you annotated is compared strictly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(f&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; (&lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;, &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;integer&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;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;apply&lt;/span&gt;(n &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;`apply` takes (integer, integer) -&amp;gt; integer here, and this is (any) -&amp;gt; any
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;destructuring-parameters&quot;&gt;Destructuring parameters&lt;/h2&gt;
&lt;p&gt;A parameter may take its argument apart, on a definition or a lambda:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;({ n }) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;*&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; g &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; ({ n }) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;+&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;({ n&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;21&lt;/span&gt; }), &lt;span class=&quot;hl-function&quot;&gt;g&lt;/span&gt;({ n&lt;span class=&quot;hl-keyword&quot;&gt;:&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;42 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The pattern is any &lt;a href=&quot;/reference/patterns/&quot;&gt;pattern&lt;/a&gt; that binds.&lt;/p&gt;
&lt;h2 id=&quot;annotations&quot;&gt;Annotations&lt;/h2&gt;
&lt;p&gt;Per parameter, and per result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Point&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; }

&lt;span class=&quot;hl-function&quot;&gt;double&lt;/span&gt;(x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;f&lt;/span&gt;(a, b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Point, c) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; b&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; c     &lt;span class=&quot;hl-comment&quot;&gt;// nothing has to be annotated for anything to be&lt;/span&gt;

&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;3&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;, { x&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, y&lt;span class=&quot;hl-keyword&quot;&gt;:&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;6 6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An annotation is checked &lt;strong&gt;at the call&lt;/strong&gt; for a parameter, and where the function answers for a result.
See &lt;a href=&quot;/reference/types/&quot;&gt;Types&lt;/a&gt; for what the compiler will say about one before the program runs.&lt;/p&gt;
&lt;h2 id=&quot;async-and-generators&quot;&gt;&lt;code&gt;async&lt;/code&gt; and generators&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt; in front of a definition or a lambda makes it answer a promise; a function holding a &lt;code&gt;yield&lt;/code&gt; is
a generator, with no word on the definition. Both are in &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;methods&quot;&gt;Methods&lt;/h2&gt;
&lt;p&gt;A function stored in an object field is a method. Whether it is handed a receiver depends on where it
was found — see &lt;a href=&quot;/reference/objects/&quot;&gt;Objects&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:fs</title>
    <link href="https://slatelang.dev/library/fs/"/>
    <id>https://slatelang.dev/library/fs/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Ten operations, each in a promise-shaped and a blocking form.</summary>
    <content type="html">&lt;h1 id=&quot;slatefs&quot;&gt;&lt;code&gt;slate:fs&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Ten operations, each in a promise-shaped and a blocking form.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { readFile, writeFile, mkdir, readDir, rename, remove, rmdir } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:fs

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;mkdir&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;writeFile&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/notes.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 line&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; notes &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readFile&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/notes.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;if&lt;/span&gt; notes&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(notes&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)
    &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;could not read it:&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, notes&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;error)

    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;readDir&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch&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;
        { ok&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; names } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(names)
        { error&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; e } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e)

    &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;rename&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/notes.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;scratch/kept.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;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;remove&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/kept.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;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;rmdir&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch&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;/code&gt;&lt;/pre&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;readFile(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;readBytes(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;an array of numbers&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;writeFile(path, v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;replaces whatever was there&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;appendFile(path, v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;adds to it, and makes the file where there is none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;writeBytes(path, bs)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the same, given the bytes themselves&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;appendBytes(path, bs)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;readDir(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the names in it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;stat(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;size, kind, and &lt;code&gt;mtime&lt;/code&gt; as an &lt;a href=&quot;/library/time/&quot;&gt;instant&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;exists(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a plain &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; — the one call with no failure case&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;remove(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;mkdir(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;rmdir(path)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;rename(from, to)&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;Every one has a blocking twin under a &lt;code&gt;Sync&lt;/code&gt; suffix&lt;/strong&gt; — &lt;code&gt;readFileSync&lt;/code&gt;, &lt;code&gt;writeFileSync&lt;/code&gt;,
&lt;code&gt;appendFileSync&lt;/code&gt;, &lt;code&gt;statSync&lt;/code&gt; and the rest — which is node’s arrangement and node’s spelling:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;mkdirSync&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;writeFileSync&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/notes.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 line&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;readFileSync&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;scratch/notes.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;.&lt;/span&gt;value)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;results-not-rejections&quot;&gt;Results, not rejections&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A call that can fail answers a result — &lt;code&gt;{ ok: true, value: v }&lt;/code&gt; or &lt;code&gt;{ ok: false, error: text }&lt;/code&gt; — and
the promise never rejects.&lt;/strong&gt; A file that is not there is not a defect in the program asking for it, so the
caller is handed something it has to look at rather than an unwind it has to be ready for.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Giving a builtin the wrong kind of argument still raises&lt;/strong&gt;: &lt;code&gt;readFile(42)&lt;/code&gt; faults, &lt;code&gt;readFile(&amp;quot;/gone&amp;quot;)&lt;/code&gt;
answers.&lt;/p&gt;
&lt;p&gt;Every error carries libuv’s own sentence — &lt;code&gt;cannot read x: ENOENT: no such file or directory&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A file that is not valid UTF-8 has no slate string to become, so &lt;code&gt;readFile&lt;/code&gt; answers an error &lt;strong&gt;naming
&lt;code&gt;readBytes&lt;/code&gt;&lt;/strong&gt;. &lt;code&gt;writeFile&lt;/code&gt; renders anything that is not a string the way &lt;code&gt;print&lt;/code&gt; would.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;writeBytes&lt;/code&gt; and &lt;code&gt;appendBytes&lt;/code&gt; are the writing side of &lt;code&gt;readBytes&lt;/code&gt;&lt;/strong&gt;, and they are what a program
holding bytes wants: &lt;code&gt;writeFile&lt;/code&gt; would render an array of numbers as the text &lt;code&gt;[137, 80, ...]&lt;/code&gt;, which
is a picture of a PNG rather than one. Each takes an array of numbers from 0 to 255; anything
else is a fault naming &lt;code&gt;writeFile&lt;/code&gt; as the call that renders things.&lt;/p&gt;
&lt;h2 id=&quot;why-the-plain-names-are-the-asynchronous-ones&quot;&gt;Why the plain names are the asynchronous ones&lt;/h2&gt;
&lt;p&gt;A language whose entire event story is one loop has a lot to lose from a call that stops it: a server that
blocks on a read stops answering everybody. The &lt;code&gt;Sync&lt;/code&gt; forms are there because a great many programs are
not servers — a script that reads a configuration file before it does anything gains nothing from a promise
and pays for it in an &lt;code&gt;async&lt;/code&gt; function that exists only to hold an &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The naming is what keeps that from being a trap.&lt;/strong&gt; The blocking call is the one with the longer name and
the suffix, so reaching for it is a decision rather than an accident. The two halves agree on everything
but the waiting: a &lt;code&gt;Sync&lt;/code&gt; call answers the same result its promise would have settled to, error and all.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Faults</title>
    <link href="https://slatelang.dev/reference/faults/"/>
    <id>https://slatelang.dev/reference/faults/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>slate has two failure channels, and which one a thing uses says what kind of failure it is.</summary>
    <content type="html">&lt;h1 id=&quot;faults&quot;&gt;Faults&lt;/h1&gt;
&lt;p&gt;slate has &lt;strong&gt;two failure channels&lt;/strong&gt;, and which one a thing uses says what kind of failure it is.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;A result&lt;/strong&gt; — &lt;code&gt;{ ok: true, value: v }&lt;/code&gt; or &lt;code&gt;{ ok: false, error: text }&lt;/code&gt; — is for a condition the
caller was always going to deal with: a file that is not there, a connection refused, text that will
not parse, a password that does not match. The caller is handed something it has to look at.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A fault&lt;/strong&gt; unwinds until something catches it, and is for a defect in the program: the wrong kind of
argument, a division by zero, a value with no JSON form, an index past the end.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Neither is used for the other’s job anywhere in slate. &lt;code&gt;readFile(42)&lt;/code&gt; &lt;strong&gt;faults&lt;/strong&gt;; &lt;code&gt;readFile(&amp;quot;/gone&amp;quot;)&lt;/code&gt;
&lt;strong&gt;answers&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;A result costs no new machinery — it is an ordinary object, so &lt;a href=&quot;/reference/patterns/&quot;&gt;&lt;code&gt;match&lt;/code&gt;&lt;/a&gt; already
destructures one and the collector already traces one.&lt;/p&gt;
&lt;h2 id=&quot;throw&quot;&gt;&lt;code&gt;throw&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;throw v&lt;/code&gt; is a &lt;strong&gt;statement&lt;/strong&gt;, like &lt;code&gt;return&lt;/code&gt; and &lt;code&gt;break&lt;/code&gt;: nothing after it runs, and the value is not
optional — a fault with nothing in it says nothing to whoever catches it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;side&lt;/span&gt;(w)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; w &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&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;throw&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 side cannot be negative&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    w

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;side&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;side&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&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 side cannot be negative
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A caught fault re-thrown keeps its own words.&lt;/strong&gt; &lt;code&gt;throw e&lt;/code&gt; reads an object’s &lt;code&gt;message&lt;/code&gt; field rather than
rendering it — rendering would replace the fault with a &lt;em&gt;description&lt;/em&gt; of one. A string is its own
message; anything else is rendered as &lt;code&gt;print&lt;/code&gt; would.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The location becomes the &lt;code&gt;throw&lt;/code&gt;‘s own and does not travel.&lt;/strong&gt; By the time a program holds a fault it is
a line number and a file name, which no span can be rebuilt from — so a re-thrown fault says the words of
the original and points at the line that put it back.&lt;/p&gt;
&lt;h2 id=&quot;catch&quot;&gt;&lt;code&gt;catch&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Two forms of one thing. &lt;strong&gt;The postfix one is an expression&lt;/strong&gt;, so it stands where a value is wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;toPort&lt;/span&gt;(text)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;(text)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;that is not a port&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    n

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; port &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toPort&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nonsense&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;, so using the default&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-number&quot;&gt;8080&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(port)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;that is not a port, so using the default
8080
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the block one is for a run of statements:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;setUp&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;=&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;set up&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)

&lt;span class=&quot;hl-function&quot;&gt;go&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;it went wrong&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;setUp&lt;/span&gt;()
    &lt;span class=&quot;hl-function&quot;&gt;go&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;message, e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;line, e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;file &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;set up
it went wrong 4 true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;catch&lt;/code&gt; binds looser than every arithmetic operator, so &lt;code&gt;a + b catch …&lt;/code&gt; guards the sum, and tighter than
the lambda arrow, so &lt;code&gt;x -&amp;gt; risky() catch e -&amp;gt; 0&lt;/code&gt; gives the lambda a body that guards.&lt;/p&gt;
&lt;h2 id=&quot;the-fault-object&quot;&gt;The fault object&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A fault is an ordinary object&lt;/strong&gt; — &lt;code&gt;message&lt;/code&gt;, &lt;code&gt;line&lt;/code&gt; and &lt;code&gt;file&lt;/code&gt; — for the same reason a module is one:
slate objects already sort, print, go in arrays and match against patterns, so there is nothing here the
rest of the language does not already do.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;risky&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;gone&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;recover&lt;/span&gt;() &lt;span class=&quot;hl-keyword&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;recovered&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;try&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;risky&lt;/span&gt;())
&lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
        { message&lt;span class=&quot;hl-keyword&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;gone&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;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;recover&lt;/span&gt;()
        &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-string&quot;&gt;something else&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;recovered
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;what-catch-does-and-does-not-reach&quot;&gt;What &lt;code&gt;catch&lt;/code&gt; does and does not reach&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It works across an &lt;code&gt;await&lt;/code&gt;.&lt;/strong&gt; A coroutine carries its handlers with it when it is set aside, so a
promise that fails minutes later still raises inside the &lt;code&gt;try&lt;/code&gt; that was written around the &lt;code&gt;await&lt;/code&gt;.
See &lt;a href=&quot;/reference/asynchrony/&quot;&gt;Asynchrony&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It does not reach a callback.&lt;/strong&gt; &lt;code&gt;try setTimeout(...)&lt;/code&gt; guards the scheduling and nothing else, the
callback running from the loop long afterwards. That is inherent: there is no statement of the
program’s left to attach it to.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-not-here&quot;&gt;What is not here&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;finally&lt;/code&gt;.&lt;/strong&gt; A &lt;code&gt;try&lt;/code&gt; with nothing to handle the fault is refused rather than allowed to
swallow it silently.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Expressions</title>
    <link href="https://slatelang.dev/reference/expressions/"/>
    <id>https://slatelang.dev/reference/expressions/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Loosest at the top. Everything is left-associative except the lambda arrow.</summary>
    <content type="html">&lt;h1 id=&quot;expressions&quot;&gt;Expressions&lt;/h1&gt;
&lt;h2 id=&quot;the-precedence-table&quot;&gt;The precedence table&lt;/h2&gt;
&lt;p&gt;Loosest at the top. Everything is left-associative except the lambda arrow.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;power&lt;/th&gt;&lt;th&gt;operators&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;right&lt;/strong&gt;-associative, so &lt;code&gt;x -&amp;gt; y -&amp;gt; x + y&lt;/code&gt; is a function answering a function&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;&lt;code&gt;match&lt;/code&gt;, &lt;code&gt;catch&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a transformation of the thing to the left&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;&lt;code&gt;??&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&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;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;20&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;25&lt;/td&gt;&lt;td&gt;&lt;code&gt;is&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;30&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;lt;=&lt;/code&gt; &lt;code&gt;&amp;gt;&lt;/code&gt; &lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one level, because a chain of them is one comparison&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;35&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;non-associative&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;40&lt;/td&gt;&lt;td&gt;&lt;code&gt;\|&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;42&lt;/td&gt;&lt;td&gt;&lt;code&gt;^&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;44&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;amp;&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;50&lt;/td&gt;&lt;td&gt;&lt;code&gt;+&lt;/code&gt; &lt;code&gt;-&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;60&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;&lt;strong&gt;a shift binds like a multiplication&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;80&lt;/td&gt;&lt;td&gt;&lt;code&gt;++&lt;/code&gt; &lt;code&gt;--&lt;/code&gt; (postfix), call, &lt;code&gt;[…]&lt;/code&gt;, &lt;code&gt;.&lt;/code&gt;, &lt;code&gt;?.&lt;/code&gt;, &lt;code&gt;with&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Three placements are worth knowing because they decide what a line means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;match&lt;/code&gt; and &lt;code&gt;catch&lt;/code&gt; sit below every arithmetic operator&lt;/strong&gt;, so &lt;code&gt;a + b match …&lt;/code&gt; transforms the sum
rather than just &lt;code&gt;b&lt;/code&gt;, and &lt;code&gt;a + b catch …&lt;/code&gt; guards the sum. They sit &lt;strong&gt;above&lt;/strong&gt; the arrow, so
&lt;code&gt;x -&amp;gt; y match …&lt;/code&gt; gives the lambda a body that matches rather than matching on the lambda.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;??&lt;/code&gt; is looser than &lt;code&gt;||&lt;/code&gt;&lt;/strong&gt;, so &lt;code&gt;a ?? b || c&lt;/code&gt; reads as &lt;code&gt;a ?? (b || c)&lt;/code&gt;. A program that writes both
usually means the defaulting to happen last. (JavaScript refuses to mix them without parentheses.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A shift binds like a multiplication&lt;/strong&gt;, not like C’s, so &lt;code&gt;1 &amp;lt;&amp;lt; 2 + 3&lt;/code&gt; groups the way it reads.
&lt;code&gt;&amp;amp;&lt;/code&gt;, &lt;code&gt;^&lt;/code&gt; and &lt;code&gt;|&lt;/code&gt; sit above the comparisons, so &lt;code&gt;a &amp;amp; b == c&lt;/code&gt; is not C’s surprise either.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Prefix operators are &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 &lt;code&gt;--&lt;/code&gt;, all binding tighter than any infix operator and
looser than a call — &lt;code&gt;-f(x)&lt;/code&gt; negates the result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;_&lt;/code&gt; where a value goes is not an operator and is not in the table&lt;/strong&gt;, because what it reaches is
decided by the nearest enclosing argument, bracketed group or right-hand side rather than by a
binding power: &lt;code&gt;map(xs, _ * 2)&lt;/code&gt; is &lt;code&gt;map(xs, n -&amp;gt; n * 2)&lt;/code&gt;. See
&lt;a href=&quot;/reference/functions/&quot;&gt;Functions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;arithmetic-and-bitwise&quot;&gt;Arithmetic and bitwise&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;+ - * / %&lt;/code&gt; over integers and reals; see &lt;a href=&quot;/reference/values/&quot;&gt;Values&lt;/a&gt; for what &lt;code&gt;/&lt;/code&gt; does between two integers.
&lt;code&gt;+&lt;/code&gt; on two strings concatenates.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;| ^ &amp;amp; ~&lt;/code&gt; and the shifts &lt;code&gt;&amp;lt;&amp;lt; &amp;gt;&amp;gt;&lt;/code&gt; work on 64-bit integers.&lt;/p&gt;
&lt;h2 id=&quot;comparison&quot;&gt;Comparison&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Comparisons chain rather than associate&lt;/strong&gt;, which is mathematics’ reading and sysl’s:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;=&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-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;)          &lt;span class=&quot;hl-comment&quot;&gt;// `n` is evaluated once&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;code&gt;==&lt;/code&gt; and &lt;code&gt;!=&lt;/code&gt; compare by value; see &lt;a href=&quot;/reference/values/&quot;&gt;Values&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;logic&quot;&gt;Logic&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and &lt;code&gt;||&lt;/code&gt; short-circuit and &lt;strong&gt;answer the operand that decided&lt;/strong&gt;, not a boolean:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&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-keyword&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;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;2 x
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;??&lt;/code&gt; answers its left operand unless that is &lt;code&gt;null&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;d&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)         &lt;span class=&quot;hl-comment&quot;&gt;// `false` is a value&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&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;d&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
d
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;is&quot;&gt;&lt;code&gt;is&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;is&lt;/code&gt; puts a &lt;a href=&quot;/reference/patterns/&quot;&gt;pattern&lt;/a&gt; where a condition is wanted, using the same grammar a &lt;code&gt;match&lt;/code&gt; arm
does:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; not &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;|&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;true true true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It sits between &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; and the comparisons, so &lt;code&gt;a is P &amp;amp;&amp;amp; b &amp;gt; 0&lt;/code&gt; is two terms.&lt;/p&gt;
&lt;h2 id=&quot;ranges&quot;&gt;Ranges&lt;/h2&gt;
&lt;p&gt;A range is a &lt;strong&gt;value&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&quot;&gt;=&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-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;..&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;])            &lt;span class=&quot;hl-comment&quot;&gt;// exclusive&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])             &lt;span class=&quot;hl-comment&quot;&gt;// inclusive&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;[&lt;span class=&quot;hl-keyword&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])         &lt;span class=&quot;hl-comment&quot;&gt;// an end left out is taken from what it is used on&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(xs[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;..&lt;/span&gt;])&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[2, 3]
[2, 3]
hel
[3, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An end left out is taken from whatever the range is used on. Ranges do not associate, so &lt;code&gt;a..b..c&lt;/code&gt; is
refused. &lt;strong&gt;&lt;code&gt;a..=b&lt;/code&gt; is refused by name&lt;/strong&gt;, since a reader arriving from Rust writes it once.&lt;/p&gt;
&lt;h2 id=&quot;field-and-index&quot;&gt;Field and index&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;.&lt;/code&gt; reads a field, &lt;code&gt;[…]&lt;/code&gt; indexes an array, a string or an object.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;?.&lt;/code&gt; guards its own link and not the rest of the chain&lt;/strong&gt;, which is Kotlin’s rule:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { b&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { c&lt;span class=&quot;hl-keyword&quot;&gt;:&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-keyword&quot;&gt;?.&lt;/span&gt;b&lt;span class=&quot;hl-keyword&quot;&gt;?.&lt;/span&gt;c)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(a&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;missing&lt;span class=&quot;hl-keyword&quot;&gt;?.&lt;/span&gt;c)         &lt;span class=&quot;hl-comment&quot;&gt;// `?.` on the link that may be absent&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;1
null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;a?.b.c&lt;/code&gt; reads &lt;code&gt;b&lt;/code&gt; off &lt;code&gt;a&lt;/code&gt; or answers &lt;code&gt;null&lt;/code&gt;, and then asks &lt;code&gt;.c&lt;/code&gt; of whatever that was — so a nullish
&lt;code&gt;a&lt;/code&gt; faults at &lt;code&gt;.c&lt;/code&gt;, and &lt;code&gt;a?.b?.c&lt;/code&gt; is what the reader means. The rule is the one slate states everywhere
about absence: &lt;strong&gt;it stops at the boundary it arose at&lt;/strong&gt;, and one character quietly excusing every link
after it is the opposite of that.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;o?.m(a)&lt;/code&gt; &lt;strong&gt;does not evaluate its arguments&lt;/strong&gt; where there is nothing to call the method on.&lt;/li&gt;
&lt;li&gt;There is no &lt;code&gt;a?.[i]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;o?.f = v&lt;/code&gt; is refused: there is no answer to what writing into absence should do.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;with&quot;&gt;&lt;code&gt;with&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;a with b&lt;/code&gt; answers a copy of &lt;code&gt;a&lt;/code&gt; with &lt;code&gt;b&lt;/code&gt;‘s fields written over it. The right-hand side may be a
literal or any expression answering an object:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; base &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { a&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, b&lt;span class=&quot;hl-keyword&quot;&gt;:&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;(base &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt; { b&lt;span class=&quot;hl-keyword&quot;&gt;:&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;(base &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt; { c&lt;span class=&quot;hl-keyword&quot;&gt;:&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;{a: 1, b: 9}
{a: 1, b: 2, c: 3}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It binds as tightly as a field selection, so &lt;code&gt;a + b with { … }&lt;/code&gt; changes &lt;code&gt;b&lt;/code&gt; rather than the sum.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no spread in a literal.&lt;/strong&gt; &lt;code&gt;{ ...o, b: 2 }&lt;/code&gt; is &lt;code&gt;o with { b: 2 }&lt;/code&gt; and &lt;code&gt;[...xs, y]&lt;/code&gt; is
&lt;code&gt;concat(xs, [y])&lt;/code&gt;, both of which slate has, so a second spelling would buy nothing.&lt;/p&gt;
&lt;h2 id=&quot;spread-in-a-call&quot;&gt;Spread in a call&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;f(...xs)&lt;/code&gt; is the one spread slate has, and it exists because a computed argument list had no spelling
at all:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;parts) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;join&lt;/span&gt;(parts, &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;val&lt;/span&gt; xs &lt;span class=&quot;hl-keyword&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;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;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;show&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;xs))
&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-keyword&quot;&gt;...&lt;/span&gt;xs, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))        &lt;span class=&quot;hl-comment&quot;&gt;// in any order, any number of times&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;b-c
a-b-c-d
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Spreading something that is not an array is a fault naming the spread rather than the call. &lt;strong&gt;The
&lt;a href=&quot;/reference/types/&quot;&gt;checker&lt;/a&gt; says nothing about a call that spreads&lt;/strong&gt;, the argument count being a run-time fact.&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;match&lt;/code&gt; is postfix — a transformation of the thing to its left, as in Scala and sysl. It is an
&lt;strong&gt;expression&lt;/strong&gt;, so it stands where a value is wanted:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;what&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    { kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&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;-&amp;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;origin&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    [first, &lt;span class=&quot;hl-keyword&quot;&gt;...&lt;/span&gt;rest] &lt;span class=&quot;hl-keyword&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-string&quot;&gt;a list starting &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(first)
    n &lt;span class=&quot;hl-keyword&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-string&quot;&gt;a negative number&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-keyword&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-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;(&lt;span class=&quot;hl-function&quot;&gt;what&lt;/span&gt;({ kind&lt;span class=&quot;hl-keyword&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;point&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, at&lt;span class=&quot;hl-keyword&quot;&gt;:&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;what&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-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;what&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&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;what&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;origin
a list starting 9
a negative number
something else
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See &lt;a href=&quot;/reference/patterns/&quot;&gt;Patterns&lt;/a&gt; for what an arm may be written with, and for when the arms have to cover
everything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A subject matching no arm is a fault&lt;/strong&gt;, as Scala’s &lt;code&gt;MatchError&lt;/code&gt; is.&lt;/p&gt;
&lt;h2 id=&quot;catch&quot;&gt;&lt;code&gt;catch&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The postfix form of &lt;a href=&quot;/reference/faults/&quot;&gt;fault handling&lt;/a&gt; is an expression too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;toPort&lt;/span&gt;(text)
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;number&lt;/span&gt;(text)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;that is not a port&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    n

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; port &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toPort&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;nonsense&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;message&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;, so using the default&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
    &lt;span class=&quot;hl-number&quot;&gt;8080&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(port)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;that is not a port, so using the default
8080
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;blocks&quot;&gt;Blocks&lt;/h2&gt;
&lt;p&gt;A block’s value is its trailing expression, so a lambda or a definition whose body is several
statements answers the last one. &lt;code&gt;return&lt;/code&gt; is for leaving early and nothing else.&lt;/p&gt;
&lt;p&gt;Every &lt;a href=&quot;/reference/statements/&quot;&gt;loop is an expression too&lt;/a&gt;, and &lt;code&gt;break&lt;/code&gt; is what gives it a value.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Elements</title>
    <link href="https://slatelang.dev/reference/elements/"/>
    <id>https://slatelang.dev/reference/elements/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>&lt;div class=&quot;x&quot;&gt;hi {name}&lt;/div&gt; parses. slate calls it slx, after tsx — the surface is JSX’s, and the mechanism it is meant to serve is React’s.</summary>
    <content type="html">&lt;h1 id=&quot;elements&quot;&gt;Elements&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;div class=&amp;quot;x&amp;quot;&amp;gt;hi {name}&amp;lt;/div&amp;gt;&lt;/code&gt; parses. slate calls it &lt;strong&gt;slx&lt;/strong&gt;, after tsx — the surface is JSX’s, and
the mechanism it is meant to serve is React’s.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Elements are read in every file.&lt;/strong&gt; &lt;code&gt;.slx&lt;/code&gt; is a name for a reader and an editor and says nothing to the
compiler: slate’s &lt;a href=&quot;/reference/types/&quot;&gt;type parameters&lt;/a&gt; are written &lt;code&gt;[T]&lt;/code&gt; and never &lt;code&gt;&amp;lt;T&amp;gt;&lt;/code&gt;, so a &lt;code&gt;&amp;lt;&lt;/code&gt; where an
operand would begin can only be an element — which is the entire reason &lt;code&gt;.tsx&lt;/code&gt; had to be a separate
parse mode from &lt;code&gt;.ts&lt;/code&gt; and slx does not.&lt;/p&gt;
&lt;h2 id=&quot;what-an-element-is&quot;&gt;What an element is&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An element adds nothing to the tree.&lt;/strong&gt; It is desugared in the parser:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;class&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;gt;&lt;/span&gt;hi&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;   →   &lt;span class=&quot;hl-function&quot;&gt;createElement&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, { class&lt;span class=&quot;hl-keyword&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;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;hi&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;So &lt;strong&gt;what an element means is a function a program can read&lt;/strong&gt; rather than a rule inside the compiler.
&lt;code&gt;createElement&lt;/code&gt; and &lt;code&gt;Fragment&lt;/code&gt; come from wherever the program gets them — &lt;code&gt;lath&lt;/code&gt; is one such —
and a file that writes an element and imports neither is refused by the undefined-name check.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { createElement, Fragment, mount, useState } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath
&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { domHost } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; lath&lt;span class=&quot;hl-keyword&quot;&gt;/&lt;/span&gt;dom

&lt;span class=&quot;hl-function&quot;&gt;Counter&lt;/span&gt;({ start &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; }) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; [count, setCount] &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;useState&lt;/span&gt;(start)

    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;class&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;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;{count}&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;onClick&lt;/span&gt;=&lt;span class=&quot;hl-punctuation&quot;&gt;{&lt;/span&gt;() &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;setCount&lt;/span&gt;(count &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;)&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;button&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;mount&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;Counter&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;/&amp;gt;&lt;/span&gt;, &lt;span class=&quot;hl-function&quot;&gt;domHost&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;#app&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;))&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-rules&quot;&gt;The rules&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;&lt;/code&gt; in prefix position begins nothing else&lt;/strong&gt;, which is the whole of the ambiguity: &lt;code&gt;&amp;lt;&lt;/code&gt; is otherwise
always an infix operator, so where an operand is expected it can only be a tag. The byte after the &lt;code&gt;&amp;lt;&lt;/code&gt; is
checked too, so &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;lt;=&lt;/code&gt; are never mistaken for a tag with a strange name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A lowercase tag is a host element and travels as the string &lt;code&gt;&amp;quot;div&amp;quot;&lt;/code&gt;; a capitalised one is a name in
scope.&lt;/strong&gt; React’s rule, kept because it is learned behaviour costing no syntax.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;class&lt;/code&gt;, not &lt;code&gt;className&lt;/code&gt;; &lt;code&gt;for&lt;/code&gt;, not &lt;code&gt;htmlFor&lt;/code&gt;.&lt;/strong&gt; React’s spellings exist only because JSX compiles into
a JavaScript object literal where those were reserved words. An attribute here is its own lexical context
and can take the right name.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A bare attribute is &lt;code&gt;true&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;&amp;lt;input disabled&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An attribute’s value is a quoted string or a &lt;code&gt;{ … }&lt;/code&gt;, and a bare word is refused.&lt;/strong&gt; &lt;code&gt;class=wide&lt;/code&gt; would
be a variable in every other position and a string to everyone who writes it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;{...props}&lt;/code&gt; is the spread an object literal already takes&lt;/strong&gt;, folded into the same &lt;code&gt;with&lt;/code&gt;, so an
attribute written after a spread wins over it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A hyphen is part of a name inside a tag and a subtraction outside one&lt;/strong&gt; — &lt;code&gt;data-id&lt;/code&gt;, &lt;code&gt;aria-label&lt;/code&gt;,
&lt;code&gt;&amp;lt;my-widget&amp;gt;&lt;/code&gt;. A dot stays a token, so &lt;code&gt;&amp;lt;Menu.Item&amp;gt;&lt;/code&gt; is an ordinary field selection.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Whitespace inside a tag is skipped whole, newlines included&lt;/strong&gt;, since a tag with an attribute per line is
the ordinary way to write one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A mismatched closing tag names both names&lt;/strong&gt;, either one being possibly the mistake.&lt;/p&gt;
&lt;h2 id=&quot;the-children&quot;&gt;The children&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The children travel as one array, not as trailing arguments.&lt;/strong&gt; React spells its own
&lt;code&gt;createElement(type, props, ...children)&lt;/code&gt;; an array is the better answer anyway, being what
&lt;code&gt;props.children&lt;/code&gt; holds in the end, so a component passing its children on writes them as the value they
already are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The whitespace rule is JSX’s.&lt;/strong&gt; A run of text holding no line break is kept exactly as written — the
space in &lt;code&gt;&amp;lt;h1&amp;gt;Count: {n}&amp;lt;/h1&amp;gt;&lt;/code&gt; is one the reader meant. A run that spans lines is trimmed per line, blank
lines dropped, the rest joined with one space, because it is mostly the indentation that lined it up
under its tag. Any other rule makes an indented element read differently from the same element on one
line.&lt;/p&gt;
&lt;h2 id=&quot;inside-an-element&quot;&gt;Inside an element&lt;/h2&gt;
&lt;p&gt;Between a tag’s &lt;code&gt;&amp;gt;&lt;/code&gt; and the &lt;code&gt;&amp;lt;&lt;/code&gt; that ends it, a space is a character, &lt;code&gt;//&lt;/code&gt; is not a comment and a newline
is not a line ending.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;{&lt;/code&gt; inside an element opens a hole&lt;/strong&gt;, and a &lt;code&gt;{&lt;/code&gt; inside that hole is an ordinary brace — so the &lt;code&gt;}&lt;/code&gt; of
an object literal written in a hole is not taken for the one closing the hole.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An element opens a layout bracket at its &lt;code&gt;&amp;lt;&lt;/code&gt; and closes it at its end&lt;/strong&gt;, which is what lets a tag be
written across lines with its children indented under it. It is the same mechanism &lt;code&gt;(&lt;/code&gt; uses, so an &lt;code&gt;-&amp;gt;&lt;/code&gt;
written inside a hole still opens a block and a callback can be written where it is passed.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:dom</title>
    <link href="https://slatelang.dev/library/dom/"/>
    <id>https://slatelang.dev/library/dom/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>The document. The one module that works in one host out of three — it is real only in a browser, reached through slate js.</summary>
    <content type="html">&lt;h1 id=&quot;slatedom&quot;&gt;&lt;code&gt;slate:dom&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;The document. &lt;strong&gt;The one module that works in one host out of three&lt;/strong&gt; — it is real only in a browser,
reached through &lt;a href=&quot;/reference/javascript/&quot;&gt;&lt;code&gt;slate js&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { byId, setText, on } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:dom&lt;/code&gt;&lt;/pre&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;createElement(tag)&lt;/code&gt;, &lt;code&gt;createText(s)&lt;/code&gt;, &lt;code&gt;createComment(s)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;setAttribute&lt;/code&gt;, &lt;code&gt;removeAttribute&lt;/code&gt;, &lt;code&gt;setProperty&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;on(node, event, fn)&lt;/code&gt;, &lt;code&gt;off(node, id)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;setChildren(node, kids)&lt;/code&gt;, &lt;code&gt;setText(node, s)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;insertBefore(parent, node, before)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one child, in front of another; &lt;code&gt;null&lt;/code&gt; appends&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;removeChild(parent, node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one child, out&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;byId(id)&lt;/code&gt;, &lt;code&gt;query(selector)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;children(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the child nodes, as handles, in order&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;tagName(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the tag in lower case, or &lt;code&gt;null&lt;/code&gt; for a text node&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;nodeText(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;what the node says, as text&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;attribute(node, name)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one attribute, or &lt;code&gt;null&lt;/code&gt; where there is none&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;nodeKind(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;&amp;quot;element&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;text&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;comment&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;fragment&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;document&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;other&amp;quot;&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;property(node, name)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;what the node HOLDS, or &lt;code&gt;null&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;splitText(node, at)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;cut a text node in two; answers the tail&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;markup(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;release(node)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;give a handle back&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;dispatch(node, event)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;send an event; answers whether nothing cancelled it&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;observe(node, options, fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;be told what changed; answers &lt;code&gt;{ disconnect }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;events(url, options)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;read a server’s event stream; answers &lt;code&gt;{ close }&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;location()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;where the page is, as a record&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pushPath(url)&lt;/code&gt;, &lt;code&gt;replacePath(url)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;move the address bar without a reload&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;back()&lt;/code&gt;, &lt;code&gt;forward()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;move through what the page has visited&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;onNavigate(fn)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the user moved — &lt;strong&gt;not&lt;/strong&gt; a push the program made&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;stored(key)&lt;/code&gt;, &lt;code&gt;store(key, v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;localStorage&lt;/code&gt;, as results&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;unstore(key)&lt;/code&gt;, &lt;code&gt;storedKeys()&lt;/code&gt;, &lt;code&gt;clearStored()&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;&lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt; rather than &lt;code&gt;addEventListener&lt;/code&gt;&lt;/strong&gt;, and &lt;code&gt;byId&lt;/code&gt; rather than &lt;code&gt;getElementById&lt;/code&gt;. The DOM’s names
are long because JavaScript had no modules when they were chosen; these are reached through an import that
already says &lt;code&gt;dom&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reading-a-page-somebody-else-rendered&quot;&gt;Reading a page somebody else rendered&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;children&lt;/code&gt;, &lt;code&gt;tagName&lt;/code&gt;, &lt;code&gt;nodeText&lt;/code&gt; and &lt;code&gt;attribute&lt;/code&gt; are what hydration walks with&lt;/strong&gt;, and three more
are what it walks with once the markup came from a server rather than from the same program.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;nodeKind(node)&lt;/code&gt; tells a comment from a text node&lt;/strong&gt;, which &lt;code&gt;tagName&lt;/code&gt; calls &lt;code&gt;null&lt;/code&gt; alike — so a
reconciler counting children read a comment as a piece of text and adopted the wrong node from there
on. It is asked outright rather than by widening what &lt;code&gt;tagName&lt;/code&gt; answers: a program reading &lt;code&gt;null&lt;/code&gt; as
&lt;em&gt;not an element&lt;/em&gt; is right and stays right.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;property(node, name)&lt;/code&gt; is what the node HOLDS, where &lt;code&gt;attribute&lt;/code&gt; is what its markup said.&lt;/strong&gt; They are
the pair a form turns on: setting the &lt;code&gt;value&lt;/code&gt; attribute says what a field started as and setting the
property says what is in it now, so a re-render comparing what it would set against what is there has
to read the property. Only a value slate can hold comes back — a string, a boolean or a number — and
anything else answers &lt;code&gt;null&lt;/code&gt;, exactly as a name the node does not carry does.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;setAttribute&lt;/span&gt;(field, &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;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;written&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;setProperty&lt;/span&gt;(field, &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;, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;typed&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;attribute&lt;/span&gt;(field, &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;), &lt;span class=&quot;hl-function&quot;&gt;property&lt;/span&gt;(field, &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;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;splitText(node, at)&lt;/code&gt; cuts one text node in two and answers a handle for the tail.&lt;/strong&gt; A component
rendering &lt;code&gt;{a}{b}&lt;/code&gt; writes two text nodes and a server’s markup carries the one string they made, so a
hydrating reconciler that cannot split has to throw the text away and rebuild it. &lt;strong&gt;The offset is in
characters&lt;/strong&gt;, which is slate’s rule wherever a string is measured and is not the DOM’s — &lt;code&gt;splitText&lt;/code&gt;
counts UTF-16 units there, so a cut written after an emoji would land inside one.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;createComment(s)&lt;/code&gt; is the other half of &lt;code&gt;nodeKind&lt;/code&gt;: a comment is what a server writes to mark a place
a component’s output begins, and a page could read one and not write one.&lt;/p&gt;
&lt;h2 id=&quot;sending-an-event-and-watching-for-a-change&quot;&gt;Sending an event, and watching for a change&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;dispatch(node, event)&lt;/code&gt; sends what &lt;code&gt;on&lt;/code&gt; reads&lt;/strong&gt;, which is the whole of why its shape is the event
record’s fields and not the DOM’s constructors: &lt;code&gt;type&lt;/code&gt;, and optionally &lt;code&gt;key&lt;/code&gt;, &lt;code&gt;button&lt;/code&gt;, &lt;code&gt;mods&lt;/code&gt;,
&lt;code&gt;bubbles&lt;/code&gt; and &lt;code&gt;cancelable&lt;/code&gt;. A string is the ordinary spelling.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;dispatch&lt;/span&gt;(button, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;dispatch&lt;/span&gt;(button, { type&lt;span class=&quot;hl-keyword&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;click&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, button&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, mods&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; { meta&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt; } })
&lt;span class=&quot;hl-function&quot;&gt;dispatch&lt;/span&gt;(field, { type&lt;span class=&quot;hl-keyword&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;keydown&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, key&lt;span class=&quot;hl-keyword&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;Enter&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;It answers &lt;code&gt;true&lt;/code&gt; where nothing cancelled the event, which is what the DOM’s own &lt;code&gt;dispatchEvent&lt;/code&gt;
answers and is all a sender can learn. &lt;strong&gt;The event’s class is chosen from its name&lt;/strong&gt; — a &lt;code&gt;click&lt;/code&gt; is
a &lt;code&gt;MouseEvent&lt;/code&gt; and a &lt;code&gt;keydown&lt;/code&gt; a &lt;code&gt;KeyboardEvent&lt;/code&gt; — because a handler reading &lt;code&gt;e.button&lt;/code&gt; off a plain
&lt;code&gt;Event&lt;/code&gt; gets &lt;code&gt;null&lt;/code&gt;, and a router telling a left click from a middle one would let every dispatched
click through to the browser.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;observe(node, options, fn)&lt;/code&gt; is a &lt;code&gt;MutationObserver&lt;/code&gt;&lt;/strong&gt;, and it answers an object whose
&lt;code&gt;disconnect&lt;/code&gt; is the one thing that stops it. The options are &lt;code&gt;children&lt;/code&gt;, &lt;code&gt;attributes&lt;/code&gt;, &lt;code&gt;text&lt;/code&gt; and
&lt;code&gt;subtree&lt;/code&gt;, and at least one of the first three has to be asked for.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; watcher &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;observe&lt;/span&gt;(list, { children&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, subtree&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt; }, (records) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;redraw&lt;/span&gt;(records))

watcher&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;disconnect&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A record carries no nodes&lt;/strong&gt;, which is the decision an event record already makes: a handle is a
table slot the program has to give back, and a re-render makes hundreds of records. What a record
says is &lt;code&gt;type&lt;/code&gt; (&lt;code&gt;&amp;quot;children&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;attributes&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;text&amp;quot;&lt;/code&gt;), &lt;code&gt;attribute&lt;/code&gt; (the name, or &lt;code&gt;null&lt;/code&gt;), and
&lt;code&gt;added&lt;/code&gt; and &lt;code&gt;removed&lt;/code&gt; as counts. A program that needs the nodes asks the page with &lt;code&gt;children&lt;/code&gt; or
&lt;code&gt;query&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;reading-a-servers-event-stream&quot;&gt;Reading a server’s event stream&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;events(url, options)&lt;/code&gt; is the reading end of &lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt;‘s &lt;code&gt;sse&lt;/code&gt;&lt;/strong&gt;, which slate could
write and had no way at all to consume. It answers an object whose &lt;code&gt;close&lt;/code&gt; ends the subscription.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; feed &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;events&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/updates&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;, {
    onMessage&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; (m) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;apply&lt;/span&gt;(m&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;data),
    onError&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; (e) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;closed &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;warn&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 stream is over&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;) })

feed&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;close&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A message is &lt;code&gt;{ data, lastEventId, type }&lt;/code&gt;. An error record says only &lt;code&gt;closed&lt;/code&gt;: an &lt;code&gt;EventSource&lt;/code&gt;
reconnects by itself, so nearly every error a page sees is a retry in progress, and a program that
stopped on those would stop on a hiccup.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;lastEventId&lt;/code&gt; is refused rather than ignored.&lt;/strong&gt; A browser’s &lt;code&gt;EventSource&lt;/code&gt; sends the last id it
saw on its own reconnections and gives a page no way to set one on the first request — so taking the
option and dropping it would be a program that believed it had resumed and had not. What a program
resuming after a reload does instead is keep the &lt;code&gt;lastEventId&lt;/code&gt; it read off each message and ask the
server for what it missed.&lt;/p&gt;
&lt;h2 id=&quot;a-node-is-a-slate-integer&quot;&gt;A node is a slate integer&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;That is the decision everything else follows from.&lt;/strong&gt; The engine keeps the elements in a table and hands
out the index, so &lt;strong&gt;no foreign object ever becomes a slate value&lt;/strong&gt;: &lt;code&gt;==&lt;/code&gt; compares what slate says it
compares, &lt;code&gt;print&lt;/code&gt; has something to say, a node travels through an array or a pattern like any other value,
and the checker learns nothing new. It is the arrangement the timers already use.&lt;/p&gt;
&lt;p&gt;The cost is that &lt;strong&gt;a handle is held until &lt;code&gt;release&lt;/code&gt; gives it back&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;an-event-arrives-as-a-slate-object&quot;&gt;An event arrives as a slate object&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;{ type, value, checked, key, mods, button, stop, prevent }&lt;/code&gt;, built when the handler fires. A &lt;code&gt;MouseEvent&lt;/code&gt;
has no representation in slate, and inventing one would mean inventing a value that could not be printed,
compared or stored.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;mods&lt;/code&gt; is &lt;code&gt;{ meta, ctrl, shift, alt }&lt;/code&gt; and &lt;code&gt;button&lt;/code&gt; is an integer or &lt;code&gt;null&lt;/code&gt;&lt;/strong&gt; — &lt;code&gt;0&lt;/code&gt; for the left button,
&lt;code&gt;1&lt;/code&gt; for the middle, &lt;code&gt;2&lt;/code&gt; for the right, and &lt;code&gt;null&lt;/code&gt; for every event that is not a mouse event. They are here
because &lt;strong&gt;a link cannot be written without them&lt;/strong&gt;: a framework that intercepts a click has to let a
cmd-click, a ctrl-click, a shift-click and a middle click through to the browser, or it swallows the most
ordinary thing anybody does to a link.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;value&lt;/code&gt; and &lt;code&gt;checked&lt;/code&gt; are set as properties and not attributes&lt;/strong&gt;, and an input is where the difference
shows: the attribute says what the field started as and the property says what it holds now, so a re-render
that set the attribute would leave a typed-in field alone and the page would appear frozen.&lt;/p&gt;
&lt;h2 id=&quot;reading-a-page-that-is-already-there&quot;&gt;Reading a page that is already there&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Four of the names above read rather than write, and they exist because hydration needs exactly
them.&lt;/strong&gt; Everything else either makes a node or changes one; a program adopting markup a server
rendered has to walk what is there and ask what it found.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { byId, children, tagName, nodeText, attribute } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:dom

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; app &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;byId&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;app&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; kid &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;children&lt;/span&gt;(app)
    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;tagName&lt;/span&gt;(kid) &lt;span class=&quot;hl-keyword&quot;&gt;==&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-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-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;nodeText&lt;/span&gt;(kid))
    &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;&amp;lt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;tagName&lt;/span&gt;(kid) &lt;span class=&quot;hl-keyword&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;&amp;gt; class=&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;string&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;attribute&lt;/span&gt;(kid, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)))&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;children&lt;/code&gt; answers EVERY child node and not only the elements&lt;/strong&gt;, because a text node between two
elements is a position: a reconciler counting children has to count what the browser counts, or it
adopts the wrong node. &lt;code&gt;tagName&lt;/code&gt; answering &lt;code&gt;null&lt;/code&gt; is how the two are told apart.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;tagName&lt;/code&gt; is lower case&lt;/strong&gt;, because that is what a program wrote — the DOM answers &lt;code&gt;DIV&lt;/code&gt; for HTML.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;attribute&lt;/code&gt; answers &lt;code&gt;true&lt;/code&gt; for a bare attribute&lt;/strong&gt;, which is the reading &lt;code&gt;setAttribute&lt;/code&gt; writes: it
puts the empty string for &lt;code&gt;true&lt;/code&gt;, so a program comparing what it would set against what is there
gets the same value back.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A handle from &lt;code&gt;children&lt;/code&gt; is released like any other, and &lt;code&gt;release&lt;/code&gt; gives back the HANDLE and not
the node.&lt;/strong&gt; The element stays exactly where it is in the page. That reads oddly the first time and
is the rule handles have always followed: &lt;code&gt;byId&lt;/code&gt; and &lt;code&gt;query&lt;/code&gt; have minted one for an element the
program never created since this module shipped.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;parent&lt;/code&gt;, the siblings and an &lt;code&gt;innerHTML&lt;/code&gt; reader are deliberately absent.&lt;/strong&gt; A page is walked
downwards from something the program already holds; the rest is a general traversal API, which is a
different thing to want and a much larger one.&lt;/p&gt;
&lt;h2 id=&quot;where-the-page-is-where-it-has-been-and-what-it-remembers&quot;&gt;Where the page is, where it has been, and what it remembers&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A browser has &lt;code&gt;location&lt;/code&gt;, &lt;code&gt;history&lt;/code&gt; and &lt;code&gt;localStorage&lt;/code&gt;, and nothing else does&lt;/strong&gt; — there is no address
bar in an interpreter and no per-origin store on a server. So these refuse everywhere else, naming
&lt;em&gt;which&lt;/em&gt; of the three is missing rather than saying something about the document. That is the same rule
&lt;code&gt;slate:time&lt;/code&gt;‘s &lt;code&gt;abbrev&lt;/code&gt; follows, read from the other side.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { location, pushPath, onNavigate, stored, store } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:dom

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; here &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;location&lt;/span&gt;()          &lt;span class=&quot;hl-comment&quot;&gt;// { href, protocol, host, hostname, port, path, query, hash }&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;show&lt;/span&gt;(path) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;render&lt;/span&gt;(path)

&lt;span class=&quot;hl-function&quot;&gt;onNavigate&lt;/span&gt;(show)               &lt;span class=&quot;hl-comment&quot;&gt;// the user pressed back, or forward&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;pushPath&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;/notes/7&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)           &lt;span class=&quot;hl-comment&quot;&gt;// the address bar moves; onNavigate does NOT fire&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;/notes/7&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)               &lt;span class=&quot;hl-comment&quot;&gt;// so a router renders after its own push&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;store&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;theme&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;dark&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;stored&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;theme&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)   &lt;span class=&quot;hl-comment&quot;&gt;// &amp;quot;dark&amp;quot;, or null when nothing is stored&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;query&lt;/code&gt; and &lt;code&gt;hash&lt;/code&gt; carry their punctuation&lt;/strong&gt; — &lt;code&gt;&amp;quot;?a=1&amp;quot;&lt;/code&gt; and &lt;code&gt;&amp;quot;#top&amp;quot;&lt;/code&gt; — which is what a program pasting
one back into a url needs. An empty one is &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; and never null.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A push does not raise &lt;code&gt;onNavigate&lt;/code&gt;.&lt;/strong&gt; A browser raises it for a movement the &lt;em&gt;user&lt;/em&gt; made and never for
one the program made itself, so a router renders after its own push and waits to be told about everything
else. Getting this wrong is how a router renders twice.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There is no state object, and that is a measurement.&lt;/strong&gt; &lt;code&gt;pushState&lt;/code&gt; structured-clones what it is given
and &lt;code&gt;structuredClone&lt;/code&gt; strips the prototype, so a slate object put in comes back a plain object nothing in
the language could read. The url is the whole of the state — which is also what keeps a router’s two
sources of truth from disagreeing after a &lt;code&gt;back&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The store answers results&lt;/strong&gt;, which is &lt;a href=&quot;/library/fs/&quot;&gt;&lt;code&gt;readFileSync&lt;/code&gt;&lt;/a&gt;‘s channel and its reason: what comes back
was written by somebody else — another tab, an earlier visit, a user who cleared it. A key that is not
there is &lt;code&gt;{ ok: true, value: null }&lt;/code&gt; and not a failure; a browser told to keep no data is
&lt;code&gt;{ ok: false, error }&lt;/code&gt;. A value that is not a string is stored as slate prints it, a store holding nothing
else.&lt;/p&gt;
&lt;h2 id=&quot;under-the-interpreter&quot;&gt;Under the interpreter&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Every name faults, and the module still exists.&lt;/strong&gt; Leaving it out would make &lt;code&gt;import { byId } from slate:dom&lt;/code&gt; a complaint about the &lt;em&gt;module&lt;/em&gt;, which sends a reader looking for a spelling mistake in the one
line that is right. The refusal instead names the &lt;strong&gt;command&lt;/strong&gt;, because the command is the mistake — the
same program is correct in a browser.&lt;/p&gt;
&lt;h2 id=&quot;the-framework&quot;&gt;The framework&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;slate:dom&lt;/code&gt; is the seam, not the framework. &lt;code&gt;lath&lt;/code&gt; is React’s model &lt;em&gt;and&lt;/em&gt; React’s mechanism, written in
slate over &lt;a href=&quot;/reference/elements/&quot;&gt;elements&lt;/a&gt;, with this module as one of its two hosts — the other
rendering to markup beside &lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt;, so server-side rendering is a by-product rather than a
project.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ slate add github.com/slate-language/lath
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It is a package rather than part of the language, and deliberately so&lt;/strong&gt;: a UI framework iterates far
faster than a compiler, and baking one in would tie every framework fix to a language release.&lt;/p&gt;
&lt;h2 id=&quot;moving-one-child&quot;&gt;Moving one child&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;setChildren&lt;/code&gt; writes the whole list and the two beside it move one node.&lt;/strong&gt; Both spellings are here
because they cost different things: replacing a list is what makes a re-render idempotent, and it is
what a browser records a mutation for per child — a keyed reconciler moving three rows of a thousand
should not make the page do a thousand pieces of work.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;insertBefore&lt;/span&gt;(list, row, list&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;children&lt;/span&gt;()[&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;])
&lt;span class=&quot;hl-function&quot;&gt;insertBefore&lt;/span&gt;(list, row, &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt;)
&lt;span class=&quot;hl-function&quot;&gt;removeChild&lt;/span&gt;(list, row)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;before&lt;/code&gt; of &lt;code&gt;null&lt;/code&gt; appends&lt;/strong&gt;, which is &lt;code&gt;Node.insertBefore&lt;/code&gt;‘s own rule and is what makes the last
position no more work than any other. &lt;strong&gt;A node already in the page MOVES rather than being copied&lt;/strong&gt;,
so it keeps its focus, its scroll position and whatever it was playing. &lt;strong&gt;The parent is named for the
removal too&lt;/strong&gt;, where a browser needs only the child: a reconciler holds both, and naming the parent
is what turns “that node is somewhere else entirely” from a silent success into a sentence.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Data types</title>
    <link href="https://slatelang.dev/reference/data-types/"/>
    <id>https://slatelang.dev/reference/data-types/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>data declares a closed set of variants — an algebraic data type — and that closed set is what makes a match over one worth checking.</summary>
    <content type="html">&lt;h1 id=&quot;data-types&quot;&gt;Data types&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt; declares a closed set of variants — an algebraic data type — and that closed set is what makes a
&lt;code&gt;match&lt;/code&gt; over one worth checking.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;data&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-function&quot;&gt;Rect&lt;/span&gt;(w, h)
    Empty

    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; self &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) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; r &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; r
        &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(w, h) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; w &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; h
        Empty &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;), &lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;())
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Empty, Empty&lt;span class=&quot;hl-keyword&quot;&gt;.&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;Circle(3) 27
Empty 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A variant is a &lt;a href=&quot;/reference/classes/&quot;&gt;class&lt;/a&gt; from the data type&lt;/strong&gt;, which is the whole of the implementation:
&lt;code&gt;is Shape&lt;/code&gt;, an annotation, &lt;code&gt;export&lt;/code&gt;, a cross-file import and a method on the shared body are all
machinery &lt;code&gt;class&lt;/code&gt; already had. &lt;code&gt;Circle(3)&lt;/code&gt; is the generated constructor, reached by the rule that
calling an object calls its &lt;code&gt;new&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A variant that declares no fields is a value rather than a maker.&lt;/strong&gt; &lt;code&gt;Empty&lt;/code&gt; is the value, not
&lt;code&gt;Empty()&lt;/code&gt;, and the test for it is identity.&lt;/p&gt;
&lt;h2 id=&quot;a-data-value-does-not-change&quot;&gt;A data value does not change&lt;/h2&gt;
&lt;p&gt;A write to one of its fields is refused, and &lt;code&gt;v with { r: 4 }&lt;/code&gt; answers a new one that differs there. Two
equal ones are equal and hash alike, so &lt;strong&gt;a data value is an ordinary table key&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;data&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-keyword&quot;&gt;val&lt;/span&gt; c &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Circle&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;(c &lt;span class=&quot;hl-keyword&quot;&gt;with&lt;/span&gt; { r&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt; }, c)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&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;Circle(4) Circle(3)
true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;exhaustive-match&quot;&gt;Exhaustive &lt;code&gt;match&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;match&lt;/code&gt; over an annotated subject must cover every variant&lt;/strong&gt;, and the complaint names each one left
out:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;data&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-function&quot;&gt;Rect&lt;/span&gt;(w, h)
    Empty

&lt;span class=&quot;hl-function&quot;&gt;sides&lt;/span&gt;(s&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Shape) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;, &lt;span class=&quot;hl-variable&quot;&gt;_&lt;/span&gt;) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;
    Empty &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;sides&lt;/span&gt;(&lt;span class=&quot;hl-function&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;sides&lt;/span&gt;(&lt;span class=&quot;hl-function&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;sides&lt;/span&gt;(Empty))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;0 4 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is checked exactly where the shape was written down — an unannotated subject is said nothing about —
and a &lt;code&gt;_&lt;/code&gt; arm is how a program says it has finished listing.&lt;/p&gt;
&lt;h2 id=&quot;patterns&quot;&gt;Patterns&lt;/h2&gt;
&lt;p&gt;Variants take the same two forms a class does — &lt;code&gt;Circle(r)&lt;/code&gt; by position, &lt;code&gt;Circle { r }&lt;/code&gt; by name — and a
field name the variant does not carry is refused where it is written. See &lt;a href=&quot;/reference/patterns/&quot;&gt;Patterns&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The data name and each variant name are shape values&lt;/strong&gt;, so &lt;code&gt;Figure.test(v)&lt;/code&gt; asks whether &lt;code&gt;v&lt;/code&gt; was made
by one of the variants and &lt;code&gt;Circle.test(v)&lt;/code&gt; asks about that one — the run-time form of the &lt;code&gt;is&lt;/code&gt; above.
&lt;code&gt;mismatch&lt;/code&gt; and &lt;code&gt;name&lt;/code&gt; come with them; see
&lt;a href=&quot;/reference/types/#a-type-is-a-value-under-its-own-name&quot;&gt;Types&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;encoding&quot;&gt;Encoding&lt;/h2&gt;
&lt;p&gt;Without a &lt;code&gt;toJSON&lt;/code&gt;, a variant encodes as its own fields: &lt;code&gt;Circle(3)&lt;/code&gt; is &lt;code&gt;{&amp;quot;r&amp;quot;:3}&lt;/code&gt;, never the chain it
hangs from. A &lt;code&gt;toJSON(self)&lt;/code&gt; on the shared body says otherwise — see &lt;a href=&quot;/reference/objects/&quot;&gt;Objects&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:crypto</title>
    <link href="https://slatelang.dev/library/crypto/"/>
    <id>https://slatelang.dev/library/crypto/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>Digests, HMAC, key derivation and randomness.</summary>
    <content type="html">&lt;h1 id=&quot;slatecrypto&quot;&gt;&lt;code&gt;slate:crypto&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;Digests, HMAC, key derivation and randomness.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { sha256, hmac, randomBytes, timingSafeEqual } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:crypto

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; nonce &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;randomBytes&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;18&lt;/span&gt;)
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; tag &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;hmac&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SHA-256&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 key&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 message&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;len&lt;/span&gt;(nonce), &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;sha256&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-function&quot;&gt;len&lt;/span&gt;(tag))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;timingSafeEqual&lt;/span&gt;(tag, &lt;span class=&quot;hl-function&quot;&gt;hmac&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SHA-256&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 key&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 message&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;timingSafeEqual&lt;/span&gt;(tag, &lt;span class=&quot;hl-function&quot;&gt;hmac&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;SHA-256&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 key&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;another message&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;18 32 32
true
false
&lt;/code&gt;&lt;/pre&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;md5  sha1  sha256  sha384  sha512&lt;/code&gt;&lt;/td&gt;&lt;td&gt;text or bytes in, the digest as bytes out&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hmac(name, key, message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pbkdf2(name, password, salt, rounds, length)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;randomBytes(n)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;from the operating system&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;timingSafeEqual(a, b)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;argon2(password)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of a PHC record — Argon2id, 19 MiB, two passes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;argon2Verify(record, attempt)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise of &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;argon2NeedsRehash(record)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, at once&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;hmac&lt;/code&gt; takes the digest by name&lt;/strong&gt; — &lt;code&gt;&amp;quot;MD5&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;SHA-1&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;SHA-256&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;SHA-384&amp;quot;&lt;/code&gt;, &lt;code&gt;&amp;quot;SHA-512&amp;quot;&lt;/code&gt; — because
what a program is speaking to decides it, and a default here would be a decision taken by whoever wrote the
module rather than by the protocol. &lt;strong&gt;&lt;code&gt;pbkdf2&lt;/code&gt; takes the same names without &lt;code&gt;&amp;quot;MD5&amp;quot;&lt;/code&gt;&lt;/strong&gt;: every other name
here reads a protocol somebody else chose, and deriving a key is the one thing a program chooses for
itself.&lt;/p&gt;
&lt;h2 id=&quot;why-the-module-exists&quot;&gt;Why the module exists&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A package cannot have a native.&lt;/strong&gt; &lt;a href=&quot;/library/jwt/&quot;&gt;&lt;code&gt;slate:jwt&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;/library/ws/&quot;&gt;&lt;code&gt;slate:ws&lt;/code&gt;&lt;/a&gt; are carried in the binary
and are compiled against the scope the natives live in; a package installed with &lt;code&gt;slate add&lt;/code&gt; is not — so
one speaking a protocol with a challenge in it (SCRAM, SASL, a signed webhook, a request signed for S3) had
no digest at all and no source of unpredictability at all. &lt;strong&gt;A nonce a program worked out from the clock is
not a nonce&lt;/strong&gt;, and that half cannot be written in slate at any price.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What a program can write, it writes.&lt;/strong&gt; Hex, base64 and the message layout of whatever protocol is being
spoken are ordinary slate, so they are not here. What is here is the compression functions and the kernel.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;pbkdf2&lt;/code&gt; is here for a reason that is not tidiness&lt;/strong&gt;: one SCRAM handshake is 4,096 HMACs, which is some
eight thousand SHA-256 compressions — a millisecond as a native and seconds in the interpreter.&lt;/p&gt;
&lt;h2 id=&quot;timingsafeequal&quot;&gt;&lt;code&gt;timingSafeEqual&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;What a program checks a tag it was sent with.&lt;/strong&gt; &lt;code&gt;==&lt;/code&gt; on two byte arrays stops at the first byte that
differs, which tells an attacker how much of a forged tag was right, and a tag can be guessed a byte at a
time from that.&lt;/p&gt;
&lt;h2 id=&quot;md5-and-sha1&quot;&gt;&lt;code&gt;md5&lt;/code&gt; and &lt;code&gt;sha1&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Both are exported and neither is an endorsement.&lt;/strong&gt; Each is what an existing protocol asks for — a
WebSocket handshake, a Git object, an old server’s SASL, PostgreSQL’s &lt;code&gt;md5&lt;/code&gt; login, HTTP Digest, an S3
&lt;code&gt;ETag&lt;/code&gt; — and a program speaking one has no say in the matter. Nothing new should be signed with either, and
no content address may be one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For a password, none of these is the answer.&lt;/strong&gt; &lt;code&gt;argon2&lt;/code&gt; below is deliberately slow, which is the whole
difference — and it is why there is no &lt;code&gt;hash&lt;/code&gt; in this module. Every name here says which algorithm it is, so
a reader checking a login path by eye can see that the slow one was used.&lt;/p&gt;
&lt;h2 id=&quot;argon2--the-one-hash-here-meant-to-be-slow&quot;&gt;&lt;code&gt;argon2&lt;/code&gt; — the one hash here meant to be slow&lt;/h2&gt;
&lt;p&gt;Argon2id, in the PHC format every other Argon2 implementation reads.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { argon2, argon2Verify, argon2NeedsRehash } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:crypto

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; stored &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;argon2&lt;/span&gt;(&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;correct horse&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;startsWith&lt;/span&gt;(stored, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;$argon2id$v=19$m=19456,t=2,p=1$&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;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;argon2Verify&lt;/span&gt;(stored, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;correct horse&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;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;argon2Verify&lt;/span&gt;(stored, &lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt;wrong&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;argon2NeedsRehash&lt;/span&gt;(stored))

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true
false
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;A password is the one thing a server stores that must be expensive to check.&lt;/strong&gt; Everything else in this
module wants to be fast, and for a password that is the whole vulnerability: a stolen table of fast hashes
is tried at billions of guesses a second on a graphics card. Argon2 is slow &lt;em&gt;and&lt;/em&gt; memory-hungry, so the
card’s thousands of cores cannot each hold a copy of the working state. The memory is the lever that
matters, and it is why a default call reserves 19 MiB.&lt;/p&gt;
&lt;p&gt;The salt is a fresh sixteen bytes from the operating system per call, so hashing one password twice gives
two different records and both verify.&lt;/p&gt;
&lt;h3 id=&quot;the-parameters-and-where-the-heavier-profile-went&quot;&gt;The parameters, and where the heavier profile went&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;argon2&lt;/code&gt; and &lt;code&gt;argon2NeedsRehash&lt;/code&gt; each take an optional record of parameters:&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;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;memoryCost&lt;/code&gt;&lt;/td&gt;&lt;td&gt;19456&lt;/td&gt;&lt;td&gt;kibibyte blocks — 19 MiB&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;timeCost&lt;/code&gt;&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;passes over that memory&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;parallelism&lt;/code&gt;&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;lanes&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;hashLength&lt;/code&gt;&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;td&gt;bytes of tag&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;salt&lt;/code&gt;&lt;/td&gt;&lt;td&gt;the kernel’s&lt;/td&gt;&lt;td&gt;text or bytes, 8 to 32 of them&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The defaults are OWASP’s first recommendation for a login. &lt;strong&gt;64 MiB and three passes — for something
hashed rarely and worth more than a session, a key-encrypting key or a recovery code — is
&lt;code&gt;argon2(secret, { memoryCost: 65536, timeCost: 3 })&lt;/code&gt;&lt;/strong&gt; rather than a second name: once the numbers are
parameters at all, a name for one particular pair of them is a second way to say the same thing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A &lt;code&gt;salt&lt;/code&gt; you give is a footgun, and it is accepted anyway&lt;/strong&gt; because a published test vector and a record
being reproduced from another implementation both need it. A program that passes a constant has given up
the only thing a salt is for: one precomputed table would then break every account at once.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An unknown key is refused rather than ignored.&lt;/strong&gt; &lt;code&gt;{ memoryCosts: 65536 }&lt;/code&gt; would otherwise be a login
that was thought to have been strengthened and was not.&lt;/p&gt;
&lt;h3 id=&quot;the-parameters-travel-inside-the-record&quot;&gt;The parameters travel inside the record&lt;/h3&gt;
&lt;p&gt;So raising what a program asks for invalidates nothing: existing records keep verifying, because
&lt;code&gt;argon2Verify&lt;/code&gt; uses the parameters the password was hashed &lt;em&gt;with&lt;/em&gt;. &lt;code&gt;argon2NeedsRehash&lt;/code&gt; says which records
are below what is written today — ask it after a successful verify, while the plaintext is still in hand,
and re-hash the ones that answer &lt;code&gt;true&lt;/code&gt;. That is the whole upgrade path.&lt;/p&gt;
&lt;p&gt;Where a program hashes with something other than the defaults, tell &lt;code&gt;argon2NeedsRehash&lt;/code&gt; so:
&lt;code&gt;argon2NeedsRehash(stored, { memoryCost: 65536, timeCost: 3 })&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-derivation-runs-on-a-thread-which-is-why-two-of-these-are-promises&quot;&gt;The derivation runs on a thread, which is why two of these are promises&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Hashing a password is supposed to take a tenth of a second, and a loop is one thread.&lt;/strong&gt; Done on the loop,
that tenth of a second is a tenth of a second in which the server answers nobody — so ten simultaneous
logins were ten seconds of a dead process. &lt;code&gt;argon2&lt;/code&gt; and &lt;code&gt;argon2Verify&lt;/code&gt; hand the derivation to a thread pool
and answer promises; everything else the server is doing carries on while it runs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;argon2NeedsRehash&lt;/code&gt; is not one of them&lt;/strong&gt;, and the difference says what the pool is for: it reads the
parameters out of the record and compares them, which is microseconds and no derivation at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The pool is four threads unless &lt;code&gt;UV_THREADPOOL_SIZE&lt;/code&gt; says otherwise&lt;/strong&gt;, and it is shared with file reads
and name resolution.&lt;/p&gt;
&lt;h3 id=&quot;neither-answers-a-result-and-that-is-a-decision&quot;&gt;Neither answers a result, and that is a decision&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A wrong password is &lt;code&gt;false&lt;/code&gt;; a stored record that will not parse faults.&lt;/strong&gt; They are not the same failure —
a record that is not an Argon2 record is a defect in whatever wrote the column — and collapsing them would
make a corrupted row read as an intruder, which is the one confusion a login path must not have.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;await argon2(p)&lt;/code&gt; is the record itself and &lt;code&gt;await argon2Verify(r, p)&lt;/code&gt; is a boolean, not the &lt;code&gt;{ ok, value }&lt;/code&gt;
a file read answers. Those carry a result because what they read came from outside the program and may not
be there; a derivation is a value the program built, and every way it can go wrong is a fault raised where
the call is written, before anything reaches a thread.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The record comes first and the password second.&lt;/strong&gt; Both are text, so a swap would answer &lt;code&gt;false&lt;/code&gt; forever
and never say why — a second argument that &lt;em&gt;is&lt;/em&gt; a record while the first is not is caught and named.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Classes</title>
    <link href="https://slatelang.dev/reference/classes/"/>
    <id>https://slatelang.dev/reference/classes/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>A class is an object with a proto and a word in front of it. class binds a name to an object literal and from is that object’s proto, so…</summary>
    <content type="html">&lt;h1 id=&quot;classes&quot;&gt;Classes&lt;/h1&gt;
&lt;p&gt;A class is an &lt;a href=&quot;/reference/objects/&quot;&gt;object with a proto&lt;/a&gt; and a word in front of it. &lt;code&gt;class&lt;/code&gt; binds a name to an
object literal and &lt;code&gt;from&lt;/code&gt; is that object’s &lt;code&gt;proto&lt;/code&gt;, so what runs is what protos already did.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sides &lt;span class=&quot;hl-keyword&quot;&gt;=&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;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;a &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;()&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; of area &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;area&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-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; Shape
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sides &lt;span class=&quot;hl-keyword&quot;&gt;=&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; side

    &lt;span class=&quot;hl-function&quot;&gt;name&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&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;square&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Square&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;a square of area 16
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A class belongs to the &lt;strong&gt;top level of a file&lt;/strong&gt;, as a &lt;code&gt;type&lt;/code&gt; does and for the same reason: its name is
resolved while compiling. &lt;code&gt;class&lt;/code&gt; is a soft word, so a program already using it as a variable name is
untouched.&lt;/p&gt;
&lt;h2 id=&quot;what-the-word-buys&quot;&gt;What the word buys&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A method is written in the ordinary definition syntax.&lt;/strong&gt; A field’s value is an expression, so a method
in a literal is a lambda and its body is whatever fits after &lt;code&gt;-&amp;gt;&lt;/code&gt;. A definition’s body may be an indented
run of statements, take annotated or destructured parameters, be &lt;code&gt;async&lt;/code&gt;, or &lt;code&gt;yield&lt;/code&gt;. A class of twenty
methods reads like twenty functions rather than like twenty fields.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;is&lt;/code&gt; asks which class a value was made from&lt;/strong&gt;, and walks the whole chain. This is the one thing &lt;code&gt;class&lt;/code&gt;
adds that a hand-written proto could not have:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; Shape
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; side

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; sq &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; Square&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;new&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;(sq &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Square, sq &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Shape)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ side&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hl-keyword&quot;&gt;proto&lt;/span&gt;&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; Square } &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Square)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;({ side&lt;span class=&quot;hl-keyword&quot;&gt;:&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; Square)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Square &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Square)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true true
true
false
false
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A bare name in pattern position is a binding unless something has declared it, and a class declaration
is what declares it — so the name works everywhere a type does: in &lt;code&gt;is&lt;/code&gt;, in a &lt;code&gt;match&lt;/code&gt; arm, and in a
parameter’s annotation. &lt;strong&gt;A class crosses a file under &lt;code&gt;export&lt;/code&gt; as both halves at once&lt;/strong&gt;, the value and
the type.&lt;/p&gt;
&lt;h2 id=&quot;val-and-var&quot;&gt;&lt;code&gt;val&lt;/code&gt; and &lt;code&gt;var&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;val&lt;/code&gt; is the class’s and &lt;code&gt;var&lt;/code&gt; is each object’s&lt;/strong&gt;, and that distinction is the one that bites. A &lt;code&gt;val&lt;/code&gt;
is one value however many objects there are; a &lt;code&gt;var&lt;/code&gt; declares a field each object gets, and its
initialiser runs &lt;strong&gt;once per object&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bag&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; items &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; []          &lt;span class=&quot;hl-comment&quot;&gt;// a NEW array for every bag&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; kind &lt;span class=&quot;hl-keyword&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;bag&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;        &lt;span class=&quot;hl-comment&quot;&gt;// one string, shared&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Bag&lt;/span&gt;()
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; b &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;Bag&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;push&lt;/span&gt;(a&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;items, &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-keyword&quot;&gt;.&lt;/span&gt;items, b&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;items, a&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;kind)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;[1] [] bag
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A mutable literal under &lt;code&gt;val&lt;/code&gt; is refused, and the message names &lt;code&gt;var&lt;/code&gt; as the fix:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Bag&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; items &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; []&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;var
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TypeScript spells the per-instance one &lt;code&gt;items = []&lt;/code&gt;, so a reader coming from TS writes &lt;code&gt;val&lt;/code&gt; and gets
one array every instance pushes into. &lt;strong&gt;A mutable literal under &lt;code&gt;val&lt;/code&gt; is therefore refused&lt;/strong&gt;, and the
message names &lt;code&gt;var&lt;/code&gt; as the fix. Only a &lt;em&gt;literal&lt;/em&gt; is refused: an object bound outside the class and named
here is sharing somebody asked for, and still compiles.&lt;/p&gt;
&lt;h2 id=&quot;the-generated-new&quot;&gt;The generated &lt;code&gt;new&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A class that declares fields and writes no constructor is given one&lt;/strong&gt;, taking all of them — the fields
with no initialiser first, then the initialised ones, each optional with its initialiser as its default:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; side
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; tags &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; []

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Square&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;4&lt;/span&gt;))            &lt;span class=&quot;hl-comment&quot;&gt;// tags is a fresh []&lt;/span&gt;
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(Square&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;new&lt;/span&gt;(&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;red&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;]))   &lt;span class=&quot;hl-comment&quot;&gt;// and tags said otherwise&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;Square(side = 4, tags = [])
Square(side = 4, tags = [&amp;quot;red&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A default is &lt;a href=&quot;/reference/functions/&quot;&gt;worked out at the call&lt;/a&gt;, so leaving &lt;code&gt;tags&lt;/code&gt; out still gives every square its
own array. An initialiser may read a field bound before it — &lt;code&gt;var side&lt;/code&gt; then &lt;code&gt;var area = side * side&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An initialised field comes after an uninitialised one whatever order they were written in&lt;/strong&gt;, since a
default has to be trailing: &lt;code&gt;var kind = &amp;quot;plain&amp;quot;&lt;/code&gt; above &lt;code&gt;var side&lt;/code&gt; gives &lt;code&gt;new(side, kind = &amp;quot;plain&amp;quot;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A class that declares nothing gets no &lt;code&gt;new&lt;/code&gt; at all&lt;/strong&gt;, rather than one answering an empty object;
&lt;code&gt;{ side: 4, proto: Square }&lt;/code&gt; still works and is how such a class is made.&lt;/p&gt;
&lt;h2 id=&quot;writing-your-own-new&quot;&gt;Writing your own &lt;code&gt;new&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Write one when it has something to do. &lt;strong&gt;&lt;code&gt;var&lt;/code&gt; in its parameter list declares the field and assigns it&lt;/strong&gt;
— TypeScript’s parameter property — and &lt;code&gt;self&lt;/code&gt; is the object being made. The body runs for its effect
and the object is what comes back:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&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; area &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hl-function&quot;&gt;new&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; w, &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h)
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; w &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;||&lt;/span&gt; h &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&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;throw&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 side cannot be negative&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

        self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;area &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; w &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; h

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&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;.&lt;/span&gt;area)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Rect&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;-&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;.&lt;/span&gt;area &lt;span class=&quot;hl-keyword&quot;&gt;catch&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt; e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;message)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;12
a side cannot be negative
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A class with no declared fields keeps the plain form, where the body’s value &lt;em&gt;is&lt;/em&gt; the object:
&lt;code&gt;new(v) = { v: v }&lt;/code&gt;. It is given the class as its proto on the way out.&lt;/p&gt;
&lt;h2 id=&quot;class-patterns&quot;&gt;Class patterns&lt;/h2&gt;
&lt;p&gt;A class name written with fields after it tests and takes apart at once, which is what a Scala case
class does — by position, or by name:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; side

&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Circle&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; radius

&lt;span class=&quot;hl-keyword&quot;&gt;class&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; w
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; h

&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(v) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;match&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(n) &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;a square of side &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-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    Circle { radius&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; r } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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;a circle of &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;r&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;
    Rect { w, h } &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&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-punctuation&quot;&gt;${&lt;/span&gt;w&lt;span class=&quot;hl-punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;hl-string&quot;&gt; by &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;h&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-variable&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;hl-keyword&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-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;(&lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Square&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;3&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Circle&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;7&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;tell&lt;/span&gt;(&lt;span class=&quot;hl-function&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;5&lt;/span&gt;)), &lt;span class=&quot;hl-function&quot;&gt;tell&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-output&quot;&gt;a square of side 3 a circle of 7 2 by 5 something else
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The positional order is the constructor’s, and that holds by construction rather than by convention&lt;/strong&gt;
— the field list a pattern is checked against &lt;em&gt;is&lt;/em&gt; the parameter list of the &lt;code&gt;new&lt;/code&gt; the class was given,
so &lt;code&gt;Square(n)&lt;/code&gt; binds what &lt;code&gt;Square.new(4)&lt;/code&gt; sets and the two cannot drift apart.&lt;/p&gt;
&lt;p&gt;A class that builds its own object in a hand-written &lt;code&gt;new&lt;/code&gt; has no such list and is &lt;strong&gt;refused the
positional form by name&lt;/strong&gt;, with the named one offered instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Naming the class is what lets a misspelled field be caught&lt;/strong&gt;: a bare &lt;code&gt;{ raduis: r }&lt;/code&gt; is a legal pattern
that never matches, where &lt;code&gt;Circle { raduis: r }&lt;/code&gt; is refused where it stands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The class name is also a shape value&lt;/strong&gt;, so &lt;code&gt;Circle.test(v)&lt;/code&gt; asks at run time what &lt;code&gt;v is Circle&lt;/code&gt; asks
where it is written, and &lt;code&gt;Circle.mismatch(v)&lt;/code&gt; and &lt;code&gt;Circle.name()&lt;/code&gt; answer too — see
&lt;a href=&quot;/reference/types/#a-type-is-a-value-under-its-own-name&quot;&gt;Types&lt;/a&gt;. A static the class declares under one of those
three names wins over it.&lt;/p&gt;
&lt;h2 id=&quot;is-in-the-header&quot;&gt;&lt;code&gt;is&lt;/code&gt; in the header&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;is&lt;/code&gt; in a class header is TypeScript’s &lt;code&gt;implements&lt;/code&gt; — a promise, checked where the class is written:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Drawable&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { draw&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;function&lt;/span&gt; }

&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pen&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Drawable
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ink

    &lt;span class=&quot;hl-function&quot;&gt;draw&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&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;pen with &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ink

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;Pen&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-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;draw&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;pen with blue
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Leave &lt;code&gt;draw&lt;/code&gt; out and the fault names the class, rather than arriving wherever something first wanted
to draw one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Drawable&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { draw&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;function&lt;/span&gt; }

&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Pen&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;is&lt;/span&gt; Drawable
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; ink

    &lt;span class=&quot;hl-function&quot;&gt;scribble&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&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;pen&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;Drawable
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;It inherits nothing;&lt;/strong&gt; &lt;code&gt;from&lt;/code&gt; does that. What it buys is &lt;em&gt;when&lt;/em&gt; you find out: leave &lt;code&gt;draw&lt;/code&gt; out and the
fault names the class rather than arriving wherever something first wanted to draw one. A class may
promise several types (&lt;code&gt;is Drawable, Named&lt;/code&gt;) and descend from one.&lt;/p&gt;
&lt;p&gt;A promise is kept by a method a base supplies, because an &lt;a href=&quot;/reference/patterns/&quot;&gt;object pattern&lt;/a&gt; counts a field a
proto supplies.&lt;/p&gt;
&lt;h2 id=&quot;there-is-no-super&quot;&gt;There is no &lt;code&gt;super&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;And none is needed. A base class is an ordinary value in scope, and a method stored on it directly is
handed no receiver — so passing one is how you call it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Shape&lt;/span&gt;
    &lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&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;a shape of area &lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;${&lt;/span&gt;self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;area&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-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Square&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; Shape
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; side

    &lt;span class=&quot;hl-function&quot;&gt;area&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; self&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;side

&lt;span class=&quot;hl-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hl-type&quot;&gt;Loud&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; Square
    &lt;span class=&quot;hl-function&quot;&gt;new&lt;/span&gt;(side) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; { side&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; side }

    &lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(self) &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;upper&lt;/span&gt;(Shape&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;(self)) &lt;span class=&quot;hl-keyword&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;!&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;Loud&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;describe&lt;/span&gt;())&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;A SHAPE OF AREA 4!
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;Shape.describe(self)&lt;/code&gt; names the class the call was written in, which is what a super call means.
Counting links from whatever object turned up — &lt;code&gt;self.proto.proto&lt;/code&gt; — is a different and wrong thing.&lt;/p&gt;
&lt;h2 id=&quot;calling-a-class&quot;&gt;Calling a class&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;An object with a &lt;code&gt;new&lt;/code&gt; is callable&lt;/strong&gt;, so &lt;code&gt;Square(4)&lt;/code&gt; is &lt;code&gt;Square.new(4)&lt;/code&gt;. That is what makes a
&lt;a href=&quot;/reference/data-types/&quot;&gt;data variant&lt;/a&gt;‘s constructor an ordinary function.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>slate:brotli</title>
    <link href="https://slatelang.dev/library/brotli/"/>
    <id>https://slatelang.dev/library/brotli/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>compress faults — it cannot fail on input the program already holds. decompress answers a result, because what is being decompressed came from somewhere else: a request body that is…</summary>
    <content type="html">&lt;h1 id=&quot;slatebrotli&quot;&gt;&lt;code&gt;slate:brotli&lt;/code&gt;&lt;/h1&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;import&lt;/span&gt; { compress, decompress } &lt;span class=&quot;hl-keyword&quot;&gt;from&lt;/span&gt; slate:brotli

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; page &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;toBytes&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;&amp;lt;p&amp;gt;hello&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&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; small &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;compress&lt;/span&gt;(page, &lt;span class=&quot;hl-number&quot;&gt;5&lt;/span&gt;)               &lt;span class=&quot;hl-comment&quot;&gt;// quality 0-11&lt;/span&gt;
&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; back &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;decompress&lt;/span&gt;(small, &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)       &lt;span class=&quot;hl-comment&quot;&gt;// the limit is not optional&lt;/span&gt;

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(small) &lt;span class=&quot;hl-keyword&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;len&lt;/span&gt;(page))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok, &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(back&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;fromBytes&lt;/span&gt;(page)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;value)
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;decompress&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;toBytes&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 brotli&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-keyword&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;20&lt;/span&gt;)&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;ok)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;true
true true
false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-two-channels&quot;&gt;The two channels&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;compress&lt;/code&gt; faults&lt;/strong&gt; — it cannot fail on input the program already holds. &lt;strong&gt;&lt;code&gt;decompress&lt;/code&gt; answers a
result&lt;/strong&gt;, because what is being decompressed came from somewhere else: a request body that is not a brotli
stream is an ordinary thing to be sent and a &lt;code&gt;400&lt;/code&gt; to answer, not a defect in the program reading it.&lt;/p&gt;
&lt;p&gt;The three failures are three sentences, since they mean three different things to whoever sent the bytes:
&lt;em&gt;expands past the N bytes it was allowed&lt;/em&gt;, &lt;em&gt;ends in the middle&lt;/em&gt;, &lt;em&gt;is not a brotli stream&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-limit-is-required&quot;&gt;The limit is required&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A brotli stream carries no length and a crafted one of a few hundred bytes expands without bound.&lt;/strong&gt; There
is no form of &lt;code&gt;decompress&lt;/code&gt; that omits the limit.&lt;/p&gt;
&lt;h2 id=&quot;not-in-a-browser&quot;&gt;Not in a browser&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;No JavaScript host has a brotli encoder&lt;/strong&gt;, so &lt;code&gt;compress&lt;/code&gt; and &lt;code&gt;decompress&lt;/code&gt; refuse under &lt;code&gt;slate js&lt;/code&gt;,
naming brotli rather than promising a release. &lt;a href=&quot;/library/gzip/&quot;&gt;&lt;code&gt;slate:gzip&lt;/code&gt;&lt;/a&gt; is the compression a browser has,
and it is promise-shaped for that reason; this module is synchronous and stays so.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/library/http/&quot;&gt;&lt;code&gt;slate:http&lt;/code&gt;&lt;/a&gt; compresses a response without asking the handler; that page says what the rules are.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Asynchrony</title>
    <link href="https://slatelang.dev/reference/asynchrony/"/>
    <id>https://slatelang.dev/reference/asynchrony/</id>
    <updated>2026-09-06T00:36:22.158815252Z</updated>
    <summary>An async function answers a promise rather than a value, and await waits for one:</summary>
    <content type="html">&lt;h1 id=&quot;asynchrony&quot;&gt;Asynchrony&lt;/h1&gt;
&lt;h2 id=&quot;async-and-await&quot;&gt;&lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;An &lt;code&gt;async&lt;/code&gt; function answers a promise rather than a value, and &lt;code&gt;await&lt;/code&gt; waits for one:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;work&lt;/span&gt;(name, ms, turns)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;=&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-keyword&quot;&gt;&amp;lt;&lt;/span&gt; turns
        &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sleep&lt;/span&gt;(ms)
        i &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    name &lt;span class=&quot;hl-keyword&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; finished&lt;/span&gt;&lt;span class=&quot;hl-punctuation&quot;&gt;&amp;quot;&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; a &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;work&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;8&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; b &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;work&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-number&quot;&gt;20&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;started both&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;await&lt;/span&gt; a)
    &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; b)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;started both
a finished
b finished
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Everything above a function’s first &lt;code&gt;await&lt;/code&gt; runs before its caller sees the promise, and everything
below it runs after the caller has moved on&lt;/strong&gt; — which is node’s rule, and why &lt;code&gt;started both&lt;/code&gt; prints
before either worker’s first step. The two workers then interleave by their own clocks: with those
numbers &lt;code&gt;a&lt;/code&gt; takes its first two steps, &lt;code&gt;b&lt;/code&gt; takes one, &lt;code&gt;a&lt;/code&gt; finishes, and &lt;code&gt;b&lt;/code&gt; finishes last.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Top-level &lt;code&gt;await&lt;/code&gt; is refused&lt;/strong&gt;, so a program that wants to wait writes an &lt;code&gt;async main&lt;/code&gt; and calls it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sleep&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;`await` belongs in an `async` function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;async&lt;/code&gt; goes in front of a definition, a lambda, or a method. Making the whole program a coroutine is a
real design and one to make on purpose.&lt;/p&gt;
&lt;h2 id=&quot;the-order-things-run-in&quot;&gt;The order things run in&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A settled promise still resumes through the queue rather than continuing in place&lt;/strong&gt;, so what was
scheduled first runs first; &lt;code&gt;await&lt;/code&gt; of a plain value answers it and still yields, so a program cannot
tell which of the two it was handed by watching what runs next.&lt;/p&gt;
&lt;p&gt;There are two queues and the order between them is fixed. One answers &lt;em&gt;something happened outside the
program&lt;/em&gt; — a timer, a socket, a file. A second, drained to empty between every turn of the first, answers
&lt;em&gt;a value a suspended call is owed is now known&lt;/em&gt;. That is JavaScript’s microtask/macrotask split, and it
is not a refinement: a program that resolved a promise from a timer callback and then ran the next timer
before the awaiting function had moved would interleave in an order nothing could predict.&lt;/p&gt;
&lt;h2 id=&quot;failure&quot;&gt;Failure&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A failed promise raises where it was awaited.&lt;/strong&gt; A promise fails when the &lt;code&gt;async&lt;/code&gt; function running it
faults; awaiting that promise raises the same fault in the awaiting function, so a chain of &lt;code&gt;await&lt;/code&gt;s
carries a fault to whoever is waiting at the end of it — and a &lt;a href=&quot;/reference/faults/&quot;&gt;&lt;code&gt;catch&lt;/code&gt;&lt;/a&gt; anywhere along that
chain stops it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;catch&lt;/code&gt; works across an &lt;code&gt;await&lt;/code&gt;.&lt;/strong&gt; A coroutine carries its handlers with it when it is set aside, so a
promise that fails minutes later still raises inside the &lt;code&gt;try&lt;/code&gt; that was written around the &lt;code&gt;await&lt;/code&gt;
rather than escaping to the scheduler.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A failure nothing was waiting for is the program’s failure&lt;/strong&gt;, reported against the line that raised it.
That is the one thing node gets wrong by default and warns about instead.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A call whose promise was thrown away fails at once; everything else is asked at the end.&lt;/strong&gt; The question
“was this handled?” usually cannot be answered when a promise fails — &lt;code&gt;val p = risky()&lt;/code&gt; and &lt;code&gt;await p&lt;/code&gt;
three lines later is ordinary — so it is asked once, after everything has settled. But a call written on
a line of its own, &lt;code&gt;main()&lt;/code&gt;, was never given to anybody: there is no name for it and no line that could
ever await it, so its failure is final where it happens. That distinction is what makes the report reach
a &lt;strong&gt;server&lt;/strong&gt;, which never settles and would otherwise hold the diagnostic for as long as the process
lived — a fault in a coroutine that looks, from outside, exactly like a hang.&lt;/p&gt;
&lt;h2 id=&quot;making-a-promise&quot;&gt;Making a promise&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;sleep(ms)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;a promise for later; takes a &lt;a href=&quot;/library/time/&quot;&gt;duration&lt;/a&gt; too&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;resolve(v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one that has already settled with a value&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;reject(message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one that has already failed&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;pending()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;one nobody has answered yet&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;settle(p, v)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;answer a pending one&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;fail(p, message)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;fail a pending one&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;resolve&lt;/code&gt; and &lt;code&gt;reject&lt;/code&gt; adapt something that has already happened; &lt;code&gt;pending&lt;/code&gt;/&lt;code&gt;settle&lt;/code&gt;/&lt;code&gt;fail&lt;/code&gt; adapt
something that has not. Without them a program could only await what slate itself started, and anything
with a callback of its own would be stuck in callbacks. They are JavaScript’s &lt;code&gt;Promise.withResolvers()&lt;/code&gt;
under slate’s own names.&lt;/p&gt;
&lt;h2 id=&quot;timers&quot;&gt;Timers&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;setTimeout(fn, ms)&lt;/code&gt; and &lt;code&gt;setInterval(fn, ms)&lt;/code&gt; answer an id; &lt;code&gt;clearTimeout(id)&lt;/code&gt; and &lt;code&gt;clearInterval(id)&lt;/code&gt;
stop one. &lt;strong&gt;A timer keeps the program alive&lt;/strong&gt;, so an interval nothing clears is a program that never
exits.&lt;/p&gt;
&lt;p&gt;The callback comes first, which is node’s order — and a callback in that position cannot be a
&lt;a href=&quot;/reference/functions/&quot;&gt;block lambda&lt;/a&gt;, those having to be last.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A fault in a callback is not caught by the call that scheduled it.&lt;/strong&gt; &lt;code&gt;try setTimeout(...)&lt;/code&gt; guards the
scheduling and nothing else, because the callback runs from the loop long afterwards. That is inherent
rather than a gap: there is no statement of the program’s left to attach it to.&lt;/p&gt;
&lt;h2 id=&quot;for-await&quot;&gt;&lt;code&gt;for await&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;for await x in source&lt;/code&gt; asks the subject for &lt;code&gt;next()&lt;/code&gt; and awaits the answer&lt;/strong&gt;, stopping when it says
it is done. It is legal only inside an &lt;code&gt;async&lt;/code&gt; function.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counted&lt;/span&gt;(n)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; it &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; {}

    it&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;next &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; () &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;sleep&lt;/span&gt;(&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-keyword&quot;&gt;&amp;gt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; { done&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; }
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
            i &lt;span class=&quot;hl-keyword&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
            { done&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; }

    it

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counted&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;(v)

&lt;span class=&quot;hl-function&quot;&gt;main&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;A source is anything with a &lt;code&gt;next()&lt;/code&gt;&lt;/strong&gt;, and that is the whole protocol — there is no second
well-known name and no symbol. A &lt;a href=&quot;#generators&quot;&gt;generator&lt;/a&gt; already has one, so a synchronous subject
works unchanged:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;twoOf&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;twoOf&lt;/span&gt;()
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;main&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;What makes one rule enough is that &lt;code&gt;await&lt;/code&gt; of a plain value answers it.&lt;/strong&gt; A generator’s &lt;code&gt;next()&lt;/code&gt;
answers &lt;code&gt;{ value, done }&lt;/code&gt; outright and an asynchronous source answers a promise of the same shape, so
there is no fallback branch to write and nothing for a reader to choose between.&lt;/p&gt;
&lt;p&gt;It is a loop like any other: &lt;code&gt;break&lt;/code&gt; gives it a value, a label says which loop to leave, and an &lt;code&gt;else&lt;/code&gt;
runs when it finished on its own.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counted&lt;/span&gt;(n)
    &lt;span class=&quot;hl-keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; it &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; {}

    it&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;next &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; () &lt;span class=&quot;hl-keyword&quot;&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;&amp;gt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;then&lt;/span&gt; { done&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;true&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;null&lt;/span&gt; }
        &lt;span class=&quot;hl-keyword&quot;&gt;else&lt;/span&gt;
            i &lt;span class=&quot;hl-keyword&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;
            { done&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;hl-variable&quot;&gt;false&lt;/span&gt;, value&lt;span class=&quot;hl-keyword&quot;&gt;:&lt;/span&gt; i &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt; }

    it

&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; found &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &apos;search &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counted&lt;/span&gt;(&lt;span class=&quot;hl-number&quot;&gt;9&lt;/span&gt;)
        &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;30&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;search v

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

    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; v &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counted&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-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;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;nothing arrived&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;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;30
nothing arrived
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The subject is evaluated once&lt;/strong&gt;, so a call in the head makes one source and not one per turn.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An array is not a source.&lt;/strong&gt; It has no &lt;code&gt;next()&lt;/code&gt;, and the refusal says so rather than naming a method
the program never wrote:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; x &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;2&lt;/span&gt;]
        &lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(x)

&lt;span class=&quot;hl-function&quot;&gt;main&lt;/span&gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-error&quot;&gt;a `for await` asks its subject for `next()`, and an array has none -- write `for` without `await` to walk an array
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Outside an &lt;code&gt;async&lt;/code&gt; function it is refused where the awaiting would happen:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;twoOf&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;yield&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; &lt;span class=&quot;hl-keyword&quot;&gt;await&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;twoOf&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;`for await` belongs in an `async` function
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;There is no &lt;code&gt;async&lt;/code&gt; generator yet.&lt;/strong&gt; A source is written by hand as an object with a &lt;code&gt;next&lt;/code&gt;, which is
how node’s streams implement theirs; the sugar for &lt;em&gt;producing&lt;/em&gt; one came second in JavaScript and can
come second here.&lt;/p&gt;
&lt;h2 id=&quot;generators&quot;&gt;Generators&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;A function is a generator because it holds a &lt;code&gt;yield&lt;/code&gt;&lt;/strong&gt; — Python’s rule, with no word on the definition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;counter&lt;/span&gt;(&lt;span class=&quot;hl-keyword&quot;&gt;from&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-keyword&quot;&gt;from&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;loop&lt;/span&gt;
        &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; n
        n &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; n &lt;span class=&quot;hl-keyword&quot;&gt;+&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; g &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;counter&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&lt;/span&gt;(g))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(g&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;next&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; &lt;span class=&quot;hl-function&quot;&gt;counter&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;(x)

    &lt;span class=&quot;hl-keyword&quot;&gt;if&lt;/span&gt; x &lt;span class=&quot;hl-keyword&quot;&gt;==&lt;/span&gt; &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;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-output&quot;&gt;{value: 1, done: false}
{value: 2, done: false}
1
2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Calling one runs nothing.&lt;/strong&gt; The body starts on the first &lt;code&gt;next&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;next(g)&lt;/code&gt; and &lt;code&gt;g.next()&lt;/code&gt; are the one call&lt;/strong&gt;, &lt;code&gt;next&lt;/code&gt; being a free function like every other method.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;next&lt;/code&gt; answers &lt;code&gt;{ value, done }&lt;/code&gt;&lt;/strong&gt;, and a generator whose body has finished answers
&lt;code&gt;{ value: null, done: true }&lt;/code&gt; from then on.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for x in g&lt;/code&gt; is an ordinary loop over one, and stops when the generator does.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A generator does not touch the event loop&lt;/strong&gt;, so generators work in a program with no loop running.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;val got = yield x&lt;/code&gt;&lt;/strong&gt; is how a value is sent in: the driver’s value is written over the slot the
yielded one left.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-slate&quot;&gt;&lt;span class=&quot;hl-function&quot;&gt;echoer&lt;/span&gt;()
    &lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; got &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hl-keyword&quot;&gt;yield&lt;/span&gt; got &lt;span class=&quot;hl-keyword&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;hl-number&quot;&gt;10&lt;/span&gt;

&lt;span class=&quot;hl-keyword&quot;&gt;val&lt;/span&gt; e &lt;span class=&quot;hl-keyword&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hl-function&quot;&gt;echoer&lt;/span&gt;()

&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hl-function&quot;&gt;next&lt;/span&gt;(e))
&lt;span class=&quot;hl-function&quot;&gt;print&lt;/span&gt;(e&lt;span class=&quot;hl-keyword&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;hl-function&quot;&gt;next&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;{value: 1, done: false}
{value: 50, done: false}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;yield&lt;/code&gt; takes the whole expression where &lt;code&gt;await&lt;/code&gt; takes one operand.&lt;/strong&gt; &lt;code&gt;await f() + 1&lt;/code&gt; waits for the
call and adds to the answer; &lt;code&gt;yield x * x&lt;/code&gt; yields the product. A yield used inside a larger expression is
bracketed. JavaScript and Python both put &lt;code&gt;yield&lt;/code&gt; at the bottom of the ladder.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;An &lt;code&gt;async&lt;/code&gt; function may not &lt;code&gt;yield&lt;/code&gt;.&lt;/strong&gt; Two things would be entitled to put one machine back and there
is no rule for which, so calling one fails its promise with &lt;em&gt;“an &lt;code&gt;async&lt;/code&gt; function may not &lt;code&gt;yield&lt;/code&gt; – an
async generator is not slate”&lt;/em&gt;. It is refused at the call rather than at the compile.&lt;/p&gt;
&lt;p&gt;An abandoned generator’s state is held for the life of the program — there is no finalizer, so a
generator never run to the end keeps what it was holding.&lt;/p&gt;</content>
  </entry>
</feed>
