<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>joel.place</title><description>Joel&apos;s blog</description><link>https://joel.place/</link><item><title>Can Anthropic Write Software?</title><link>https://joel.place/blog/anthropic-admin/</link><guid isPermaLink="true">https://joel.place/blog/anthropic-admin/</guid><description>Tales From the Organization Settings Page</description><pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It is somewhat in vogue right now to criticize Anthropic. In particular, much ink has been spilled over the color of the &lt;a href=&quot;https://status.claude.com/&quot;&gt;Claude Status page&lt;/a&gt; and the corresponding lack of reliability, as well as accusations of fear-mongering about their latest model, &lt;a href=&quot;https://red.anthropic.com/2026/mythos-preview/&quot;&gt;Mythos&lt;/a&gt;. In these and many other domains, I have great sympathy for Anthropic. It is a hugely challenging problem to try and accommodate the pace of growth in agentic coding, made worse by their limitations in compute.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Furthermore, although they are certainly financially incentivized to espouse a belief in the overwhelming power of AI, I have found their employees to be genuine in their concern about its impact.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; I wasn’t looking for an excuse to pile on. Nonetheless, when I accidentally found myself administrating my startup’s Claude subscription, I found myself a little shocked by the experience.&lt;/p&gt;
&lt;h2 id=&quot;lamentations&quot;&gt;Lamentations&lt;/h2&gt;
&lt;p&gt;Let me briefly list out a few of the problems I’ve had in the “organization settings” page off the top of my head:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;UI updates usually require a page refresh. If I change an employee’s status, the page will print a success message, but continue showing the old status.&lt;/li&gt;
&lt;li&gt;Adding employees to the plan does not reliably succeed. After enough people telling me they didn’t get my invites, I’ve found myself refreshing the page to check the status after each invite so that I can retry if it wasn’t registered.&lt;/li&gt;
&lt;li&gt;Downgrading users is nigh impossible. If I attempt to downgrade someone, I’m told I must schedule for it to occur at the end of the month, but then when I take any other action (e.g. adding or upgrading anyone else) I’m required to cancel any scheduled changes.&lt;/li&gt;
&lt;li&gt;Employees are identified by first name only. If someone requests to increase the limits on their usage, I have no way to disambiguate (e.g. by their employee email they were added with).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Don’t even get me started on the janky broken scrolling experience that exists on certain pages.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; I’d report these issues properly if their process for such issues weren’t notoriously slow and painful.&lt;/p&gt;
&lt;h2 id=&quot;why-im-surprised&quot;&gt;Why I’m Surprised&lt;/h2&gt;
&lt;p&gt;To me, there are two main reasons for this to be so shocking:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Incentive&lt;/strong&gt;: This is the bread and butter of the company’s revenue. They sell Claude Code to enterprises. I’ve focused my complaints here on the pages I can use in order to send them more money. Shouldn’t that be the very place they want the experience to be smoothest?&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Capability&lt;/strong&gt;: This is also the key thing their product is considered best at. Claude Code makes beautiful web UIs faster than the most experienced humans. Presumably Anthropic engineers should have the most access to and be the most adept at using their own product?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Anthropic should be uniquely able and motivated to fix this. So why haven’t they?&lt;/p&gt;
&lt;h2 id=&quot;root-causes&quot;&gt;Root Causes&lt;/h2&gt;
&lt;p&gt;So far I have two main theories to explain this:&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Carelessness&lt;/strong&gt;: It is possible that, although important, this sort of work sanding down rough edges in the UX is simply seen as low status within the organization compared to the sort of research that might lead more directly to the goals of recursive self-improvement and super-intelligence. There’s so much else exciting going on that it’s easy for things to fall through the cracks. If that were the case, I would be a little bit worried about Anthropic, and its ability to maintain its enterprise advantage as it scales into a bigger organization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kool-Aid&lt;/strong&gt;: It is possible that rather than appearing despite the power of Claude Code, these sorts of issues are in fact symptomatic of the ways that language models can now intermediate between developers and their products, and of an organization uniquely enamored with this capability. Perhaps a human more tightly integrated with internal testing might have caught these before they reached me. If this is instead the case, then I worry not for Anthropic, but for all of us who’ve begun to rely on agentic coding more heavily, and may soon face the costs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I won’t claim to know which of these or the many other possibilities is more true, but I certainly hope it’s something closer to the former, and that Anthropic can assign a few more people to tighten all this up and prove that to us.&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;I’m even amenable to &lt;a href=&quot;https://www.dwarkesh.com/p/dario-amodei-2&quot;&gt;Dario’s arguments&lt;/a&gt; that, given what they knew at the time, aggressively acquiring more compute earlier would have been irresponsible. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Many had similar beliefs before any of this was profitable, and it’s only sensible that they’ve updated them to be more aggressive given the pace of advancements. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;But not others, since there is limited consistency to the UI even when representing seemingly similar-shaped data. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;Perhaps admin pages are universally secondary to those for the end users, but they’re still an important stakeholder to have on board. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;A third possibility could be that organizations like ours doing our own administration are simply too small to matter compared to the biggest customers. &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item><item><title>A Path Not Taken for OxCaml</title><link>https://joel.place/blog/path-not-taken/</link><guid isPermaLink="true">https://joel.place/blog/path-not-taken/</guid><description>The Price of Backwards Compatibility</description><pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://oxcaml.org/&quot;&gt;OxCaml&lt;/a&gt; is Jane Street’s effort to &lt;em&gt;oxidize&lt;/em&gt; OCaml, that is, to make it more Rust-like. In particular, the aspect of Rust focused on here is its “fearless concurrency” where the compiler can protect against data races, which is important in light of OCaml 5’s new multicore capabilities.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;The project adds a significant number of exciting new features to the language (modes, kinds, layouts, etc.), but is careful to act only as an “extension” to the language, promising on its front page that&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;all valid OCaml programs are also valid OxCaml programs&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’m going to argue that this promise, while noble, was ultimately misguided, forcing it to give up on what could have been a simpler language. To do that, we’ll first have to go over a little OxCaml, talk about how it’s complex, consider its use in practice, and then finally explore an alternate path. Hopefully by the end you’ll understand why, despite this promise, the &lt;a href=&quot;https://github.com/janestreet/core/blob/oxcaml/validate/src/validate.mli&quot;&gt;Core validation library&lt;/a&gt; went from looking like this&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &apos;a&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &apos;a&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; combine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; of_list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; name_list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; fail_fn &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pass_bool &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; pass_unit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; try_with &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unit&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; first_failure &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to instead like this (sans comments for brevity)&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; value &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;mod&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; contended&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;type%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template (&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;&apos;a&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; :&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; any) check &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; &apos;a&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template combine &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template of_list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template name &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template name_list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template fail_fn &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p]) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; portable [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template pass_bool &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p]) [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template pass_unit &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; check[&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p]) [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template try_with &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;unit&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; unit&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val%&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;template first_failure &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p [&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;@@mode&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; p &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (portable&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; nonportable)]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;modes&quot;&gt;Modes&lt;/h2&gt;
&lt;p&gt;So what’s that word “mode” we’re seeing above? OxCaml’s &lt;a href=&quot;https://oxcaml.org/documentation/modes/intro/&quot;&gt;mode system&lt;/a&gt; is sort of like its type system, in that every value &lt;code&gt;x : t @ m&lt;/code&gt; has some statically known type &lt;code&gt;t&lt;/code&gt; and mode &lt;code&gt;m&lt;/code&gt;, where &lt;code&gt;@&lt;/code&gt; is the syntax for mode annotation.&lt;/p&gt;
&lt;p&gt;Modes are deep properties (so &lt;code&gt;m&lt;/code&gt; applies recursively to the contents of &lt;code&gt;x&lt;/code&gt;) and are formed as a lattice of different mode axes which are generally orthogonal to types and each other (although values of some types can disregard or “cross” certain modes). To make this concrete, let’s look at some examples of how they might map onto Rust’s type system.&lt;/p&gt;
&lt;h3 id=&quot;modes--references&quot;&gt;Modes &amp;#x26; References&lt;/h3&gt;
&lt;p&gt;At Rust’s core is a borrow checker, which enforces each value &lt;code&gt;x: T&lt;/code&gt; has a single owner, but allows it to be temporarily borrowed as &lt;code&gt;&amp;#x26;x: &amp;#x26;T&lt;/code&gt; or &lt;code&gt;&amp;#x26;mut x: &amp;#x26;mut T&lt;/code&gt;, with these borrows reflected in the type system. How might we express something similar in OxCaml?&lt;/p&gt;
&lt;p&gt;Well, rather than being forced to change the type of our value to reflect these, we would put this additional information about how it can be used into its modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;#x26;x: &amp;#x26;T&lt;/code&gt; might loosely correspond to &lt;code&gt;x : t @ local read aliased&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;x: T&lt;/code&gt; might loosely correspond to &lt;code&gt;x : t @ global read_write unique&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here, we see our first three mode axes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Locality&lt;/strong&gt;: &lt;code&gt;local&lt;/code&gt; indicates a value which cannot escape its scope, whereas &lt;code&gt;global&lt;/code&gt; values can do so (analogous to Rust’s lifetimes).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visibility&lt;/strong&gt;: &lt;code&gt;read&lt;/code&gt; indicates a value which can read from but not write to its mutable state, whereas &lt;code&gt;read_write&lt;/code&gt; values can do either.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uniqueness&lt;/strong&gt;: &lt;code&gt;aliased&lt;/code&gt; represents a value which may have other references to it, whereas &lt;code&gt;unique&lt;/code&gt; values act like Rust’s affine type system.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So far I’m relatively fond of these modes: they create clarity about what they each control rather than intermingling in a single concept of ownership, and don’t need to corrupt the type of &lt;code&gt;x&lt;/code&gt; to represent this in the way that Rust’s version is also inextricably linked with whether we have a reference with indirection.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; However, you can probably see already the danger of a sort of combinatorial explosion in possible states as the number of axes that can be set independently increases.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; If each value can have a type, a locality, a visibility, and a uniqueness, that’s a lot more to hold in your head than usual.&lt;/p&gt;
&lt;h3 id=&quot;modes--traits&quot;&gt;Modes &amp;#x26; Traits&lt;/h3&gt;
&lt;p&gt;OxCaml also has some modes that don’t map as directly onto Rust’s concepts of ownership, but instead look more like what Rust might put in a trait. In particular, I’d like to focus here on the portability mode:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Portability&lt;/strong&gt;: &lt;code&gt;portable&lt;/code&gt; indicates a value which can be shared with another thread&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;, whereas &lt;code&gt;nonportable&lt;/code&gt; values cannot do so.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Portability can be thought of as analogous to Rust’s &lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt; traits, which determine a type is safe to be shared across threads.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Note here a crucial distinction. Our Rust concept was a property of types: if &lt;code&gt;T: Send + Sync&lt;/code&gt;, then any value of type &lt;code&gt;T&lt;/code&gt; could be shared between threads. Meanwhile, in OxCaml this is a property of values. It is possible to have values &lt;code&gt;x1 : t @ portable&lt;/code&gt; and &lt;code&gt;x2 : t @ nonportable&lt;/code&gt; with different portabilities despite having the same type.&lt;/p&gt;
&lt;p&gt;This may be initially unintuitive to a Rust programmer, who is used to thinking about types as determining thread-safety. Canonically, atomically reference counted &lt;code&gt;Arc&amp;#x3C;_&gt;&lt;/code&gt; values could be shared, while non-atomic &lt;code&gt;Rc&amp;#x3C;_&gt;&lt;/code&gt; versions could not. However, the important thing to remember is that, in OCaml, functions are all values of the same arrow type:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;val&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; func &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; t1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; t2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the space of possible functions is very large, including both those which can clearly be shared across threads, as well as closures which capture mutable state, and therefore cannot be called from multiple threads without risking data races.&lt;/p&gt;
&lt;p&gt;This means the arrow type cannot have one deterministic portability applied to all of its values.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7&quot; id=&quot;user-content-fnref-7&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;7&lt;/a&gt;&lt;/sup&gt; Furthermore, since any abstract type could potentially contain a function, this means just about every OCaml value must maintain some portability state (apart from those which are explicitly annotated as containing no functions and therefore “crossing” portability).&lt;/p&gt;
&lt;p&gt;OxCaml divides its 9 currently documented modes into 4 “past” modes like the ones we saw earlier, and 5 “future” modes like portability, which are relevant only for types which contain functions for similar reasons to this.&lt;/p&gt;
&lt;h3 id=&quot;default-modes&quot;&gt;Default Modes&lt;/h3&gt;
&lt;p&gt;Now, we’d said earlier that OxCaml promised backwards compatibility with any OCaml code. One immediate observation is that old OCaml code did not have mode annotations everywhere, and so OxCaml must be able to handle code which does not specify modes. To do so, it uses “default modes”.&lt;/p&gt;
&lt;p&gt;Each mode axis has a default position, which is assumed when no mode is explicitly annotated. These defaults must be chosen carefully so that they do not break backwards compatibility:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Locality&lt;/strong&gt;: In OCaml, we never had to worry about whether a value was allowed to escape its scope. Therefore, our default mode must be &lt;code&gt;global&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visibility&lt;/strong&gt;: In OCaml, we never had to worry about whether we had permission to mutate a value of a type with mutability. Therefore, our default mode must be &lt;code&gt;read_write&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Uniqueness&lt;/strong&gt;: In OCaml, any value could be freely aliased, or have been so in the past. Therefore, our default mode must be &lt;code&gt;aliased&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In general, so far we’ve set all of our modes to be maximally permissive, allowing you to do as you please with your values.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-8&quot; id=&quot;user-content-fnref-8&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;8&lt;/a&gt;&lt;/sup&gt; Now let’s think about how we should extend this to the portability mode.&lt;/p&gt;
&lt;p&gt;So, legacy OCaml code was always single-core&lt;sup&gt;&lt;a href=&quot;#user-content-fn-9&quot; id=&quot;user-content-fnref-9&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;9&lt;/a&gt;&lt;/sup&gt;, and therefore there’s no legacy concept of whether values could be shared between them which we need to maintain backwards compatibility with. It would be nice if we could therefore continue to use the permissive modes, and by default allow values to be shared between threads.&lt;/p&gt;
&lt;p&gt;However, this doesn’t mean we’re free to just set any default that we want, as we’d made another promise: that OxCaml would statically prevent data races. And as we discussed earlier, there exist some values which could cause data races if shared across threads. Therefore we must set&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Portability&lt;/strong&gt;: In OCaml, there exist functions that are not thread-safe. To be free from data races, we must conservatively assume all values are &lt;code&gt;nonportable&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, this time we must choose the default mode that is more restrictive. Because the default mode applies to all legacy OCaml code, this means that &lt;em&gt;all&lt;/em&gt; OCaml code, when used in OxCaml, must be presumed not to be thread-safe.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-10&quot; id=&quot;user-content-fnref-10&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;10&lt;/a&gt;&lt;/sup&gt; That’s going to cause us some pain when writing code.&lt;/p&gt;
&lt;h2 id=&quot;portabilization&quot;&gt;Portabilization&lt;/h2&gt;
&lt;p&gt;So what does it mean for us to say that all legacy OCaml code is going to be &lt;code&gt;nonportable&lt;/code&gt;? Well definitionally, it means that those values cannot cross threads, but let’s think about the further implications.&lt;/p&gt;
&lt;p&gt;One thing OxCaml likes to emphasize along with its backwards compatibility story is its “pay-as-you-go” complexity. That if you don’t need some particular new advanced feature, you can simply avoid it and continue to write plain old OCaml. Can that work out in practice?&lt;/p&gt;
&lt;h3 id=&quot;portability-interoperability&quot;&gt;Portability Interoperability&lt;/h3&gt;
&lt;p&gt;If we took that literally, we might want to write most of our code in OCaml, which OxCaml would interpret as &lt;code&gt;nonportable&lt;/code&gt;. Then we would only adopt OxCaml’s concurrency features and their corresponding complications when we needed them for scaling performance-critical apps.&lt;/p&gt;
&lt;p&gt;In this world, we might further hope that when we wrote a new app or moved some existing app to &lt;code&gt;portable&lt;/code&gt; concurrent OxCaml, it could still take advantage of the larger OCaml ecosystem and preexisting libraries. Unfortunately, that’s going to prove difficult.&lt;/p&gt;
&lt;p&gt;You see non-portability is infectious. We’d said earlier that modes are deep: applying recursively to all of a value’s contents. So a &lt;code&gt;portable&lt;/code&gt; value cannot contain anything &lt;code&gt;nonportable&lt;/code&gt;, and any function which calls a &lt;code&gt;nonportable&lt;/code&gt; function must itself be &lt;code&gt;nonportable&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Given that all values in the default mode are &lt;code&gt;nonportable&lt;/code&gt;, asking you to write &lt;code&gt;portable&lt;/code&gt; concurrent OxCaml that depends on &lt;code&gt;nonportable&lt;/code&gt; legacy OCaml is sort of like asking you to write synchronous code that depends on a library in which every function is async. It just doesn’t work!&lt;/p&gt;
&lt;p&gt;However, this does not mean that all hope of true backwards compatibility is lost. There remains a ray of hope in the opposite direction, if you want to write OCaml code depending on OxCaml. A &lt;code&gt;nonportable&lt;/code&gt; function can call &lt;code&gt;portable&lt;/code&gt; functions. This opens up a path for how our OCaml and OxCaml might coexist.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-11&quot; id=&quot;user-content-fnref-11&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&quot;migration&quot;&gt;Migration&lt;/h3&gt;
&lt;p&gt;If we want our &lt;code&gt;portable&lt;/code&gt; OxCaml and &lt;code&gt;nonportable&lt;/code&gt; OCaml to share dependencies, we’re going to need to start from the very bottom of the dependency stack, where no existing &lt;code&gt;nonportable&lt;/code&gt; code is depended on. Converting that library to &lt;code&gt;portable&lt;/code&gt; OxCaml is safe, because existing OCaml code can still use it, and now &lt;code&gt;portable&lt;/code&gt; code can too.&lt;/p&gt;
&lt;p&gt;Once we’ve done that, we’ve now opened up another few libraries which we might be able to migrate, because they now only depend on &lt;code&gt;portable&lt;/code&gt; libraries, and so they themselves can become portable. Gradually, we can expand the scope of our migration out to the entire ecosystem in a process we’ll call portabilization.&lt;/p&gt;
&lt;p&gt;As we’re performing this migration, we can effectively find ourselves in one of two states&lt;sup&gt;&lt;a href=&quot;#user-content-fn-12&quot; id=&quot;user-content-fnref-12&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;12&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Either our code is already thread-safe, frequently via use of immutable persistent data structures, and just needs to be annotated as such in its signature.&lt;/li&gt;
&lt;li&gt;Or our code had the possibility of data races in the presence of multiple threads, and needs to be fundamentally rewritten or restructured to avoid this.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The former of course is simple, but the latter can create real work. Especially when porting the sort of performance-critical code we’d most like to move to OxCaml. That’s the same code most likely to use heavy mutation.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-13&quot; id=&quot;user-content-fnref-13&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;13&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, we persevere because we can see the light at the end of the tunnel. If we can take all of our libraries and move them one by one from OCaml to OxCaml, then we will finally be able to inter-operate between the languages: choosing to write code in either &lt;code&gt;portable&lt;/code&gt; or &lt;code&gt;nonportable&lt;/code&gt; fashion and share the same dependencies. For an organization like Jane Street with a large quantity of existing OCaml code that cannot all be migrated at once, this is essential.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-14&quot; id=&quot;user-content-fnref-14&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;14&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id=&quot;bifurcation&quot;&gt;Bifurcation&lt;/h3&gt;
&lt;p&gt;Still, does it feel like I pulled a bit of a sleight of hand on you there? I started this post talking about how the language was fully backwards compatible, and could compile all old code with no changes. Yet now I’m describing a world in which we must actively migrate all libraries from OCaml to OxCaml?&lt;/p&gt;
&lt;p&gt;And even once we’ve done so, and all our libraries are in &lt;code&gt;portable&lt;/code&gt; OxCaml, granting us the freedom to choose which way we want to write apps depending on them: which way do you think we’ll choose? The one where nobody else can depend on us and we might have to migrate in the future? No, we’ll probably stick with this new &lt;code&gt;portable&lt;/code&gt; OxCaml.&lt;/p&gt;
&lt;p&gt;In that case, incorporating OxCaml into an OCaml ecosystem risks feeling like migrating languages completely. You have to get used to new unfamiliar syntax for modes and layouts. You even have to substantially rewrite the logic of some of your code to fit the paradigms of the new language in which closures over mutable data are restrictive.&lt;/p&gt;
&lt;p&gt;It’s not quite as bad as the Python 3 migration&lt;sup&gt;&lt;a href=&quot;#user-content-fn-15&quot; id=&quot;user-content-fnref-15&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;15&lt;/a&gt;&lt;/sup&gt;, but the backwards compatibility promise wasn’t quite what we’re used to for regular language evolution where we can mostly avoid touching our old code. It’s like we’re migrating languages, but with a special property: that OCaml code can depend on OxCaml code, and the two can share the same toolchain.&lt;/p&gt;
&lt;p&gt;To some extent that was unavoidable. There was genuinely a lot of OCaml code which was safe only because it was known that it could never cross threads. That couldn’t be magically transferred to a multicore language without modification. Still, if we acknowledge that kind of migration is all we can do, then perhaps we can widen the design space we consider.&lt;/p&gt;
&lt;h2 id=&quot;another-path&quot;&gt;Another Path&lt;/h2&gt;
&lt;p&gt;So what if we took that literally? If we decided that we’d never quite achieve true backwards compatibility between a language which required thread-safety and one that only ever used a single thread. If we concluded that the best we could hope for was the existence of a migration path from OCaml due to the ability to gradually swap out components and still use OCaml code?&lt;/p&gt;
&lt;p&gt;This sort of change might feel like Rust’s concept of editions: where a project decides which edition of the language it will be written in, and the editions aren’t necessarily backwards compatible with each other. However, they still keep compatible interfaces, and even provide automatic migration tooling to convert from one to the other.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-16&quot; id=&quot;user-content-fnref-16&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;16&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;How would we design our thread-safe successor edition? Would we choose to write OxCaml? I would argue not. As we saw in the setting of default modes, the constraint that this language be able to compile plain OCaml really placed a lot of restrictions on us. And those restrictions led to complexity: in the combinatorial explosion of modes as we’ve focused on here, but also in the ways we can use unboxed types, layouts, and other OxCaml features.&lt;/p&gt;
&lt;p&gt;The space of possible languages is huge, and I won’t claim to come here with the perfect version. Still, let me talk through at least some of the ways we might improve upon the ailments we’ve discussed for a hypothetical better OxCaml.&lt;/p&gt;
&lt;h3 id=&quot;portability&quot;&gt;Portability&lt;/h3&gt;
&lt;p&gt;In a language designed for multithreading, &lt;code&gt;portable&lt;/code&gt; should be the default mode, and &lt;code&gt;nonportable&lt;/code&gt; values should feel like an exception. This is especially true in a functional language where immutability is the default, but holds even outside that. Rust requires &lt;code&gt;static mut&lt;/code&gt; to be wrapped arduously in &lt;code&gt;unsafe&lt;/code&gt;, and this sort of thing should feel similarly discouraged in OCaml. Instead, this sort of globally shared mutable state is made to appear easy and idiomatic by the language.&lt;/p&gt;
&lt;p&gt;If you look through OxCaml branches of Jane Street’s core libraries, this is already effectively the case, with most files starting with &lt;code&gt;@@ portable&lt;/code&gt; to indicate that the entire module’s contents should be taken as &lt;code&gt;portable&lt;/code&gt;. Still, I don’t want to have to scroll up to the top to learn how to interpret a declaration. If this is what’s sensible, I’d argue it should apply in general, and &lt;code&gt;nonportable&lt;/code&gt; values should have to explicitly inform us of their presence.&lt;/p&gt;
&lt;p&gt;A migration tool here might mark every value as &lt;code&gt;nonportable&lt;/code&gt;, or only those the compiler could not automatically infer to be &lt;code&gt;portable&lt;/code&gt;. To legacy OCaml edition dependencies where modes are erased, this would of course have no impact whatsoever, as there would still be no concept of crossing threads.&lt;/p&gt;
&lt;h3 id=&quot;functions&quot;&gt;Functions&lt;/h3&gt;
&lt;p&gt;Still, it is possible to imagine better: a world not just with a sensible default, but where we could get rid of the portability mode altogether. To do that, we would have to represent the difference between a thread-safe and non-thread-safe function in the type system, sort of like Rust’s &lt;code&gt;Fn&lt;/code&gt;, &lt;code&gt;FnMut&lt;/code&gt;, and &lt;code&gt;FnOnce&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A function which is intrinsically &lt;code&gt;nonportable&lt;/code&gt; is one which mutates values held in its closure, which could cause a data race. Another way to say that, is it is a function which, in order to be called, should have &lt;code&gt;read_write&lt;/code&gt;&lt;sup&gt;&lt;a href=&quot;#user-content-fn-17&quot; id=&quot;user-content-fnref-17&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;17&lt;/a&gt;&lt;/sup&gt; access to the contents of its closure on the mutability mode. Ordinarily, our modes are deep and apply recursively to a value’s contents. A function’s closure is the one exception where we don’t track or enforce this.&lt;/p&gt;
&lt;p&gt;You could imagine expressing that in the type of our functions. Where rather than having &lt;code&gt;type (-in, +out) fn&lt;/code&gt;, OxCaml might have &lt;code&gt;type (-in, +out, +mode) fn&lt;/code&gt;, where &lt;code&gt;mode&lt;/code&gt; is the mode in which you must hold that function in order to be allowed to call it.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-18&quot; id=&quot;user-content-fnref-18&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;18&lt;/a&gt;&lt;/sup&gt; Now data races on the contents of closures could be handled by the same mechanisms that stop data races elsewhere. Migrations could assume conservative requirements of their functions.&lt;/p&gt;
&lt;p&gt;Suddenly, we could basically cut out our future modes. While this risks its own form of combinatorial explosion, it’s one much more limited in scope. These parameters apply only to functions, not to all values like our modes, and in most cases you probably don’t need to be generic over all of them, and might have some expectation about what manner of function should be allowed in a given use case.&lt;/p&gt;
&lt;h3 id=&quot;beyond&quot;&gt;Beyond&lt;/h3&gt;
&lt;p&gt;One could imagine even crazier proposals to eliminate further modes or simplify OxCaml’s other features. It could even adopt linear or affine types as the default rather than an as after-thought mode, since linear logic really does simplify many of our problems. I won’t try to iterate all of these possibilities.&lt;/p&gt;
&lt;p&gt;It can sound here like perhaps I am saying that OCaml should cease to exist, and that if it is going to adopt some Rust-like features it should just go all the way. I’d like to make clear that I do not believe that. I find OCaml to be a particularly elegant language, and it is for exactly this reason that I am both eager to increase its capabilities and hesitant to add complexity.&lt;/p&gt;
&lt;p&gt;Perhaps Jane Street could not have feasibly offered a proper edition without backwards compatibility when they don’t control the language and can’t always pull upstream with them. Still, if some of these changes make it back into upstream, that would offer an opportunity to consider such choices and add this power in the best possible way.&lt;/p&gt;
&lt;p&gt;I believe OCaml should learn as much as it can from the experiences of other languages for how to offer safe concurrency. It is understandable that doing so may require new syntax, but when that is already the case, I don’t think making the syntax only nominally an exact superset of what exists is worth making it more complex than it needs to be.&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;OxCaml contains other Rust-like features, such as its ability to handle types with multiple layouts beyond OCaml’s standard one-word option, but we won’t focus on those for this post. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;There also exists an &lt;code&gt;immutable&lt;/code&gt; mode for values which can only access the immutable parts of their state, which has no real parallel in Rust where all fields are potentially mutable. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Rust has had repeated proposals for &lt;code&gt;&amp;#x26;own&lt;/code&gt; references that can decouple responsibility for cleaning up memory from whether or not you have a pointer, among similar messiness. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;That explosion is even actualized by &lt;code&gt;ppx_template&lt;/code&gt; we saw in our example, which really does expand out to all of the different mode combinations. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;Here the proper term would really be “domain”, which is OCaml’s version of a green-thread, but I’ll continue to use the term “thread” interchangeably in this piece, as does much OxCaml documentation. &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;&lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt; may feel distinct, but it is able to capture both simultaneously due to yet another mode tracking “contention” which roughly captures whether a value is exclusive to its thread. &lt;a href=&quot;#user-content-fnref-6&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7&quot;&gt;
&lt;p&gt;Whereas in Rust, each closure has its own anonymous type, so that not all closures need to share the same &lt;code&gt;Send&lt;/code&gt; and &lt;code&gt;Sync&lt;/code&gt; state. &lt;a href=&quot;#user-content-fnref-7&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 7&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-8&quot;&gt;
&lt;p&gt;More formally, the mode axes include a notion of submoding, and we have always chosen the least mode which can freely move to any of the other modes. &lt;a href=&quot;#user-content-fnref-8&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 8&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-9&quot;&gt;
&lt;p&gt;Here I’m considering “legacy OCaml” to be OCaml 4, with OxCaml as a potential upgrade from that. OCaml 5 does introduce multicore without these safety features, for which OxCaml does not make the same backwards compatibility promise. &lt;a href=&quot;#user-content-fnref-9&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 9&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-10&quot;&gt;
&lt;p&gt;This is made even worse by OCaml’s use of explicit &lt;code&gt;.mli&lt;/code&gt; interfaces separate from &lt;code&gt;.ml&lt;/code&gt; implementations. This means that even when the compiler can infer some values are portable, that can’t be exposed without annotation. &lt;a href=&quot;#user-content-fnref-10&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 10&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-11&quot;&gt;
&lt;p&gt;I realize there is an implicit assumption here that OxCaml code is necessarily &lt;code&gt;portable&lt;/code&gt;. While not strictly required, I argue that if you were going to forgo multicore capabilities, you might as well write ordinary OCaml instead. &lt;a href=&quot;#user-content-fnref-11&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 11&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-12&quot;&gt;
&lt;p&gt;Alright 3 states: it’s possible our values are portable but the compiler can’t prove it and so we’re sprinkling &lt;code&gt;Basement.Stdlib_shim.Obj.magic_portable&lt;/code&gt; everywhere. &lt;a href=&quot;#user-content-fnref-12&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 12&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-13&quot;&gt;
&lt;p&gt;It was in fact, a common practice in certain circles to pre-allocate a single global value and then mutate that to hold current data in non-recursive functions. This avoided allocations that might trigger a garbage collection cycle. &lt;a href=&quot;#user-content-fnref-13&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 13&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-14&quot;&gt;
&lt;p&gt;Even their much smaller-scoped migrations need to be careful not to disrupt existing systems, e.g. &lt;a href=&quot;https://signalsandthreads.com/swapping-the-engine-out-of-a-moving-race-car/&quot;&gt;https://signalsandthreads.com/swapping-the-engine-out-of-a-moving-race-car/&lt;/a&gt;. &lt;a href=&quot;#user-content-fnref-14&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 14&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-15&quot;&gt;
&lt;p&gt;In which Guido Van Rossum famously made the opposite promise&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is no requirement that Python 2.6 code will run unmodified on Python 3.0. Not even a subset. (Of course there will be a tiny subset, but it will be missing major functionality.)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;a href=&quot;#user-content-fnref-15&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 15&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-16&quot;&gt;
&lt;p&gt;Admittedly Rust’s editions offer somewhat stronger guarantees in that they allow dependencies in either direction. This causes its own pain for things like &lt;code&gt;Pin&lt;/code&gt; types. &lt;a href=&quot;#user-content-fnref-16&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 16&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-17&quot;&gt;
&lt;p&gt;Strictly speaking it also needs to be &lt;code&gt;uncontended&lt;/code&gt; on the contention mode, but the idea still applies. &lt;a href=&quot;#user-content-fnref-17&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 17&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-18&quot;&gt;
&lt;p&gt;Although currying makes this somewhat more unwieldy, and you wouldn’t want to have to annotate every arrow of a &lt;code&gt;t1 -&gt; t2 -&gt; ... -&gt; t_n&lt;/code&gt;. So you’d probably have to keep the existing syntax to denote the case which does not make any requirements on the mode of its closure, which would be by far the most common case, and certainly apply to early curried arguments. &lt;a href=&quot;#user-content-fnref-18&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 18&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item><item><title>Dwarkesh, Lex, &amp; Ezra</title><link>https://joel.place/blog/dwarkesh/</link><guid isPermaLink="true">https://joel.place/blog/dwarkesh/</guid><description>What Makes a Good Podcast?</description><pubDate>Mon, 20 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I am eternally grateful to Dwarkesh Patel for creating real competition to the &lt;em&gt;Lex Fridman Podcast&lt;/em&gt;. I find Lex to be a completely unbearable podcast host, capable neither of contributing anything I want to hear himself, nor eliciting interesting opinions from his guests. That made it a tragedy that for so long he seemed to monopolize the big name guests in CS, AI, tech, and the like. I’m also not that enthralled by his secondary bro-y focus, much preferring Dwarkesh’s excursions into history, China, and the like.&lt;/p&gt;
&lt;p&gt;However, as of late, particularly after his relatively combative &lt;a href=&quot;https://www.dwarkesh.com/p/jensen-huang&quot;&gt;episode with Nvidia’s Jensen Huang&lt;/a&gt;, there has been more chatter online about whether Dwarkesh too could be lacking in some ways. Most of this conversation has been picking sides: determining whether Dwarkesh or Jensen was right about whether AI chips should be sold to China, and which one of them was the more skillful debater. Although those are interesting questions, I’d like to ask something else: whether the nearly 40 minutes spent pressing Jensen on this produced the best possible podcast as an artifact, and whether Dwarkesh’s craft could be improved by dropping things sooner.&lt;/p&gt;
&lt;h2 id=&quot;interview-podcasts&quot;&gt;Interview Podcasts&lt;/h2&gt;
&lt;p&gt;Dwarkesh’s podcast fits into the broader genre of interview podcasts. These are perhaps the most dominant form of podcast, usually involving some persistent host, along with a rotating cast of guests per episode who they converse with. Guests are typically chosen to be noteworthy or interesting figures within the field or domain that the podcast and its host focus on. The host and guest then engage in a somewhat free-form conversation, with the host usually guiding and bringing up topics, but allowing the guest to provide most of the content.&lt;/p&gt;
&lt;p&gt;This is in opposition to podcasts with more simultaneous participants, where keeping a single thread of conversation and taking turns at the mic can be harder, as well as podcasts that are exposition of a scripted narrative, often by only one person. You can see why interviewing is such a popular format. Rather than relying on the host or hosts to be a constant wellspring of new and unique thought at the pace demanded by the modern internet, they only need each guest to have enough depth to make one interesting episode. Topics fall out naturally from their expertise, and the variety keeps things interesting.&lt;/p&gt;
&lt;h2 id=&quot;conversation&quot;&gt;Conversation&lt;/h2&gt;
&lt;p&gt;With so many of these interview podcasts aiming to feel like a sort of conversation, a natural question for us to help elucidate their purpose might be “why should somebody listen to such a podcast instead of having a conversation of their own?” Surely it would be more engaging to be part of the conversation rather than a passive observer to it, and that would in turn help you learn more. Well, there are a few obvious difficulties with that, mostly centered around scale.&lt;/p&gt;
&lt;p&gt;Many of the most exciting guests with interesting knowledge and experience are in high demand. We can’t all get our turn talking to the CEO of the most valuable company on the planet. However, if one person records their conversation with him to a podcast, then all of us can listen in. Additionally, if we’re all going to hear that same conversation, then it becomes worth the host’s time to prepare well: reading up on relevant context and planning out good questions that will result in hearing better stories. Maybe this lets all of us get access to a better dialogue than we would have had ourselves.&lt;/p&gt;
&lt;h2 id=&quot;the-platonic-ideal&quot;&gt;The Platonic Ideal&lt;/h2&gt;
&lt;p&gt;Still, there is a way in which the best version of this for me as an audience member is one close to the conversation I might’ve had myself if I had the same level of access to guests and time to prepare for interviewing them. I synthesize information best when I am actively working with it. So in much the same way as I felt the best way to listen to lectures in college was to try and constantly predict where the next five minutes would go and what conclusions would be drawn, I like to listen to podcasts by silently looking for holes in the explanations and arguments given, or connections to other interests.&lt;/p&gt;
&lt;p&gt;That is to say, during a lot of my listening I am effectively considering what questions I might ask, or where I might take the conversation if I were the host. So there’s a special joy I get, when in fact a podcast’s host has the same curiosity as I do (or that I would, if only I had the same level of preparation). In these cases they are able to explore that idea and get the answers for me. In doing so, they are getting as close as possible to the world in which I actually got to have these conversations. In contrast, when they go on tangents I don’t care about, or prevent the guest from exploring something interesting, that gets further away.&lt;/p&gt;
&lt;h2 id=&quot;the-ezra-klein-show&quot;&gt;The Ezra Klein Show&lt;/h2&gt;
&lt;p&gt;For me, the podcast host who comes closest to this ideal is Ezra Klein. He clearly &lt;a href=&quot;https://howiwrite.substack.com/p/ezra-klein-the-case-against-writing&quot;&gt;does the reading&lt;/a&gt;, and can engage meaningfully with guests across a variety of topics (even if that makes it a pity that so much of his content is now focused just on politics). Quite reliably, when a guest says something interesting that I’d want to tug on more, or something questionable that I’d want to challenge, he’s there first, able to channel the conversation in the direction I’d like it to go. Maybe this is just another way of saying that I think Ezra is smart.&lt;/p&gt;
&lt;p&gt;However, just as important to me as this in creating a good listening experience is that he’s empathetic. He’s empathetic to the listener, making sure to define terms and bring in context explicitly, even if he and the guest are both familiar with them. He’s also empathetic to the guest, clearly trying to feel out what they’re interested in talking about. As a rule of thumb, he almost never seems to object to the same thing more than once. Sometimes a guest will say something nonsensical that he pushes back on, and the guest will find themselves repeating their original position, or unable to respond properly. In these cases, rather than pressing the point to win the argument and expose them as inconsistent, Ezra just moves on, keeping the guest comfortable and allowing the audience to see that on their own. Although my monkey brain sometimes wants the confrontation, in retrospect I’m always glad to be able to spend more time on what the guest is thoughtful and has good points about rather than sticking in the areas where they are wrong and should be ignored.&lt;/p&gt;
&lt;h2 id=&quot;returning-to-dwarkesh&quot;&gt;Returning to Dwarkesh&lt;/h2&gt;
&lt;p&gt;Dwarkesh clearly also puts in the research time, talking in &lt;a href=&quot;https://www.dwarkesh.com/p/michael-nielsen&quot;&gt;a recent episode&lt;/a&gt; about how he wishes he could be tested on the topics to cement his learning. However, it is in this second aspect where he sometimes falls short. He self-admits to often playing devil’s advocate, which can be a fine conversational device, but sometimes leads to the conversations getting stuck: where there is fundamental disagreement between him and the guest, or something he wants the guest to say more on or acknowledge, which they are unwilling to do. In the aforementioned Jensen interview, he spends nearly 40 minutes trying repeatedly to get Jensen to say that giving China more compute is dangerous. In these cases, it feels like I am denied the ability to explore the full space of the guest’s mind and ideas because we must devote so much time to this focus of Dwarkesh’s.&lt;/p&gt;
&lt;p&gt;When people have tried to explain to me the appeal of Lex Fridman, they often say something quite close to this: that he acts as an unthreatening blank slate, in a way that is attractive to guests and allows them to get out their ideas without being obstructed. While I appreciate Dwarkesh’s ability to be an engaged host, and think this produces a better result than just a monologue, it’s possible there’s something to this. Maybe he too can eventually find a middle path that produces a better product for the audience even if it wins fewer debates decisively. The art of podcasting is largely about extracting from each guest the stories and knowledge only they can give, and a concession forced out of them by the host can’t be that.&lt;/p&gt;</content:encoded></item><item><title>Post-Penultimate Conditional Syntax</title><link>https://joel.place/blog/conditionals/</link><guid isPermaLink="true">https://joel.place/blog/conditionals/</guid><description>Reinventing Boolean Logic for Pattern Matching</description><pubDate>Sat, 04 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In the control flow of many programming languages, there exists a sort of divide between boolean &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; conditionals and pattern &lt;code&gt;match&lt;/code&gt;ing statements&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; which may bind values for future reference. In choosing syntax for &lt;a href=&quot;/mox&quot;&gt;my own language&lt;/a&gt;, I wanted to see if I could unify these two. Here lie my attempts at creating an ideal conditional syntax.&lt;/p&gt;
&lt;h2 id=&quot;prior-art&quot;&gt;Prior Art&lt;/h2&gt;
&lt;p&gt;Existing languages have often noticed this distinction and made some effort to bridge the gap and allow one construction to better cover scenarios that might ordinarily require the other. Let’s start with my two primary inspirations: OCaml and Rust.&lt;/p&gt;
&lt;h3 id=&quot;ocaml-putting-if-in-match&quot;&gt;OCaml: Putting &lt;code&gt;if&lt;/code&gt; in &lt;code&gt;match&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;As an ML-family language, OCaml tends to treat &lt;code&gt;match&lt;/code&gt; as the primary conditional.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; To permit that, it provides &lt;code&gt;match&lt;/code&gt; some of the flexibility of &lt;code&gt;if&lt;/code&gt; by introduction of the &lt;code&gt;when&lt;/code&gt; clause, which adds a conditional that must be met in order for a branch to be taken. This lets us write something like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; rec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;has_repeated_pair&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; has_repeated_pair rest&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where we have a single expressive top-level conditional which lists out the possible cases. Meanwhile, if we had to use purely ordinary &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;match&lt;/code&gt; we might be forced to instead write&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; rec &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;has_repeated_pair&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rest &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;      true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;      has_repeated_pair (y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; rest)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;having to increase our indentation and nest the logic a bit. This isn’t so painful for such a small function, but you can imagine that the complexity felt compounds in real logic. These are the sorts of inconveniences we’ll try to avoid today.&lt;/p&gt;
&lt;p&gt;However, this syntax has clear limitations. First, one can do no additional binding or pattern matching after the &lt;code&gt;when&lt;/code&gt;, which means that we might still be required to nest for something as simple as this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pipelined&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f1 x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e1 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f2 y &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; z &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;       ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or in any equivalent case where further computation requires new bindings.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Second, and more dangerously, these &lt;code&gt;when&lt;/code&gt; clauses actually make the language unsound, such that this code will compile without any warnings, but then crash on &lt;code&gt;ref false&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; impure_guard&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; bool&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; ref) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { contents &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; (* compiler believes this covers the true case *)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; when&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; (x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; (* mutates x *)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { contents &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#6A737D&quot;&gt; (* compiler believes this covers the false case *)&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; ()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A key feature of &lt;code&gt;match&lt;/code&gt; statements is their ability to check exhaustiveness, ensuring that they cover all possible cases. Doing so is complicated when there might be arbitrary mutating functions in the middle. Clearly this is not yet a perfect solution, so let’s see how Rust, as a newer language, approached it with the benefit of hindsight.&lt;/p&gt;
&lt;h3 id=&quot;rust-putting-match-in-if&quot;&gt;Rust: Putting &lt;code&gt;match&lt;/code&gt; in &lt;code&gt;if&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Rust is somewhat more imperative and systems-focused, so it approaches from the opposite direction, treating &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; as primary, and giving them some of the power of &lt;code&gt;match&lt;/code&gt; by way of the &lt;code&gt;if let&lt;/code&gt; statement. This allows &lt;code&gt;let&lt;/code&gt; to be used not just as a way to deterministically bind to expressions, but also act as a conditional for whether a pattern can be bound:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; if_let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; deterministic&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; conditional&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This adds some complication to the language. Now, depending on the surrounding context, &lt;code&gt;let&lt;/code&gt; may or may not be an expression of type &lt;code&gt;bool&lt;/code&gt;. It also reads backwards relative to the dataflow, where you first compute a value and then inspect it. Nonetheless, it does neatly resolve the sort of pipelining we discussed earlier without nesting:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pipelined_1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; f1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    &amp;#x26;&amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(z) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; f2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    } &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At least, it does so long as we are alright treating errors in &lt;code&gt;f1&lt;/code&gt; and &lt;code&gt;f2&lt;/code&gt; as equivalent, which may not always hold. We’ve been able to clean up the happy path, but haven’t really represented all branches well in our conditional. To achieve that, we might try yet another Rust feature, the &lt;code&gt;let ... else&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;fn&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; pipelined_2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; T&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; f1&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(x) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // must diverge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    let&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(z) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; f2&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;        // must diverge&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These represent a conditional where the happy path can be raised to the top level because the other branches must &lt;code&gt;return&lt;/code&gt; early or otherwise can never resume the rest of the function. They let us handle the two kinds of errors differently, but still don’t actually let us inspect &lt;code&gt;e1&lt;/code&gt; or &lt;code&gt;e2&lt;/code&gt; in our failure case. We haven’t really accessed the full &lt;code&gt;match&lt;/code&gt;-like power to destructure the &lt;code&gt;Result&amp;#x3C;T, E&gt;&lt;/code&gt; type and say “&lt;code&gt;f1(x)&lt;/code&gt; is either &lt;code&gt;Ok(_)&lt;/code&gt; or &lt;code&gt;Err(_)&lt;/code&gt;”, let alone handle cases with more possible branches or without a single happy path.&lt;/p&gt;
&lt;p&gt;Rust has identified some of the most common patterns and created syntactic sugar that works well for those specialized cases. However, with so many different syntactic structures punning the same keywords and not yet covering the general case, we haven’t yet found my desired simplicity. We’ll have to venture further to the world of niche languages.&lt;/p&gt;
&lt;h3 id=&quot;ultimate-conditional-syntax&quot;&gt;Ultimate Conditional Syntax&lt;/h3&gt;
&lt;p&gt;So I wandered the &lt;a href=&quot;https://dotat.at/@/2025-05-13-if-is.html&quot;&gt;blogosphere&lt;/a&gt; and came upon the &lt;a href=&quot;https://dl.acm.org/doi/10.1145/3689746&quot;&gt;Ultimate Conditional Syntax (UCS)&lt;/a&gt;, which appeared to be about the state of the art in unifying these concerns into a simple syntax. It introduces two keywords to a toy language: &lt;code&gt;is&lt;/code&gt; and &lt;code&gt;and&lt;/code&gt;. In the spirit of these coming from a proper paper, let me try and give them proper definitions.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;expression is pattern&lt;/code&gt; is a boolean expression. More specifically, it is the expression that evaluates to &lt;code&gt;true&lt;/code&gt; if and only if &lt;code&gt;pattern&lt;/code&gt; binds to &lt;code&gt;expression&lt;/code&gt;. This means that in contexts where we learn it is true, we can use those bindings in our environment:&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    do_something x&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We gain extra bindings inside the &lt;code&gt;if&lt;/code&gt;, analogous to how we might gain some type unification when matching on a GADT. This functions in an equivalent manner to Rust’s &lt;code&gt;if let ...&lt;/code&gt;, but I appreciate having a new keyword to distinguish it. &lt;code&gt;and&lt;/code&gt;, meanwhile, is perhaps best understood by example.&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) and y is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(z) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;can be viewed as syntactic sugar for the following:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(y) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;  if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; y is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Some&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(z) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    expression3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is, of course, how boolean &lt;code&gt;and&lt;/code&gt; or &lt;code&gt;&amp;#x26;&amp;#x26;&lt;/code&gt; operates under the hood in many languages that permit short-circuiting: skipping evaluation of the right hand side if the left turns out to be &lt;code&gt;false&lt;/code&gt;. However, it is worth emphasizing that this is truly a kind of control flow that deserves a keyword, and nothing like other infix operators that evaluate both their operands before applying some function.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-5&quot; id=&quot;user-content-fnref-5&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; Additionally, this means that it has special interactions with &lt;code&gt;is&lt;/code&gt; expressions.&lt;/p&gt;
&lt;p&gt;In order for us to even begin evaluating the right side, it must be the case that the left side was &lt;code&gt;true&lt;/code&gt;. Meaning that we can use any of its bindings in evaluating the right side. Likewise, we can use both of their bindings inside the &lt;code&gt;if&lt;/code&gt;, which makes sense since &lt;code&gt;and&lt;/code&gt; gives the expression that is &lt;code&gt;true&lt;/code&gt; if and only if both of its operands are &lt;code&gt;true&lt;/code&gt;, and here our operands use &lt;code&gt;is&lt;/code&gt; which binds when that occurs.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-6&quot; id=&quot;user-content-fnref-6&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;To me, this felt like a pretty strong start towards the goal of giving &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; the power of &lt;code&gt;match&lt;/code&gt;, tightening up Rust’s &lt;code&gt;let&lt;/code&gt;-chains. Sure, it was still missing &lt;code&gt;match&lt;/code&gt;’s exhaustiveness check and ability to combine branches, but we could build up to those. That made it all the more disappointing to me when the paper re-introduced a &lt;code&gt;match&lt;/code&gt;-like construct for these:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ok)   &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err) &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sure, they reused the keywords &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;is&lt;/code&gt; to build it, but what I was searching for was not just keyword punning: I wanted to see if I could merge the language constructs properly. As it is here, we’ve introduced confusion about whether &lt;code&gt;is&lt;/code&gt; should be followed by a pattern to conditionally bind to and evaluate to a boolean, or a list of cases to exhaustively enter one of, and the remainder of the paper is forced to tackle the complexity of disambiguating during compilation.&lt;/p&gt;
&lt;h2 id=&quot;post-penultimate-conditional-syntax&quot;&gt;Post-Penultimate Conditional Syntax&lt;/h2&gt;
&lt;p&gt;I’d like to resume where UCS left off, which I suppose forces me to adopt a ridiculous name like Post-Penultimate Conditional Syntax.&lt;/p&gt;
&lt;h3 id=&quot;or-patterns&quot;&gt;OR Patterns&lt;/h3&gt;
&lt;p&gt;One simple thing I’d like to be able to recreate from &lt;code&gt;match&lt;/code&gt; statements is the ability to merge branches that would create the same bindings:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ last ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; last ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; last ] &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; f last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; ::&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; failwith &lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;more than 3 elements&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’d be substantially more verbose if each &lt;code&gt;|&lt;/code&gt;-separated pattern needed its own case:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list is [ last ] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    f last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list is [ _, last ] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    f last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list is [ _, _, last ] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    f last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    panic!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;more than 3 elements&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To do the same in our world of boolean logic, we’d have to introduce an &lt;code&gt;or&lt;/code&gt; operator&lt;sup&gt;&lt;a href=&quot;#user-content-fn-7&quot; id=&quot;user-content-fnref-7&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;, which we could think of as syntactic sugar for the former. After all, a short-circuiting &lt;code&gt;or&lt;/code&gt; would execute the second operand only if the first was &lt;code&gt;false&lt;/code&gt;, just like an &lt;code&gt;else&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; list is [ last ] or list is [ _, last ] or list is [ _, _, last ] {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    f last&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;    panic!&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#9ECBFF&quot;&gt;&quot;more than 3 elements&quot;&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Where &lt;code&gt;and&lt;/code&gt; was the operator that, when &lt;code&gt;true&lt;/code&gt;, gave the union of all bindings from its operands (since they must both be &lt;code&gt;true&lt;/code&gt;), &lt;code&gt;or&lt;/code&gt; would be the operator that, when &lt;code&gt;true&lt;/code&gt;, gives the intersection of its operands’ bindings&lt;sup&gt;&lt;a href=&quot;#user-content-fn-8&quot; id=&quot;user-content-fnref-8&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;8&lt;/a&gt;&lt;/sup&gt;, since at least one must be &lt;code&gt;true&lt;/code&gt;, but we can’t assume that it’s any specific one.&lt;/p&gt;
&lt;h3 id=&quot;exhaustiveness&quot;&gt;Exhaustiveness&lt;/h3&gt;
&lt;p&gt;Now perhaps more intimidating, the ability of the compiler to check exhaustiveness of some conditional, ensuring that it will always enter some branch, is very important to &lt;code&gt;match&lt;/code&gt;. In particular, it is what allows it to be an expression with a non-unit type, otherwise there’d always be a risk we didn’t enter any branch and didn’t know what value to use.&lt;/p&gt;
&lt;p&gt;To rephrase that a little bit, we could say the thing an exhaustiveness checker needs to prove is that “conditional on not having entered any of the prior branches, we are guaranteed to enter the last branch”. And as it turns out, in curly-brace syntax there’s some unused space in the &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; construct where we could put just that information:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(ok) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, when an expression &lt;code&gt;e&lt;/code&gt; comes after &lt;code&gt;else&lt;/code&gt;, the exhaustiveness checker must be able to prove that, if we were to reach the &lt;code&gt;else&lt;/code&gt;, then &lt;code&gt;e&lt;/code&gt; must evaluate to &lt;code&gt;true&lt;/code&gt;. This is identical to what we’d have to prove in a &lt;code&gt;match&lt;/code&gt;, doing casework on the scrutinee(s), which are inferred from the expression behind the &lt;code&gt;else&lt;/code&gt; rather than stated up-front. Now we can even combine to write things like&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; query_result is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(info) or (retry_allowed and &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;do_retry&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(info)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; query_result is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(err) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;putting-it-all-together&quot;&gt;Putting It All Together&lt;/h3&gt;
&lt;p&gt;So we’ve now got&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A judgement we can make about expressions, in which we say they produce some bindings when they are evaluated to &lt;code&gt;true&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;is&lt;/code&gt; keyword, which serves as the basis for expressions which we can make such judgements about.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;and&lt;/code&gt; and &lt;code&gt;or&lt;/code&gt; keywords, which compose these using union and intersection respectively.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; keywords, which allow us to unpack and use those bindings and check exhaustiveness.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I’m pretty happy with unification and the way it recreates seemingly particular features in a single coherent system by grounding itself in an algebra. One could even imagine introducing a &lt;code&gt;not&lt;/code&gt; keyword, which inverts whether expressions form bindings on &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;. Combined with analysis that a block must exit early (&lt;code&gt;return&lt;/code&gt;, &lt;code&gt;break&lt;/code&gt;, etc.) this would recover Rust’s &lt;code&gt;let ... else&lt;/code&gt; guards, but feel like a natural extension rather than additional distinct syntax for newcomers to learn. Before we get too excited though, let’s think about a couple of concerns.&lt;/p&gt;
&lt;h3 id=&quot;concerns&quot;&gt;Concerns&lt;/h3&gt;
&lt;h4 id=&quot;unsoundness&quot;&gt;Unsoundness&lt;/h4&gt;
&lt;p&gt;To start with something familiar, earlier I brought up how OCaml matches could be made unsound by using &lt;code&gt;when&lt;/code&gt; clauses with functions that had the side effect of mutating the values being matched on. One could imagine a system like this in which exhaustivity checks are less clearly contained to lead to more common issues of this kind.&lt;/p&gt;
&lt;p&gt;Indeed, I would not recommend this syntax to OCaml, which has historically been able to permit mutation without constraint due to its single-threaded runtime.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-9&quot; id=&quot;user-content-fnref-9&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;9&lt;/a&gt;&lt;/sup&gt; Luckily, however, Rust-like languages already solve this by requiring that functions annotate whether they mutate their arguments. Any mutation then invalidates the compiler’s notion that it has already covered some cases, preventing the unsoundness.&lt;/p&gt;
&lt;h4 id=&quot;ergonomics&quot;&gt;Ergonomics&lt;/h4&gt;
&lt;p&gt;Probably the bigger thing you’ve been noticing though, is how this system can sometimes be more verbose than the kind of &lt;code&gt;match&lt;/code&gt; statements you’re used to. It forces you to name intermediaries and then repeat their name in each &lt;code&gt;is&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;  big_computation&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    many,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    long,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    arguments);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(_) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;whereas a standard &lt;code&gt;match&lt;/code&gt; might have allowed you to write just&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;match&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;  big_computation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    many&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    long&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;    arguments&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ....&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Indeed, for the case of a single computation which acts as the scrutinee in a conditional with many cases, we cannot be more concise than syntax specifically designed for that scenario. That is even a sufficiently common situation to perhaps warrant the retention of a &lt;code&gt;match&lt;/code&gt; or similar statement. However, that is not all cases, and our familiarity with it as the standard may force the paradigm into cases where it doesn’t make sense. E.g., if we wrote in this new syntax&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result1 is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(val) or result2 is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Ok&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(val) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;} &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;else&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result1 is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e1) and result2 is &lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Err&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;(e2) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to fit it into a &lt;code&gt;match&lt;/code&gt; we might have previously written&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;ocaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;match&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; result2 &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; val,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Ok&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; val&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; -&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Error&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; e2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This encodes the same idea, and may even be more ergonomic, but it suggests the wrong semantics. In OCaml, the creation of a tuple to use as a scrutinee should theoretically incur a heap allocation, as all values bigger than one word are boxed. Meanwhile in Rust, the creation of the tuple (assuming it is owned) should theoretically incur a move of the results into a new segment of stack memory. Neither of these costs should be necessary when we can just inspect the results directly. The clever compilers can probably optimize both of them away, but isn’t it better for clarity if our syntax represents the logic we expect directly?&lt;/p&gt;
&lt;p&gt;I would even argue that the discipline of naming intermediaries can make the code easier to read, as you never need to scroll up from a case to see what was initially matched on. So I’m going to continue experimenting with unifying conditionals entirely and leaving &lt;code&gt;match&lt;/code&gt; out.&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;Or &lt;code&gt;switch&lt;/code&gt; for those coming from algebraically deficient languages &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;Some, including me when writing OCaml, even believe in matching on &lt;code&gt;bool&lt;/code&gt;s to eschew any use of &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt; in the language. &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;Of course in this particular monadic case we just match on &lt;code&gt;Or_error.(f1 x &gt;&gt;= f2)&lt;/code&gt;, but that might not be friendlier to newcomers and doesn’t always apply. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;I’m using Rust-like syntax here in place of the ML-like syntax in the paper, but otherwise retaining the constructs. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-5&quot;&gt;
&lt;p&gt;At least outside of lazy languages like Haskell where short-circuiting can be replicated within normal operators. &lt;a href=&quot;#user-content-fnref-5&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 5&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-6&quot;&gt;
&lt;p&gt;If I were a proper theorist here’s where I’d start defining judgements for this notion of bindings conditional upon being true, but I don’t want to scare anyone away with symbols. &lt;a href=&quot;#user-content-fnref-6&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 6&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-7&quot;&gt;
&lt;p&gt;I do not mean to claim this as entirely novel, and I’ve seen discussions of logical or e.g. &lt;a href=&quot;https://blog.yoshuawuyts.com/syntactic-musings-on-match-expressions/#logical-or&quot;&gt;in Rust&lt;/a&gt; if not in UCS. &lt;a href=&quot;#user-content-fnref-7&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 7&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-8&quot;&gt;
&lt;p&gt;Conditional on unifying the types of each pair of intersected bindings. &lt;code&gt;and&lt;/code&gt; likewise has complications when intersections exist between its bindings. &lt;a href=&quot;#user-content-fnref-8&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 8&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-9&quot;&gt;
&lt;p&gt;This has changed in OCaml 5, but the safety story isn’t as developed as Rust, leading to offshoots like &lt;a href=&quot;https://oxcaml.org/&quot;&gt;OxCaml&lt;/a&gt;. &lt;a href=&quot;#user-content-fnref-9&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 9&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item><item><title>The &quot;Billion Dollar Mistake&quot; Lives On in Rust</title><link>https://joel.place/blog/billion-dollar-mistake-lives-on/</link><guid isPermaLink="true">https://joel.place/blog/billion-dollar-mistake-lives-on/</guid><description>Why the Default Trait Is an Anti-Pattern</description><pubDate>Tue, 17 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Tony Hoare famously calls the invention of &lt;code&gt;NULL&lt;/code&gt; pointers to serve as a kind of universal empty or invalid value his “billion dollar mistake.” This unfortunate choice has since been reflected on by many modern languages, which have introduced various kinds of &lt;a href=&quot;https://doc.rust-lang.org/std/option/&quot;&gt;optionals&lt;/a&gt; to their type systems. These annotate when values may be absent and encourage programmers to handle that case gracefully. Some compilers even provide &lt;a href=&quot;https://www.noahlev.org/papers/popl22src-filling-a-niche.pdf&quot;&gt;niche optimizations&lt;/a&gt; to make these zero-cost!&lt;/p&gt;
&lt;p&gt;So, problem solved, right? Well, not so fast. I’ll argue here that the same mindset that infected so many early programming languages lives on, even in communities as focused on type safety as the Rustaceans are. To do that, let’s first talk about what exactly made &lt;code&gt;NULL&lt;/code&gt; so insidious.&lt;/p&gt;
&lt;h2 id=&quot;whats-wrong-with-null&quot;&gt;What’s Wrong With &lt;code&gt;NULL&lt;/code&gt;?&lt;/h2&gt;
&lt;p&gt;You see, it’s not just the fact that you could produce undefined behavior by dereferencing &lt;code&gt;*NULL&lt;/code&gt; in C, or that you’d hit &lt;code&gt;NullPointerException&lt;/code&gt; calling methods on it in Java: the ability for code to fail by requiring valid data is alive and well in Rust’s &lt;code&gt;unwrap&lt;/code&gt;, which panics upon encountering &lt;code&gt;None&lt;/code&gt;. No, &lt;code&gt;NULL&lt;/code&gt;’s true problem is much more sinister.&lt;/p&gt;
&lt;p&gt;See, the issue with &lt;code&gt;NULL&lt;/code&gt; is that it corrupts the type system: it is a valid value for any pointer type, no matter what sort of data that type is supposed to represent. In doing so, it makes it impossible to express the idea of a value that is guaranteed not to be in this problematic exceptional state. A type theorist would say that a type is the set of possible values it can take, and &lt;code&gt;NULL&lt;/code&gt; was required to be placed in every set. By granting it this universal power we forced ourselves to constantly worry “could that be &lt;code&gt;NULL&lt;/code&gt;?”&lt;/p&gt;
&lt;p&gt;But gosh was it convenient: for any type, no matter how big or small, we had a way to express an empty, invalid, or uninitialized state. That’s super common to want to reason about, and it’s convenient for that not to require a wrapper which changes the type. Who hasn’t reached a point in Rust code where they knew their value would be &lt;code&gt;Some&lt;/code&gt; - and wouldn’t just being able to use the value be more concise and no less safe than &lt;code&gt;unwrap&lt;/code&gt;? Why would we have the function if those cases weren’t common?&lt;/p&gt;
&lt;h2 id=&quot;introducing-default&quot;&gt;Introducing &lt;code&gt;Default&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Well, some folks seem to have found a way to have their cake and eat it too. Allow me to introduce you to the &lt;code&gt;Default&lt;/code&gt; trait:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;pub&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt; trait&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Sized&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;    fn&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#79B8FF&quot;&gt; Self&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seemingly innocuous enough, this trait consists of a single function which gives a sane default value for your type. E.g., &lt;code&gt;Vec::default()&lt;/code&gt; will give us an empty vector. Don’t want to deal with the possibility your key isn’t present? Try &lt;code&gt;map.entry().or_default()&lt;/code&gt;.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-1&quot; id=&quot;user-content-fnref-1&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Bored when initializing your long struct? Try&lt;/p&gt;
&lt;pre class=&quot;astro-code github-dark&quot; style=&quot;background-color:#24292e;color:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;rust&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F97583&quot;&gt;let&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; x &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt; Large&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; { field1&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; a, field2&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt; b, &lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;..&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;Default&lt;/span&gt;&lt;span style=&quot;color:#F97583&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#B392F0&quot;&gt;default&lt;/span&gt;&lt;span style=&quot;color:#E1E4E8&quot;&gt;() }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My coworkers are even in the habit of checks like &lt;code&gt;if x == Default::default()&lt;/code&gt; (literally using it as a kind of &lt;code&gt;NULL&lt;/code&gt;-check like they might have in other languages). Note how &lt;code&gt;Default::default()&lt;/code&gt;, like &lt;code&gt;NULL&lt;/code&gt;, is a sort of universal value that works as a placeholder on any type (that implements &lt;code&gt;Default&lt;/code&gt;, as most types are encouraged to&lt;sup&gt;&lt;a href=&quot;#user-content-fn-2&quot; id=&quot;user-content-fnref-2&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;).&lt;/p&gt;
&lt;h2 id=&quot;is-default-better&quot;&gt;Is &lt;code&gt;Default&lt;/code&gt; Better?&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Default&lt;/code&gt; seems to have recovered some of &lt;code&gt;NULL&lt;/code&gt;’s utility as an empty value that we can change to something substantive later, but without our big pain points:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;It always gives a proper value of its type, and so can generally be used without just propagating failure like &lt;code&gt;NullPointerException&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;That means it has not introduced an additional value to types which implement it, so the types retain their expected set of possible values and we need not always check for a special case.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;But if not a special value that’s a member of every type, then what value, pray tell, will be the default? Well let’s start with the simple case of integers. Their default value is zero. Is that sensible?&lt;/p&gt;
&lt;p&gt;Well it would depend on the use.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-3&quot; id=&quot;user-content-fnref-3&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Integers are commonly used as counters, or to sum values, and zero is the additive identity, so in those cases it probably works well. But if you’re instead multiplying numbers, you’d probably want one as your identity, and if you’re not doing math at all, but recording some other metric with interesting meaning, maybe neither would be safe to use in general? However, since traits are defined uniquely per type, &lt;code&gt;Default&lt;/code&gt; can never be specific to its situation and must attempt to capture all possible uses.&lt;/p&gt;
&lt;h2 id=&quot;is-default-worse&quot;&gt;Is &lt;code&gt;Default&lt;/code&gt; Worse?&lt;/h2&gt;
&lt;p&gt;It cannot really do that of course, and so often the most you can say about a default value is that it is a legal member of the type, and you’ll be tasked with turning it into something meaningful on your own. This is all to say, that often &lt;code&gt;Default&lt;/code&gt; can take the place of uninitialized data: that which the programmer is required to overwrite later with something meaningful.&lt;sup&gt;&lt;a href=&quot;#user-content-fn-4&quot; id=&quot;user-content-fnref-4&quot; data-footnote-ref=&quot;&quot; aria-describedby=&quot;footnote-label&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; And now just like with &lt;code&gt;NULL&lt;/code&gt;, we have escaped the type system, which cannot hope to tell us whether we appropriately overwrote our default value, or whether it may still be lurking as garbage in any of our values.&lt;/p&gt;
&lt;p&gt;In fact, I’d almost say this can be more dangerous. While &lt;code&gt;NULL&lt;/code&gt;s were prone to fail fast and loudly, uninitialized values guaranteed to be valid are much sneakier: they can hide out in your codebase and function mostly adequately, until one day you discover your application logic’s output is subtly wrong. This is explicitly counter to Rust’s usual philosophy, exposing errors in the compiler if possible, or otherwise at least tending to panic loudly rather than permit undefined behavior. While no longer in the same form, &lt;code&gt;Default&lt;/code&gt; has reintroduced semantically meaningless values that the type system cannot protect us from.&lt;/p&gt;
&lt;h2 id=&quot;takeaways&quot;&gt;Takeaways&lt;/h2&gt;
&lt;p&gt;Using &lt;code&gt;Default&lt;/code&gt; in Rust can genuinely make your code more concise and easier to write, which I do not mean to belittle. This is of course, not unlike &lt;code&gt;NULL&lt;/code&gt; pointers in other languages. Nonetheless, outside of quick prototypes, most code is read many more times than it is written, and so the reader should usually be prioritized.&lt;/p&gt;
&lt;p&gt;As a reader, when I see &lt;code&gt;Default::default()&lt;/code&gt;, the main takeaway I get is that the writer didn’t care about the value it produces. If it were meaningful to the writer that the integer were zero, or that the set was empty, let alone any other less common type, they should have told me what that value is: if only because I might not have memorized what its default was.&lt;/p&gt;
&lt;p&gt;Furthermore, I would generally argue that having data you don’t care about is an anti-pattern. If it’s in your code, it should mean something! So next time you’re initializing: consider being explicit, tell me what is the right default for you in your particular use case.&lt;/p&gt;
&lt;section data-footnotes=&quot;&quot; class=&quot;footnotes&quot;&gt;&lt;h2 class=&quot;sr-only&quot; id=&quot;footnote-label&quot;&gt;Footnotes&lt;/h2&gt;
&lt;ol&gt;
&lt;li id=&quot;user-content-fn-1&quot;&gt;
&lt;p&gt;I’ve got a separate gripe that it’s not sufficiently explicit that this is a mutating operation, which inserts the result of &lt;code&gt;Default::default()&lt;/code&gt; into &lt;code&gt;map&lt;/code&gt;. &lt;a href=&quot;#user-content-fnref-1&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 1&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-2&quot;&gt;
&lt;p&gt;There’s even a standard linter rule against types having a &lt;code&gt;new()&lt;/code&gt; without implementing &lt;code&gt;Default&lt;/code&gt;! &lt;a href=&quot;#user-content-fnref-2&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 2&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-3&quot;&gt;
&lt;p&gt;So despite all my grumbling about &lt;code&gt;entry().or_default()&lt;/code&gt;, I think something like Python’s &lt;code&gt;defaultdict&lt;/code&gt; where you define a specific default value within some dictionary where you know its use is totally fine. &lt;a href=&quot;#user-content-fnref-3&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 3&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;user-content-fn-4&quot;&gt;
&lt;p&gt;It would of course be wrong to say they’re truly uninitialized as in C: the initialization is deterministic, just not set meaningfully by the programmer. &lt;a href=&quot;#user-content-fnref-4&quot; data-footnote-backref=&quot;&quot; aria-label=&quot;Back to reference 4&quot; class=&quot;data-footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content:encoded></item></channel></rss>