<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://batsov.com/feeds/Clojure.xml" rel="self" type="application/atom+xml" /><link href="https://batsov.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-03-11T23:32:49+02:00</updated><id>https://batsov.com/feeds/Clojure.xml</id><title type="html">(think)</title><subtitle>Bozhidar Batsov&apos;s personal blog</subtitle><entry><title type="html">Building Emacs Major Modes with Tree-sitter: Lessons Learned</title><link href="https://batsov.com/articles/2026/02/27/building-emacs-major-modes-with-treesitter-lessons-learned/" rel="alternate" type="text/html" title="Building Emacs Major Modes with Tree-sitter: Lessons Learned" /><published>2026-02-27T10:00:00+02:00</published><updated>2026-02-27T10:00:00+02:00</updated><id>https://batsov.com/articles/2026/02/27/building-emacs-major-modes-with-treesitter-lessons-learned</id><content type="html" xml:base="https://batsov.com/articles/2026/02/27/building-emacs-major-modes-with-treesitter-lessons-learned/"><![CDATA[<p>Over the past year I’ve been spending a lot of time building <a href="https://tree-sitter.github.io/tree-sitter/">Tree-sitter</a>-powered
major modes for Emacs – <a href="https://github.com/clojure-emacs/clojure-ts-mode">clojure-ts-mode</a>
(as co-maintainer), <a href="https://github.com/bbatsov/neocaml">neocaml</a> (from scratch),
and <a href="https://github.com/bbatsov/asciidoc-mode">asciidoc-mode</a> (also from scratch).
Between the three projects I’ve accumulated enough knowledge (and battle scars) to write about the
experience. This post distills the key lessons for anyone thinking about writing
a Tree-sitter-based major mode, or curious about what it’s actually like.</p>

<!--more-->

<h2 id="why-tree-sitter">Why Tree-sitter?</h2>

<p>Before Tree-sitter, Emacs font-locking was done with regular expressions and
indentation was handled by ad-hoc engines (SMIE, custom indent functions, or
pure regex heuristics). This works, but it has well-known problems:</p>

<ul>
  <li>
    <p><strong>Regex-based font-locking is fragile.</strong> Regexes can’t parse nested structures,
so they either under-match (missing valid code) or over-match (highlighting
inside strings and comments). Every edge case is another regex, and the patterns
become increasingly unreadable over time.</p>
  </li>
  <li>
    <p><strong>Indentation engines are complex.</strong> SMIE (the generic indentation engine for non-Tree-sitter modes) requires defining operator
precedence grammars for the language, which is hard to get right. Custom
indentation functions tend to grow into large, brittle state machines. Tuareg’s
indentation code, for example, is thousands of lines long.</p>
  </li>
</ul>

<p>Tree-sitter changes the game because you get a <strong>full, incremental, error-tolerant
syntax tree</strong> for free. Font-locking becomes “match this AST pattern, apply this
face”:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1">;; Highlight let-bound functions: match a let_binding with parameters</span>
<span class="p">(</span><span class="nv">let_binding</span> <span class="nv">pattern:</span> <span class="p">(</span><span class="nv">value_name</span><span class="p">)</span> <span class="nv">@font-lock-function-name-face</span>
             <span class="p">(</span><span class="nv">parameter</span><span class="p">)</span><span class="nb">+</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And indentation becomes “if the parent node is X, indent by Y”:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c1">;; Children of a let_binding are indented by neocaml-indent-offset</span>
<span class="p">((</span><span class="nv">parent-is</span> <span class="s">"let_binding"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="nv">neocaml-indent-offset</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The rules are declarative, composable, and much easier to reason about than
regex chains.</p>

<p>In practice, <code class="language-plaintext highlighter-rouge">neocaml</code>’s entire font-lock and indentation logic fits in about 350
lines of Elisp. The equivalent in tuareg is spread across thousands of lines.
That’s the real selling point: <strong>simpler, more maintainable code that handles more
edge cases correctly</strong>.</p>

<h2 id="challenges">Challenges</h2>

<p>That said, Tree-sitter in Emacs is not a silver bullet. Here’s what I ran into.</p>

<h3 id="every-grammar-is-different">Every grammar is different</h3>

<p>Tree-sitter grammars are written by different authors with different philosophies.
The <a href="https://github.com/tree-sitter/tree-sitter-ocaml">tree-sitter-ocaml</a>
grammar provides a rich, detailed AST with named fields. The
<a href="https://github.com/sogaiu/tree-sitter-clojure">tree-sitter-clojure</a> grammar,
by contrast, deliberately keeps things minimal – it only models syntax, not
semantics, because Clojure’s macro system makes static semantic analysis
unreliable.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> This means font-locking <code class="language-plaintext highlighter-rouge">def</code> forms in Clojure requires
predicate matching on symbol text, while in OCaml you can directly match
<code class="language-plaintext highlighter-rouge">let_binding</code> nodes with named fields.</p>

<p>To illustrate: here’s how you’d fontify a function definition in OCaml, where
the grammar gives you rich named fields:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1">;; OCaml: grammar provides named fields -- direct structural match</span>
<span class="p">(</span><span class="nv">let_binding</span> <span class="nv">pattern:</span> <span class="p">(</span><span class="nv">value_name</span><span class="p">)</span> <span class="nv">@font-lock-function-name-face</span>
             <span class="p">(</span><span class="nv">parameter</span><span class="p">)</span><span class="nb">+</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And here’s the equivalent in Clojure, where the grammar only gives you lists of
symbols and you need predicate matching:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="c1">;; Clojure: grammar is syntax-only -- match by symbol text</span>
<span class="p">((</span><span class="nv">list_lit</span> <span class="ss">:anchor</span> <span class="p">(</span><span class="nv">sym_lit</span> <span class="nv">!namespace</span>
                            <span class="nv">name:</span> <span class="p">(</span><span class="nv">sym_name</span><span class="p">)</span> <span class="nv">@font-lock-keyword-face</span><span class="p">))</span>
 <span class="p">(</span><span class="ss">:match</span> <span class="o">,</span><span class="nv">clojure-ts--definition-keyword-regexp</span> <span class="nv">@font-lock-keyword-face</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can’t learn “how to write Tree-sitter queries” generically – you need to
learn each grammar individually. The best tool for this is <code class="language-plaintext highlighter-rouge">treesit-explore-mode</code>
(to visualize the full parse tree) and <code class="language-plaintext highlighter-rouge">treesit-inspect-mode</code> (to see the node
at point). Use them constantly.</p>

<h3 id="grammar-quality-varies-wildly">Grammar quality varies wildly</h3>

<p>You’re dependent on someone else providing the grammar, and quality is all over
the map. The OCaml grammar is mature and well-maintained – it’s hosted under the
official <a href="https://github.com/tree-sitter">tree-sitter</a> GitHub org. The Clojure
grammar is small and stable by design. But not every language is so lucky.</p>

<p><a href="https://github.com/bbatsov/asciidoc-mode">asciidoc-mode</a> uses a
<a href="https://github.com/cathaysia/tree-sitter-asciidoc">third-party AsciiDoc grammar</a>
that employs a dual-parser architecture – one parser for block-level structure
(headings, lists, code blocks) and another for inline formatting (bold, italic,
links). This is the same approach used by Emacs’s built-in <code class="language-plaintext highlighter-rouge">markdown-ts-mode</code>,
and it makes sense for markup languages where block and inline syntax are largely
independent.</p>

<p>The problem is that the two parsers run independently on the same text, and they
can <strong>disagree</strong>. The inline parser misinterprets <code class="language-plaintext highlighter-rouge">*</code> and <code class="language-plaintext highlighter-rouge">**</code> list markers as
emphasis delimiters, creating spurious bold spans that swallow subsequent inline
content. The workaround is to use <code class="language-plaintext highlighter-rouge">:override t</code> on all block-level font-lock
rules so they win over the incorrect inline faces:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c1">;; Block-level rules use :override t so block-level faces win over</span>
<span class="c1">;; spurious inline emphasis nodes (the inline parser misreads `*'</span>
<span class="c1">;; list markers as emphasis delimiters).</span>
<span class="ss">:language</span> <span class="ss">'asciidoc</span>
<span class="ss">:override</span> <span class="no">t</span>
<span class="ss">:feature</span> <span class="ss">'list</span>
<span class="o">'</span><span class="p">((</span><span class="nv">ordered_list_marker</span><span class="p">)</span> <span class="nv">@font-lock-constant-face</span>
  <span class="p">(</span><span class="nv">unordered_list_marker</span><span class="p">)</span> <span class="nv">@font-lock-constant-face</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This doesn’t fix inline elements consumed by the spurious emphasis – that
requires an upstream grammar fix. When you hit grammar-level issues like this,
you either fix them yourself (which means diving into the grammar’s JavaScript
source and C toolchain) or you live with workarounds. Either way, it’s a
reminder that your mode is only as good as the grammar underneath it.</p>

<p>Getting the font-locking right in <code class="language-plaintext highlighter-rouge">asciidoc-mode</code> was probably the most
challenging part of all three projects, precisely because of these grammar
quirks. I also ran into a subtle <code class="language-plaintext highlighter-rouge">treesit</code> behavior: the default font-lock mode
(<code class="language-plaintext highlighter-rouge">:override nil</code>) skips an entire captured range if <em>any</em> position within it
already has a face. So if you capture a parent node like <code class="language-plaintext highlighter-rouge">(inline_macro)</code> and a
child was already fontified, the whole thing gets skipped silently. The fix is
to capture specific child nodes instead:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="c1">;; BAD: entire node gets skipped if any child is already fontified</span>
<span class="c1">;; (inline_macro) @font-lock-function-call-face</span>

<span class="c1">;; GOOD: capture specific children</span>
<span class="p">(</span><span class="nv">inline_macro</span> <span class="p">(</span><span class="nv">macro_name</span><span class="p">)</span> <span class="nv">@font-lock-function-call-face</span><span class="p">)</span>
<span class="p">(</span><span class="nv">inline_macro</span> <span class="p">(</span><span class="nv">target</span><span class="p">)</span> <span class="nv">@font-lock-string-face</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>These issues took a lot of trial and error to diagnose. The lesson: <strong>budget
extra time for font-locking when working with less mature grammars</strong>.</p>

<h3 id="grammar-versions-and-breaking-changes">Grammar versions and breaking changes</h3>

<p>Grammars evolve, and breaking changes happen. <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> switched from
the stable grammar to the <a href="https://github.com/sogaiu/tree-sitter-clojure/tree/unstable-20250526">experimental
branch</a>
because the stable version had metadata nodes as children of other nodes, which
caused <code class="language-plaintext highlighter-rouge">forward-sexp</code> and <code class="language-plaintext highlighter-rouge">kill-sexp</code> to behave incorrectly. The experimental
grammar makes metadata standalone nodes, fixing the navigation issues but
requiring all queries to be updated.</p>

<p><code class="language-plaintext highlighter-rouge">neocaml</code> pins to
<a href="https://github.com/tree-sitter/tree-sitter-ocaml/tree/v0.24.0">v0.24.0</a> of the
OCaml grammar. If you don’t pin versions, a grammar update can silently break
your font-locking or indentation.</p>

<p>The takeaway: <strong>always pin your grammar version</strong>, and include a mechanism to
detect outdated grammars. <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> tests a query that changed between
versions to detect incompatible grammars at startup.</p>

<h3 id="grammar-delivery">Grammar delivery</h3>

<p>Users shouldn’t have to manually clone repos and compile C code to use your
mode. Both <code class="language-plaintext highlighter-rouge">neocaml</code> and <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> include grammar recipes:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">defconst</span> <span class="nv">neocaml-grammar-recipes</span>
  <span class="o">'</span><span class="p">((</span><span class="nv">ocaml</span> <span class="s">"https://github.com/tree-sitter/tree-sitter-ocaml"</span>
           <span class="s">"v0.24.0"</span>
           <span class="s">"grammars/ocaml/src"</span><span class="p">)</span>
    <span class="p">(</span><span class="nv">ocaml-interface</span> <span class="s">"https://github.com/tree-sitter/tree-sitter-ocaml"</span>
                     <span class="s">"v0.24.0"</span>
                     <span class="s">"grammars/interface/src"</span><span class="p">)))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>On first use, the mode checks <code class="language-plaintext highlighter-rouge">treesit-language-available-p</code> and offers to install
missing grammars via <code class="language-plaintext highlighter-rouge">treesit-install-language-grammar</code>. This works, but requires
a C compiler and Git on the user’s machine, which is not ideal.<sup id="fnref:2"><a href="#fn:2" class="footnote" rel="footnote" role="doc-noteref">2</a></sup></p>

<h3 id="the-emacs-tree-sitter-apis-are-a-moving-target">The Emacs Tree-sitter APIs are a moving target</h3>

<p>The Tree-sitter support in Emacs has been improving steadily, but each version
has its quirks:</p>

<p><strong>Emacs 29</strong> introduced Tree-sitter support but lacked several APIs. For instance,
<code class="language-plaintext highlighter-rouge">treesit-thing-settings</code> (used for structured navigation) doesn’t exist – you
need a fallback:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="c1">;; Fallback for Emacs 29 (no treesit-thing-settings)</span>
<span class="p">(</span><span class="nb">unless</span> <span class="p">(</span><span class="nb">boundp</span> <span class="ss">'treesit-thing-settings</span><span class="p">)</span>
  <span class="p">(</span><span class="nv">setq-local</span> <span class="nv">forward-sexp-function</span> <span class="nf">#'</span><span class="nv">neocaml-forward-sexp</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Emacs 30</strong> added <code class="language-plaintext highlighter-rouge">treesit-thing-settings</code>, sentence navigation, and better
indentation support. But it also had a bug in <code class="language-plaintext highlighter-rouge">treesit-range-settings</code> offsets
(<a href="https://debbugs.gnu.org/cgi/bugreport.cgi?bug=77848">#77848</a>) that broke
embedded parsers, and another in <code class="language-plaintext highlighter-rouge">treesit-transpose-sexps</code> that required
<code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> to disable its Tree-sitter-aware version.</p>

<p><strong>Emacs 31</strong> has a bug in <code class="language-plaintext highlighter-rouge">treesit-forward-comment</code> where an off-by-one error
causes <code class="language-plaintext highlighter-rouge">uncomment-region</code> to leave <code class="language-plaintext highlighter-rouge">*)</code> behind on multi-line OCaml comments. I
had to skip the affected test with a version check:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nb">when</span> <span class="p">(</span><span class="nb">&gt;=</span> <span class="nv">emacs-major-version</span> <span class="mi">31</span><span class="p">)</span>
  <span class="p">(</span><span class="nb">signal</span> <span class="ss">'buttercup-pending</span>
          <span class="s">"Emacs 31 treesit-forward-comment bug (off-by-one)"</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The lesson: <strong>test your mode against multiple Emacs versions</strong>, and be prepared
to write version-specific workarounds. CI that runs against Emacs 29, 30, and
snapshot is essential.</p>

<h3 id="no-scm-file-support-yet">No .scm file support (yet)</h3>

<p>Most Tree-sitter grammars ship with <code class="language-plaintext highlighter-rouge">.scm</code> query files for syntax highlighting
(<code class="language-plaintext highlighter-rouge">highlights.scm</code>) and indentation (<code class="language-plaintext highlighter-rouge">indents.scm</code>). Editors like Neovim and
Helix use these directly. Emacs doesn’t – you have to manually translate the
<code class="language-plaintext highlighter-rouge">.scm</code> patterns into <code class="language-plaintext highlighter-rouge">treesit-font-lock-rules</code> and <code class="language-plaintext highlighter-rouge">treesit-simple-indent-rules</code>
calls in Elisp.</p>

<p>This is tedious and error-prone. For example, here’s a rule from the OCaml
grammar’s <code class="language-plaintext highlighter-rouge">highlights.scm</code>:</p>

<div class="language-scheme highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="c1">;; upstream .scm (used by Neovim, Helix, etc.)</span>
<span class="p">(</span><span class="nf">constructor_name</span><span class="p">)</span> <span class="nv">@type</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And here’s the Elisp equivalent you’d write for Emacs:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="c1">;; Emacs equivalent -- wrapped in treesit-font-lock-rules</span>
<span class="ss">:language</span> <span class="ss">'ocaml</span>
<span class="ss">:feature</span> <span class="ss">'type</span>
<span class="o">'</span><span class="p">((</span><span class="nv">constructor_name</span><span class="p">)</span> <span class="nv">@font-lock-type-face</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The query syntax is nearly identical, but you have to wrap everything in
<code class="language-plaintext highlighter-rouge">treesit-font-lock-rules</code> calls, map upstream capture names (<code class="language-plaintext highlighter-rouge">@type</code>) to Emacs
face names (<code class="language-plaintext highlighter-rouge">@font-lock-type-face</code>), assign features, and manage <code class="language-plaintext highlighter-rouge">:override</code>
behavior. You end up maintaining a parallel set of queries that can drift from
upstream. Emacs 31 will introduce
<a href="https://github.com/emacs-mirror/emacs/blob/master/lisp/treesit-x.el#L47"><code class="language-plaintext highlighter-rouge">define-treesit-generic-mode</code></a>
which will make it possible to use <code class="language-plaintext highlighter-rouge">.scm</code> files for font-locking, which should
help significantly. But for now, you’re hand-coding everything.</p>

<h2 id="tips-and-tricks">Tips and tricks</h2>

<h3 id="debugging-font-locking">Debugging font-locking</h3>

<p>When a face isn’t being applied where you expect:</p>

<ol>
  <li>Use <code class="language-plaintext highlighter-rouge">treesit-inspect-mode</code> to verify the node type at point matches your
query.</li>
  <li>Set <code class="language-plaintext highlighter-rouge">treesit--font-lock-verbose</code> to <code class="language-plaintext highlighter-rouge">t</code> to see which rules are firing.</li>
  <li>Check the font-lock feature level – your rule might be in level 4 while the
user has the default level 3. The features are assigned to levels via
<code class="language-plaintext highlighter-rouge">treesit-font-lock-feature-list</code>.</li>
  <li>Remember that <strong>rule order matters</strong>. Without <code class="language-plaintext highlighter-rouge">:override</code>, an earlier rule that
already fontified a region will prevent later rules from applying. This can be
intentional (e.g. builtin types at level 3 take precedence over generic types)
or a source of bugs.</li>
</ol>

<h3 id="use-the-font-lock-levels-wisely">Use the font-lock levels wisely</h3>

<p>Tree-sitter modes define four levels of font-locking via
<code class="language-plaintext highlighter-rouge">treesit-font-lock-feature-list</code>, and the default level in Emacs is 3. It’s
tempting to pile everything into levels 1–3 so users see maximum highlighting
out of the box, but resist the urge. When every token on the screen has a
different color, code starts looking like a Christmas tree and the important
things – keywords, definitions, types – stop standing out.</p>

<p>Less is more here. Here’s how <code class="language-plaintext highlighter-rouge">neocaml</code> distributes features across levels:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">setq-local</span> <span class="nv">treesit-font-lock-feature-list</span>
            <span class="o">'</span><span class="p">((</span><span class="nv">comment</span> <span class="nv">definition</span><span class="p">)</span>
              <span class="p">(</span><span class="kt">keyword</span> <span class="nb">string</span> <span class="nc">number</span><span class="p">)</span>
              <span class="p">(</span><span class="nv">attribute</span> <span class="nv">builtin</span> <span class="nv">constant</span> <span class="k">type</span><span class="p">)</span>
              <span class="p">(</span><span class="nv">operator</span> <span class="nv">bracket</span> <span class="nv">delimiter</span> <span class="nv">variable</span> <span class="k">function</span><span class="p">)))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>And <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> follows the same philosophy:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">setq-local</span> <span class="nv">treesit-font-lock-feature-list</span>
            <span class="o">'</span><span class="p">((</span><span class="nv">comment</span> <span class="nv">definition</span><span class="p">)</span>
              <span class="p">(</span><span class="kt">keyword</span> <span class="nb">string</span> <span class="nb">char</span> <span class="nc">symbol</span> <span class="nv">builtin</span> <span class="k">type</span><span class="p">)</span>
              <span class="p">(</span><span class="nv">constant</span> <span class="nc">number</span> <span class="k">quote</span> <span class="nv">metadata</span> <span class="nv">doc</span> <span class="nv">regex</span><span class="p">)</span>
              <span class="p">(</span><span class="nv">bracket</span> <span class="nv">deref</span> <span class="k">function</span> <span class="nv">tagged-literals</span><span class="p">)))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>The pattern is the same: essentials first, progressively more detail at higher
levels. This way the default experience (level 3) is clean and readable, and
users who want the full rainbow can bump <code class="language-plaintext highlighter-rouge">treesit-font-lock-level</code> to 4. Better
yet, they can use <code class="language-plaintext highlighter-rouge">treesit-font-lock-recompute-features</code> to cherry-pick
individual features regardless of level:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c1">;; Enable 'function' (level 4) without enabling all of level 4</span>
<span class="p">(</span><span class="nv">treesit-font-lock-recompute-features</span> <span class="o">'</span><span class="p">(</span><span class="k">function</span><span class="p">)</span> <span class="no">nil</span><span class="p">)</span>

<span class="c1">;; Disable 'bracket' even if the user's level would include it</span>
<span class="p">(</span><span class="nv">treesit-font-lock-recompute-features</span> <span class="no">nil</span> <span class="o">'</span><span class="p">(</span><span class="nv">bracket</span><span class="p">))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>This gives users fine-grained control without requiring mode authors to
anticipate every preference.</p>

<h3 id="debugging-indentation">Debugging indentation</h3>

<p>Indentation issues are harder to diagnose because they depend on tree structure,
rule ordering, and anchor resolution:</p>

<ol>
  <li>Set <code class="language-plaintext highlighter-rouge">treesit--indent-verbose</code> to <code class="language-plaintext highlighter-rouge">t</code> – this logs which rule matched for each
line, what anchor was computed, and the final column.</li>
  <li>Use <code class="language-plaintext highlighter-rouge">treesit-explore-mode</code> to understand the parent chain. The key question
is always: “what is the parent node, and which rule matches it?”</li>
  <li>
    <p>Remember that <strong>rule order matters</strong> for indentation too – the first matching
rule wins. A typical set of rules reads top to bottom from most specific to
most general:</p>

    <div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="rouge-code"><pre><span class="c1">;; Closing delimiters align with the opening construct</span>
<span class="p">((</span><span class="nv">node-is</span> <span class="s">")"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">((</span><span class="nv">node-is</span> <span class="s">"end"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="mi">0</span><span class="p">)</span>

<span class="c1">;; then/else clauses align with their enclosing if</span>
<span class="p">((</span><span class="nv">node-is</span> <span class="s">"then_clause"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="mi">0</span><span class="p">)</span>
<span class="p">((</span><span class="nv">node-is</span> <span class="s">"else_clause"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="mi">0</span><span class="p">)</span>

<span class="c1">;; Bodies inside then/else are indented</span>
<span class="p">((</span><span class="nv">parent-is</span> <span class="s">"then_clause"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="nv">neocaml-indent-offset</span><span class="p">)</span>
<span class="p">((</span><span class="nv">parent-is</span> <span class="s">"else_clause"</span><span class="p">)</span> <span class="nv">parent-bol</span> <span class="nv">neocaml-indent-offset</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
  <li>
    <p>Watch out for the <strong>empty-line problem</strong>: when the cursor is on a blank line,
Tree-sitter has no node at point. The indentation engine falls back to the root
<code class="language-plaintext highlighter-rouge">compilation_unit</code> node as the parent, which typically matches the top-level
rule and gives column 0. In neocaml I solved this with a <code class="language-plaintext highlighter-rouge">no-node</code> rule that
looks at the previous line’s last token to decide indentation:</p>

    <div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">no-node</span> <span class="nv">prev-line</span> <span class="nv">neocaml--empty-line-offset</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div>    </div>
  </li>
</ol>

<h3 id="build-a-comprehensive-test-suite">Build a comprehensive test suite</h3>

<p>This is the single most important piece of advice. Font-lock and indentation are
easy to break accidentally, and manual testing doesn’t scale. Both projects use
<a href="https://github.com/jorgenschaefer/emacs-buttercup">Buttercup</a> (a BDD testing
framework for Emacs) with custom test macros.</p>

<p><strong>Font-lock tests</strong> insert code into a buffer, run <code class="language-plaintext highlighter-rouge">font-lock-ensure</code>, and assert
that specific character ranges have the expected face:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">when-fontifying-it</span> <span class="s">"fontifies let-bound functions"</span>
  <span class="p">(</span><span class="s">"let greet name = ..."</span>
   <span class="p">(</span><span class="mi">5</span> <span class="mi">9</span> <span class="nv">font-lock-function-name-face</span><span class="p">)))</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Indentation tests</strong> insert code, run <code class="language-plaintext highlighter-rouge">indent-region</code>, and assert the result
matches the expected indentation:</p>

<div class="language-emacs-lisp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nv">when-indenting-it</span> <span class="s">"indents a match expression"</span>
  <span class="s">"match x with"</span>
  <span class="s">"| 0 -&gt; \"zero\""</span>
  <span class="s">"| n -&gt; string_of_int n"</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p><strong>Integration tests</strong> load real source files and verify that both font-locking
and indentation survive <code class="language-plaintext highlighter-rouge">indent-region</code> on the full file. This catches
interactions between rules that unit tests miss.</p>

<p><code class="language-plaintext highlighter-rouge">neocaml</code> has 200+ automated tests and <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> has even more.
Investing in test infrastructure early pays off enormously – I can refactor
indentation rules with confidence because the suite catches regressions
immediately.</p>

<h4 id="a-personal-story-on-testing-roi">A personal story on testing ROI</h4>

<p>When I became the maintainer of
<a href="https://github.com/clojure-emacs/clojure-mode">clojure-mode</a> many years ago, I
really struggled with making changes. There were no font-lock or indentation
tests, so every change was a leap of faith – you’d fix one thing and break three
others without knowing until someone filed a bug report. I spent years working
on a testing approach I was happy with, alongside many great contributors, and
the return on investment was massive.</p>

<p>The same approach – almost the same test macros – carried over directly to
<code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> when we built the Tree-sitter version. And later I reused the
pattern again in <code class="language-plaintext highlighter-rouge">neocaml</code> and <code class="language-plaintext highlighter-rouge">asciidoc-mode</code>. One investment in testing
infrastructure, four projects benefiting from it.</p>

<p>I know that automated tests, for whatever reason, never gained much traction in
the Emacs community. Many popular packages have no tests at all. I hope stories
like this convince you that investing in tests is really important and pays off
– not just for the project where you write them, but for every project you build
after.</p>

<h3 id="pre-compile-queries">Pre-compile queries</h3>

<p>This one is specific to <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> but applies broadly: compiling
Tree-sitter queries at runtime is expensive. If you’re building queries
dynamically (e.g. with <code class="language-plaintext highlighter-rouge">treesit-font-lock-rules</code> called at mode init time),
consider pre-compiling them as <code class="language-plaintext highlighter-rouge">defconst</code> values. This made a noticeable
difference in <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code>’s startup time.</p>

<h2 id="a-note-on-naming">A note on naming</h2>

<p>The Emacs community has settled on a <code class="language-plaintext highlighter-rouge">-ts-mode</code> suffix convention for
Tree-sitter-based modes: <code class="language-plaintext highlighter-rouge">python-ts-mode</code>, <code class="language-plaintext highlighter-rouge">c-ts-mode</code>, <code class="language-plaintext highlighter-rouge">ruby-ts-mode</code>, and so
on. This makes sense when both a legacy mode and a Tree-sitter mode coexist in
Emacs core – users need to choose between them. But I think the convention is
being applied too broadly, and I’m afraid the resulting name fragmentation will
haunt the community for years.</p>

<p>For new packages that don’t have a legacy counterpart, the <code class="language-plaintext highlighter-rouge">-ts-mode</code> suffix is
unnecessary. I named my packages <code class="language-plaintext highlighter-rouge">neocaml</code> (not <code class="language-plaintext highlighter-rouge">ocaml-ts-mode</code>) and
<code class="language-plaintext highlighter-rouge">asciidoc-mode</code> (not <code class="language-plaintext highlighter-rouge">adoc-ts-mode</code>) because there was no prior <code class="language-plaintext highlighter-rouge">neocaml-mode</code>
or <code class="language-plaintext highlighter-rouge">asciidoc-mode</code> to disambiguate from. The <code class="language-plaintext highlighter-rouge">-ts-</code> infix is an implementation
detail that shouldn’t leak into the user-facing name. Will we rename everything
again when Tree-sitter becomes the default and the non-TS variants are removed?</p>

<p>Be bolder with naming. If you’re building something new, give it a name that
makes sense on its own merits, not one that encodes the parsing technology in the
package name.</p>

<h2 id="the-road-ahead">The road ahead</h2>

<p>I think the full transition to Tree-sitter in the Emacs community will take
3–5 years, optimistically. There are hundreds of major modes out there, many
maintained by a single person in their spare time. Converting a mode from regex
to Tree-sitter isn’t just a mechanical translation – you need to understand the
grammar, rewrite font-lock and indentation rules, handle version compatibility,
and build a new test suite. That’s a lot of work.</p>

<p>Interestingly, this might be one area where agentic coding tools can genuinely
help. The structure of Tree-sitter-based major modes is fairly uniform: grammar
recipes, font-lock rules, indentation rules, navigation settings, imenu. If you
give an AI agent a grammar and a reference to a high-quality mode like
<code class="language-plaintext highlighter-rouge">clojure-ts-mode</code>, it could probably scaffold a reasonable new mode fairly
quickly. The hard parts – debugging grammar quirks, handling edge cases, getting
indentation <em>just right</em> – would still need human attention, but the boilerplate
could be automated.</p>

<p>Still, knowing the Emacs community, I wouldn’t be surprised if a full migration
never actually completes. Many old-school modes work perfectly fine, their
maintainers have no interest in Tree-sitter, and “if it ain’t broke, don’t fix
it” is a powerful force. And that’s okay – diversity of approaches is part of
what makes Emacs Emacs.</p>

<h2 id="closing-thoughts">Closing thoughts</h2>

<p>Tree-sitter is genuinely great for building Emacs major modes. The code is
simpler, the results are more accurate, and incremental parsing means everything
stays fast even on large files. I wouldn’t go back to regex-based font-locking
willingly.</p>

<p>But it’s not magical. Grammars are inconsistent across languages, the Emacs APIs
are still maturing, you can’t reuse <code class="language-plaintext highlighter-rouge">.scm</code> files (yet), and you’ll hit
version-specific bugs that require tedious workarounds. The testing story is
better than with regex modes – tree structures are more predictable than regex
matches – but you still need a solid test suite to avoid regressions.</p>

<p>If you’re thinking about writing a Tree-sitter-based major mode, do it. The
ecosystem needs more of them, and the experience of working with syntax trees
instead of regexes is genuinely enjoyable. Just go in with realistic
expectations, pin your grammar versions, test against multiple Emacs releases,
and build your test suite early.</p>

<p>Anyways, I wish there was an article like this one when I was starting out
with <code class="language-plaintext highlighter-rouge">clojure-ts-mode</code> and <code class="language-plaintext highlighter-rouge">neocaml</code>, so there you have it. I hope that
the lessons I’ve learned along the way will help build better modes
with Tree-sitter down the road.</p>

<p>That’s all I have for you today. Keep hacking!</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>See the excellent <a href="https://github.com/sogaiu/tree-sitter-clojure/blob/master/doc/scope.md">scope discussion</a> in the tree-sitter-clojure repo for the rationale. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
    <li id="fn:2">
      <p>There’s ongoing discussion in the Emacs community about distributing pre-compiled grammar binaries, but nothing concrete yet. <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Bozhidar Batsov</name></author><category term="Emacs" /><category term="OCaml" /><category term="Clojure" /><category term="AsciiDoc" /><summary type="html"><![CDATA[Over the past year I’ve been spending a lot of time building Tree-sitter-powered major modes for Emacs – clojure-ts-mode (as co-maintainer), neocaml (from scratch), and asciidoc-mode (also from scratch). Between the three projects I’ve accumulated enough knowledge (and battle scars) to write about the experience. This post distills the key lessons for anyone thinking about writing a Tree-sitter-based major mode, or curious about what it’s actually like.]]></summary></entry><entry><title type="html">OCaml at First Glance</title><link href="https://batsov.com/articles/2022/08/29/ocaml-at-first-glance/" rel="alternate" type="text/html" title="OCaml at First Glance" /><published>2022-08-29T07:31:00+03:00</published><updated>2022-08-31T00:00:00+03:00</updated><id>https://batsov.com/articles/2022/08/29/ocaml-at-first-glance</id><content type="html" xml:base="https://batsov.com/articles/2022/08/29/ocaml-at-first-glance/"><![CDATA[<blockquote>
  <p>You never get a second chance to make a first impression.</p>
</blockquote>

<p>Lately I’ve been <a href="/articles/2022/08/19/learning-ocaml/">learning OCaml</a> and
I thought it might be a good time to share a few initial impressions, while they
are still fresh. Of course, you should take those with a grain of salt, given
that my knowledge of OCaml is still quite basic and I might be missing out
on some stuff.</p>

<p>Also you should keep in mind my own background, experiences and preferences:</p>

<ul>
  <li>Over the course of almost 20 years I’ve been programming professionally (mostly) in C, C++, Java, Scala and Ruby. The last 10 years have been almost exclusively dedicated to Ruby.</li>
  <li>I’ve always been super passionate about programming languages and on the side I’ve learned to some extent about a dozen more languages (e.g. several Lisps, Haskell, Erlang, etc)</li>
  <li>I’ve got a massive fondness for the simplicity of Lisps, I’ve written a ton of code in Emacs Lisp and Clojure, and I really love REPL-driven (interactive/incremental) programming.</li>
  <li>I’ve never been a strong proponent of either dynamically or statically typed programming languages. I’ve yet to see a compelling argument in favor of one side or the other.</li>
</ul>

<p>Obviously, all of this tends to influence a lot my perception of (new) programming languages. That’s why throughout the article I’ll be drawing some comparisons to other (functional) programming languages that I’m familiar with.</p>

<h2 id="general-notes">General Notes</h2>

<blockquote>
  <p>OCaml is a general-purpose, industrial-strength programming language with an emphasis on expressiveness and safety.</p>

  <p>– ocaml.org</p>
</blockquote>

<p>The language strikes a good balance between being functional and practical. In this sense it really reminds me of Clojure on the practical side and Haskell on the somewhat impractical side (the pursuit of purity comes at a cost). OCaml’s strict evaluation model makes it easier to reason than Haskell and also results in programs with more predictable performance.</p>

<h2 id="language-syntax">Language Syntax</h2>

<p>Language syntax is a favorite bike-shedding topic for most programmers, so I’ll do my best to stay constructive here. I think OCaml’s syntax won’t present much of a challenge for any seasoned programmer, especially for someone with a passing knowledge of a similar language like Haskell.</p>

<p>To put the discussion that follows in context, here are a few trivial OCaml code snippets:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">square</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span>

<span class="n">square</span> <span class="mi">5</span>

<span class="c">(* a classic function definition *)</span>
<span class="k">let</span> <span class="n">hello</span> <span class="n">name</span> <span class="o">=</span> <span class="n">print_endline</span> <span class="p">(</span><span class="s2">"Hello, "</span> <span class="o">^</span> <span class="n">name</span> <span class="o">^</span> <span class="s2">"!"</span><span class="p">)</span>

<span class="n">hello</span> <span class="s2">"world"</span>

<span class="c">(* filter a list with some predicate *)</span>
<span class="k">let</span> <span class="n">is_even</span> <span class="n">x</span> <span class="o">=</span> <span class="n">x</span> <span class="ow">mod</span> <span class="mi">2</span> <span class="o">=</span> <span class="mi">0</span>

<span class="nn">List</span><span class="p">.</span><span class="n">filter</span> <span class="n">is_even</span> <span class="p">[</span><span class="mi">1</span><span class="p">;</span> <span class="mi">2</span><span class="p">;</span> <span class="mi">3</span><span class="p">;</span> <span class="mi">4</span><span class="p">;</span> <span class="mi">5</span><span class="p">;</span> <span class="mi">6</span><span class="p">;</span> <span class="mi">7</span><span class="p">;</span> <span class="mi">8</span><span class="p">;</span> <span class="mi">9</span><span class="p">]</span>
<span class="o">-</span> <span class="o">:</span> <span class="kt">int</span> <span class="kt">list</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">;</span> <span class="mi">4</span><span class="p">;</span> <span class="mi">6</span><span class="p">;</span> <span class="mi">8</span><span class="p">]</span>

<span class="c">(* compute factorial recursively *)</span>
<span class="k">let</span> <span class="k">rec</span> <span class="n">fact</span> <span class="n">x</span> <span class="o">=</span>
  <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;=</span> <span class="mi">1</span> <span class="k">then</span> <span class="mi">1</span> <span class="k">else</span> <span class="n">x</span> <span class="o">*</span> <span class="n">fact</span> <span class="p">(</span><span class="n">x</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>

<span class="n">fact</span> <span class="mi">10</span>

<span class="c">(* reverse a list using pattern matching and tail recursion *)</span>
<span class="k">let</span> <span class="n">rev</span> <span class="n">lst</span> <span class="o">=</span>
  <span class="k">let</span> <span class="k">rec</span> <span class="n">rev'</span> <span class="n">res</span> <span class="o">=</span> <span class="k">function</span>
  <span class="o">|</span> <span class="bp">[]</span> <span class="o">-&gt;</span> <span class="n">res</span>
  <span class="o">|</span> <span class="n">h</span> <span class="o">::</span> <span class="n">t</span> <span class="o">-&gt;</span> <span class="n">rev'</span> <span class="p">(</span><span class="n">h</span> <span class="o">::</span> <span class="n">res</span><span class="p">)</span> <span class="n">t</span>
  <span class="k">in</span>
  <span class="n">rev'</span> <span class="bp">[]</span> <span class="n">lst</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>I hope those snippets gave you some notion of OCaml’s syntax. I’ll admit
that I’m fairly fond of it by now, although it definitely takes a bit of time to
get used to it.</p>

<h3 id="things-i-liked">Things I Liked</h3>

<p>Some aspects of the OCaml syntax that I liked:</p>

<ul>
  <li>using <code class="language-plaintext highlighter-rouge">;;</code> as expression terminator - that’s useful in toplevels as it makes it easy to input a multi-line expression. It’s also optional elsewhere, so it doesn’t add unneeded verbosity.</li>
  <li>being explicit about recursive bindings. Notice the <code class="language-plaintext highlighter-rouge">rec</code> keyword here:</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="k">rec</span> <span class="n">last</span> <span class="o">=</span> <span class="k">function</span>
  <span class="o">|</span> <span class="bp">[]</span> <span class="o">-&gt;</span> <span class="nc">None</span>
  <span class="o">|</span> <span class="p">[</span> <span class="n">x</span> <span class="p">]</span> <span class="o">-&gt;</span> <span class="nc">Some</span> <span class="n">x</span>
  <span class="o">|</span> <span class="n">_</span> <span class="o">::</span> <span class="n">t</span> <span class="o">-&gt;</span> <span class="n">last</span> <span class="n">t</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>type signatures are optional</li>
  <li>module types</li>
  <li>the ability to restrict an open module to a very small scope</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">average</span> <span class="n">x</span> <span class="n">y</span> <span class="o">=</span>
  <span class="k">let</span> <span class="k">open</span> <span class="nc">Int64</span> <span class="k">in</span>
  <span class="p">(</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> <span class="o">/</span> <span class="n">of_int</span> <span class="mi">2</span>

<span class="k">let</span> <span class="n">average</span> <span class="n">x</span> <span class="n">y</span> <span class="o">=</span>
  <span class="nn">Int64</span><span class="p">.((</span><span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">)</span> <span class="o">/</span> <span class="n">of_int</span> <span class="mi">2</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>labeled arguments</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">div</span> <span class="o">~</span><span class="n">num</span> <span class="o">~</span><span class="n">denom</span> <span class="o">=</span> <span class="n">num</span> <span class="o">/</span> <span class="n">denom</span>

<span class="n">div</span> <span class="o">~</span><span class="n">num</span><span class="o">:</span><span class="mi">3</span> <span class="o">~</span><span class="n">denom</span><span class="o">:</span><span class="mi">10</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>the ability to place the signature of a module in a dedicated <code class="language-plaintext highlighter-rouge">.mli</code> file.</li>
  <li>the ability to have user-defined types that look as something built-in (e.g. lists, <code class="language-plaintext highlighter-rouge">ref</code>s, etc)</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c">(* here's how you can define ref yourselves *)</span>
<span class="k">type</span> <span class="k">'</span><span class="n">a</span> <span class="n">ref</span> <span class="o">=</span> <span class="p">{</span> <span class="k">mutable</span> <span class="n">contents</span> <span class="o">:</span> <span class="k">'</span><span class="n">a</span> <span class="p">}</span>

<span class="k">let</span> <span class="n">ref</span> <span class="n">x</span> <span class="o">=</span> <span class="p">{</span> <span class="n">contents</span> <span class="o">=</span> <span class="n">x</span> <span class="p">}</span>

<span class="k">let</span> <span class="p">(</span><span class="o">!</span><span class="p">)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">contents</span>

<span class="k">let</span> <span class="p">(</span><span class="o">:=</span><span class="p">)</span> <span class="n">r</span> <span class="n">x</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">contents</span> <span class="o">&lt;-</span> <span class="n">x</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>having handy functions like <code class="language-plaintext highlighter-rouge">|&gt;</code> out-of-the-box (I’m quite used to this from Clojure)</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">some_list</span> <span class="o">|&gt;</span> <span class="nn">List</span><span class="p">.</span><span class="n">filter</span> <span class="n">is_even</span> <span class="o">|&gt;</span> <span class="n">sum</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>By the way, there’s nothing really special about <code class="language-plaintext highlighter-rouge">|&gt;</code>, it’s a function like any other. One of the nice aspects of OCaml’s syntax in general.</p>

<ul>
  <li>the usages of <code class="language-plaintext highlighter-rouge">snake_case</code> instead of <code class="language-plaintext highlighter-rouge">camelCase</code> most of the time. I find <code class="language-plaintext highlighter-rouge">snake_case</code> identifiers to be more readable, although obviously that’s super subjective.</li>
</ul>

<h3 id="things-i-disliked">Things I Disliked</h3>

<p>Some aspects of the syntax that I disliked or found confusing (at least initially):</p>

<ul>
  <li>using <code class="language-plaintext highlighter-rouge">(* *)</code> for comments and lack of line comments (e.g. <code class="language-plaintext highlighter-rouge">//</code> is some C-like
languages). Not the end of the world, but the comment syntax makes some things
trickier (e.g. referring to the multiplication operator <code class="language-plaintext highlighter-rouge">*</code>) and is just too
verbose.</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
</pre></td><td class="rouge-code"><pre><span class="c">(* this will work *)</span>
<span class="nn">List</span><span class="p">.</span><span class="n">fold_left</span> <span class="p">(</span><span class="o">+</span><span class="p">)</span> <span class="mi">0</span> <span class="p">[</span><span class="mi">1</span><span class="p">;</span><span class="mi">2</span><span class="p">;</span><span class="mi">3</span><span class="p">;</span><span class="mi">4</span><span class="p">;</span><span class="mi">5</span><span class="p">]</span>

<span class="c">(* this will work *)</span>
<span class="nn">List</span><span class="p">.</span><span class="n">fold_left</span> <span class="p">(</span> <span class="o">*</span> <span class="p">)</span> <span class="mi">1</span> <span class="p">[</span><span class="mi">1</span><span class="p">;</span><span class="mi">2</span><span class="p">;</span><span class="mi">3</span><span class="p">;</span><span class="mi">4</span><span class="p">;</span><span class="mi">5</span><span class="p">]</span>

<span class="c">(* this will not work *)</span>
<span class="nn">List</span><span class="p">.</span><span class="n">fold_left</span> <span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="mi">1</span> <span class="p">[</span><span class="mi">1</span><span class="p">;</span><span class="mi">2</span><span class="p">;</span><span class="mi">3</span><span class="p">;</span><span class="mi">4</span><span class="p">;</span><span class="mi">5</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Here’s one more comment that won’t work - <code class="language-plaintext highlighter-rouge">(* " *)</code>. I’ll leave to the curious reader to figure out why that’s the case.</p>

<ul>
  <li>using <code class="language-plaintext highlighter-rouge">;</code> heavily as element separator (e.g. in lists and records):</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">some_list</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">;</span> <span class="mi">2</span><span class="p">;</span> <span class="mi">3</span><span class="p">;</span> <span class="mi">4</span><span class="p">;</span> <span class="mi">5</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You get used to this, but it’s a pretty big departure from the norm to use commas. I wonder what’s the reasoning behind this. Most likely it has to do with being able to define tuples without parentheses around them:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="p">);;</span>
<span class="c">(* - : int * int * int = (1, 2, 3) *)</span>

<span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="p">;;</span>
<span class="c">(* - : int * int * int = (1, 2, 3) *)</span>

<span class="c">(* a more realistic example of the usefulness of this *)</span>
<span class="k">let</span> <span class="n">a</span><span class="o">,</span> <span class="n">b</span><span class="o">,</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span> <span class="k">in</span>
<span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">+</span> <span class="n">c</span>

<span class="c">(* but we pay a steep price for the above convenience *)</span>
<span class="p">[</span><span class="mi">1</span><span class="o">,</span> <span class="mi">2</span><span class="o">,</span> <span class="mi">3</span><span class="p">];;</span>
<span class="c">(* - : (int * int * int) list = [(1, 2, 3)] *)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>introducing <a href="/articles/2022/08/28/ocaml-tips-multiple-let-bindings/">multiple <code class="language-plaintext highlighter-rouge">let</code> bindings</a> is a bit too verbose for my taste</li>
  <li>it took me a while to figure out <a href="https://stackoverflow.com/questions/1604270/what-is-the-difference-between-the-fun-and-function-keywords">the difference between <code class="language-plaintext highlighter-rouge">fun</code> and <code class="language-plaintext highlighter-rouge">function</code></a></li>
  <li>no syntax for list comprehensions (I often use those in Clojure, Haskell and Erlang, although I’m well aware they are not something essential)</li>
  <li>the syntax for array literals is somewhat weird (<code class="language-plaintext highlighter-rouge">[|1; 2; 3|]</code>) - I don’t like such usage of multiple symbols as literal boundaries, as this makes it harder for dev tools to figure out what you’re doing. The indexing syntax <code class="language-plaintext highlighter-rouge">arr.(i)</code> is slightly weird as well, as it doesn’t fit very well with the rest of the language.</li>
  <li>no first-class syntax for maps and sets (Clojure spoiled on this front)</li>
</ul>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="c1">;; Clojure map</span><span class="w">
</span><span class="p">{</span><span class="no">:name</span><span class="w"> </span><span class="s">"Bruce Wayne"</span><span class="w"> </span><span class="no">:alias</span><span class="w"> </span><span class="s">"Batman"</span><span class="p">}</span><span class="w">

</span><span class="c1">;; Clojure set</span><span class="w">
</span><span class="o">#</span><span class="p">{</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="p">}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>nothing like Haskell’s typeclasses, which means in some cases you get different operators for similar types (e.g. numeric types):</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="c">(* int version *)</span>
<span class="k">let</span> <span class="n">average</span> <span class="n">a</span> <span class="n">b</span> <span class="o">=</span>
    <span class="p">(</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="o">.</span><span class="mi">0</span>

<span class="c">(* float version *)</span>
<span class="k">let</span> <span class="n">average</span> <span class="n">a</span> <span class="n">b</span> <span class="o">=</span>
    <span class="p">(</span><span class="n">a</span> <span class="o">+.</span> <span class="n">b</span><span class="p">)</span> <span class="o">/.</span> <span class="mi">2</span><span class="o">.</span><span class="mi">0</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>On the bright side - it’s really easy to spot float operations.</p>

<p>By the way, this also means you get different operators for things like string and
list concatenation, as you can’t use <code class="language-plaintext highlighter-rouge">+</code> which is defined in terms of integers:</p>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
</pre></td><td class="rouge-code"><pre><span class="s2">"Hello, "</span> <span class="o">^</span> <span class="s2">"world!"</span>

<span class="p">[</span><span class="mi">1</span><span class="p">;</span> <span class="mi">2</span><span class="p">]</span> <span class="o">@</span> <span class="p">[</span><span class="mi">3</span><span class="p">;</span> <span class="mi">4</span><span class="p">]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<h3 id="surprising-bits-of-syntax">Surprising Bits of Syntax</h3>

<p>Here are some things that I like overall, but I found somewhat surprising early on:</p>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">=</code> operator is used both for assignment and for structural comparisons:</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">5</span>

<span class="n">x</span> <span class="o">=</span> <span class="mi">5</span>
<span class="o">-</span> <span class="o">:</span> <span class="kt">bool</span> <span class="o">=</span> <span class="bp">true</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>
    <p>The operators <code class="language-plaintext highlighter-rouge">==</code> and <code class="language-plaintext highlighter-rouge">!=</code> are used for identity comparison (whether you’re comparing something with itself), when in some other languages they are used for structural comparison. Not exactly wild, but not very common either.</p>
  </li>
  <li>
    <p>The operator for structural inequality is <code class="language-plaintext highlighter-rouge">&lt;&gt;</code>. Although it’s not like Haskell’s <code class="language-plaintext highlighter-rouge">\=</code> is particularly common either.</p>
  </li>
</ul>

<p>By the way, when it comes to learning OCaml’s operators I can’t recommend <a href="https://www.craigfe.io/operator-lookup/">this site</a> highly enough!</p>

<ul>
  <li>Several modules in the standard library have two versions - one where the functions are using positional arguments and one where the functions are taking labeled (named) arguments (e.g. <code class="language-plaintext highlighter-rouge">String</code> and <code class="language-plaintext highlighter-rouge">StringLabels</code>). Not exactly a syntax matter, but definitely a peculiarity.</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="o">#</span> <span class="nn">List</span><span class="p">.</span><span class="n">map</span><span class="p">;;</span>
<span class="o">-</span> <span class="o">:</span> <span class="p">(</span><span class="k">'</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">a</span> <span class="kt">list</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">b</span> <span class="kt">list</span> <span class="o">=</span> <span class="o">&lt;</span><span class="k">fun</span><span class="o">&gt;</span>
<span class="o">#</span> <span class="nn">ListLabels</span><span class="p">.</span><span class="n">map</span><span class="p">;;</span>
<span class="o">-</span> <span class="o">:</span> <span class="n">f</span><span class="o">:</span><span class="p">(</span><span class="k">'</span><span class="n">a</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">b</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">a</span> <span class="kt">list</span> <span class="o">-&gt;</span> <span class="k">'</span><span class="n">b</span> <span class="kt">list</span> <span class="o">=</span> <span class="o">&lt;</span><span class="k">fun</span><span class="o">&gt;</span>

<span class="o">#</span> <span class="nn">String</span><span class="p">.</span><span class="n">sub</span><span class="p">;;</span>
<span class="o">-</span> <span class="o">:</span> <span class="kt">string</span> <span class="o">-&gt;</span> <span class="kt">int</span> <span class="o">-&gt;</span> <span class="kt">int</span> <span class="o">-&gt;</span> <span class="kt">string</span> <span class="o">=</span> <span class="o">&lt;</span><span class="k">fun</span><span class="o">&gt;</span>
<span class="o">#</span> <span class="nn">StringLabels</span><span class="p">.</span><span class="n">sub</span><span class="p">;;</span>
<span class="o">-</span> <span class="o">:</span> <span class="kt">string</span> <span class="o">-&gt;</span> <span class="n">pos</span><span class="o">:</span><span class="kt">int</span> <span class="o">-&gt;</span> <span class="n">len</span><span class="o">:</span><span class="kt">int</span> <span class="o">-&gt;</span> <span class="kt">string</span> <span class="o">=</span> <span class="o">&lt;</span><span class="k">fun</span><span class="o">&gt;</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li>Having two ways to create anonymous functions - via <code class="language-plaintext highlighter-rouge">fun</code> and <code class="language-plaintext highlighter-rouge">function</code>.
Basically <code class="language-plaintext highlighter-rouge">function</code> only allows for one argument, but allows for pattern matching, while <code class="language-plaintext highlighter-rouge">fun</code> is the more general way to define a function.</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">f</span> <span class="o">=</span> <span class="k">function</span> <span class="n">x</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">5</span>

<span class="k">let</span> <span class="k">rec</span> <span class="n">last</span> <span class="o">=</span> <span class="k">function</span>
  <span class="o">|</span> <span class="bp">[]</span> <span class="o">-&gt;</span> <span class="nc">None</span>
  <span class="o">|</span> <span class="p">[</span> <span class="n">x</span> <span class="p">]</span> <span class="o">-&gt;</span> <span class="nc">Some</span> <span class="n">x</span>
  <span class="o">|</span> <span class="n">_</span> <span class="o">::</span> <span class="n">t</span> <span class="o">-&gt;</span> <span class="n">last</span> <span class="n">t</span>

<span class="k">let</span> <span class="n">f</span> <span class="o">=</span> <span class="k">fun</span> <span class="n">x</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">5</span>
<span class="k">let</span> <span class="n">g</span> <span class="o">=</span> <span class="k">fun</span> <span class="n">x</span> <span class="n">y</span> <span class="o">-&gt;</span> <span class="n">x</span> <span class="o">*</span> <span class="n">y</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>You can learn more about the differences between <code class="language-plaintext highlighter-rouge">fun</code> and <code class="language-plaintext highlighter-rouge">function</code> <a href="https://stackoverflow.com/questions/1604270/what-is-the-difference-between-the-fun-and-function-keywords">here</a>.</p>

<h3 id="reason">Reason</h3>

<blockquote>
  <p>Reason is a programming language powered by OCaml’s strong type system, and has a syntax designed to feel familiar to people coming from JavaScript or C-family languages.</p>

  <p>– https://reasonml.github.io</p>
</blockquote>

<p>In other words Reason allows you to leverage the OCaml ecosystem with a syntax that might be more familiar to some people. Think something like the relationship between Elixir and Erlang. Here’s some code written in Reason:</p>

<pre><code class="language-reason">let launchMissile = () =&gt; {
  someSideEffects();
  print_endline("Missiles have been launched!");
};

launchMissile();

type schoolPerson = Teacher | Director | Student(string);

let greeting = person =&gt;
  switch (person) {
  | Teacher =&gt; "Hey Professor!"
  | Director =&gt; "Hello Director."
  | Student("Richard") =&gt; "Still here Ricky?"
  | Student(anyOtherName) =&gt; "Hey, " ++ anyOtherName ++ "."
  };
</code></pre>

<p>Whether this is any better than OCaml’s syntax is up to you to decide. Personally,
I’m not a fan of Reason, but if it helps grow the OCaml community then it’s a great
idea in my book.</p>

<h3 id="syntax-summary">Syntax Summary</h3>

<blockquote>
  <p>This too shall pass.</p>

  <p>– Ancient Persian adage</p>
</blockquote>

<p>Overall, there’s not much to write home about when it comes to OCaml’s syntax - it certainly won’t shock anyone the way Lisp or Prolog would. OCaml has a very long legacy as part of the ML-family of languages and I guess it accumulated a few syntactic oddities over time. I don’t expect any changes to happen and I got used to whatever I considered to be “weird” fairly quickly.</p>

<h2 id="ocaml-platform-compiler-libraries-frameworks">OCaml Platform (Compiler, Libraries, Frameworks)</h2>

<p>In brief:</p>

<ul>
  <li>the compiler is super fast, but that was expected given that OCaml is famous for it.</li>
  <li>the compiler is also quite helpful, although its messages can definitely be more descriptive in some cases.</li>
  <li>the standard library is quite basic and that’s probably my main gripe with the language so far - e.g. the support for things like string manipulation (the standard library doesn’t support Unicode strings) and regular expressions is abysmal given what you’d get with most other languages today.</li>
  <li>the above has spurred the creation of all sorts of extensions and replacements to the standard library, which creates a lot of learning overhead and fragmentation. I was amused to see that the popular book <a href="https://dev.realworldocaml.org/">Real World OCaml</a> directly recommends replacing the standard library with a third-party alternative.</li>
  <li>the package manager <a href="https://opam.ocaml.org">Opam</a> is relatively easy to use, although using switches (isolated OCaml environments) takes a while to get used to. I’m still not sure that should be part of the responsibilities of a package manager, but it gets the job done. Opam could use some better <a href="https://opam.ocaml.org/doc/Manual.html">documentation</a>.</li>
</ul>

<p>There’s also support to target <a href="https://github.com/ocsigen/js_of_ocaml">JavaScript from OCaml sources</a>, which looks interesting, but I haven’t tried it yet. <a href="https://rescript-lang.org/">ReScript</a> (basically Reason that targets JavaScript) is also appealing in this space, even if it’s only tangentially connected to OCaml.<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<p>One common complaint about OCaml is its lack of support for parallel programming - OCaml currently doesn’t natively support multiple OS-level OCaml threads running simultaneously. A global lock prevents multiple OCaml threads from running at once. The good news is that <a href="https://discuss.ocaml.org/t/ocaml-5-0-zeroth-alpha-release/10026">OCaml 5.0</a> is right around the corner and its flagship feature is native support for multicore parallelism! This <a href="https://github.com/ocaml-multicore/parallel-programming-in-multicore-ocaml">article</a> is a fantastic overview of Multicore OCaml. Exciting times ahead!</p>

<p>Back to the present - today OCaml has pretty decent support for <a href="https://ocamlverse.github.io/content/parallelism.html#concurrency">concurrent programming</a> (most notably via the library <a href="https://github.com/ocsigen/lwt">Lwt</a>). Moreover, my experience with Ruby has taught me that one can get pretty far and build a lot of useful software despite the presence of a global lock. And don’t even get me started on the performance difference between Ruby and OCaml…</p>

<p>There are plenty of third-party OCaml libraries, although most of them seem somewhat under-maintained and under-documented. I’ve noticed that for many libraries all the documentation you’ll find is just API signatures - e.g. <a href="https://ocaml.org/p/re/1.10.4/doc/Re/Perl/index.html">this</a>.</p>

<p>The only framework I looked into was <a href="https://aantron.github.io/dream/">Dream</a> (a web framework). It looked pretty nice, but it’s still in alpha, has only one developer and it seems he has been not been very active lately. Oh, well - that’s a common problem in smaller programming communities.</p>

<h3 id="a-note-about-standard-libraries">A Note About Standard Libraries</h3>

<p>OCaml’s standard library has few fans and lots of competition.</p>

<p>It seems that today the most popular complete alternative of OCaml’s standard library is <a href="https://opensource.janestreet.com/base/">Base</a> by Jane Street. There’s also <a href="https://opensource.janestreet.com/core/">Core</a> which is a superset of <code class="language-plaintext highlighter-rouge">Base</code> and features even more functionality. As I’ve started out by reading the RWO book initially I was
using <code class="language-plaintext highlighter-rouge">Base</code> all the time, but I’ve stopped using it since. Not that the library is bad or anything - I just wanted to give myself some time to assess for myself the problems that <code class="language-plaintext highlighter-rouge">Base</code> supposedly solves, plus consider other alternatives.</p>

<p>I’ve recently discovered <a href="https://github.com/c-cube/ocaml-containers">Containers</a>, which extends OCaml’s standard library instead of replacing it completely. I plan to make heavier use of it going forward.</p>

<h2 id="development-tooling">Development Tooling</h2>

<p>I’d say the development tooling for OCaml is pretty decent, although I wouldn’t go as far as saying it’s great. I’ve documented my current Emacs setup <a href="/articles/2022/08/23/setting-up-emacs-for-ocaml-development/">here</a> and I’ve also played a bit with the “official” VS Code extension to get a feel for OCaml-LSP.</p>

<p>Without a doubt, <a href="https://ocaml.github.io/merlin/">Merlin</a> is the primary workhorse of the development tools and it’s definitely pretty awesome. It provides editor features like code completion, typing information, navigation to definition, refactoring, code generation, linting, etc. It’s a beast! Emacs’s <code class="language-plaintext highlighter-rouge">merlin-mode</code> reminds me in a way of CIDER (for Clojure).</p>

<p><a href="https://github.com/ocaml-community/utop/">utop</a> is a good toplevel (REPL) and has become a major part of my OCaml toolbox. It’d be nice if down the road someone improves a bit the default <code class="language-plaintext highlighter-rouge">ocaml</code> toplevel, which is extremely basic by every modern standard.</p>

<p><a href="https://dune.build/">Dune</a> is a solid build tool and I definitely enjoyed working with it. It does need better documentation, though, as I learned more about it (and Opam) from third-party documentation instead of from their official documentation.</p>

<p>For testing I can recommend the following libraries:</p>

<ul>
  <li><a href="https://github.com/janestreet/ppx_inline_test">ppx_inline_test</a> for simple tests that you can place alongside your code, while you’re developing it:</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="k">let</span> <span class="n">is_prime</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">magic</span><span class="o">&gt;</span>

<span class="k">let</span><span class="o">%</span><span class="n">test</span> <span class="n">_</span> <span class="o">=</span> <span class="n">is_prime</span> <span class="mi">5</span>
<span class="k">let</span><span class="o">%</span><span class="n">test</span> <span class="n">_</span> <span class="o">=</span> <span class="n">is_prime</span> <span class="mi">7</span>
<span class="k">let</span><span class="o">%</span><span class="n">test</span> <span class="n">_</span> <span class="o">=</span> <span class="n">not</span> <span class="p">(</span><span class="n">is_prime</span> <span class="mi">1</span><span class="p">)</span>
<span class="k">let</span><span class="o">%</span><span class="n">test</span> <span class="n">_</span> <span class="o">=</span> <span class="n">not</span> <span class="p">(</span><span class="n">is_prime</span> <span class="mi">8</span><span class="p">)</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li><a href="https://github.com/janestreet/ppx_expect">ppx_expect</a> is a framework for writing tests in OCaml, similar to Cram. Expect-tests mimic the existing inline tests framework with the <code class="language-plaintext highlighter-rouge">let%expect_test</code> construct. The body of an expect-test can contain output-generating code, interleaved with <code class="language-plaintext highlighter-rouge">%expect</code> extension expressions to denote the expected output:</li>
</ul>

<div class="language-ocaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="k">open</span> <span class="nc">Core</span>

<span class="k">let</span><span class="o">%</span><span class="n">expect_test</span> <span class="s2">"addition"</span> <span class="o">=</span>
  <span class="n">printf</span> <span class="s2">"%d"</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span>
  <span class="p">[</span><span class="o">%</span><span class="n">expect</span> <span class="p">{</span><span class="o">|</span> <span class="mi">4</span> <span class="o">|</span><span class="p">}]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<ul>
  <li><a href="https://github.com/mirage/alcotest">alcotest</a> is my favorite testing framework so far. It’s really easy to work with and it has beautiful output.</li>
</ul>

<p><img src="https://raw.githubusercontent.com/mirage/alcotest/main/.meta/error.png" alt="alcotest.png" /></p>

<p>I think for most people a combination of VS Code + a <code class="language-plaintext highlighter-rouge">utop</code> and <code class="language-plaintext highlighter-rouge">dune</code> (e.g. <code class="language-plaintext highlighter-rouge">dune runtest -w</code>) running in dedicated terminals will provide the optimal development experience. This way you’ll be able to play with some small snippets of OCaml code in your toplevel and get instant feedback from your test suite on every change you make. Of course, if you can stomach Emacs - even better. ;-)</p>

<h2 id="community">Community</h2>

<p>The OCaml community is tiny by the standards of more popular programming languages, but I really enjoyed all my interactions with its members. I’ve been mostly using the official <a href="https://discord.gg/cCYQbqN">Discord</a> and <a href="https://discus.ocaml.org">Discourse</a>, but there are plenty of <a href="https://ocaml.org/community">other options</a> for you to choose from.</p>

<p>I’ve gotten plenty of answers to every question I asked and I really enjoyed learning more about <a href="https://discuss.ocaml.org/t/whats-your-development-workflow/10358">the workflows OCaml developers have</a>, as finding a productive workflow was one of the things I’ve struggled with early on.<sup id="fnref:2"><a href="#fn:2" class="footnote" rel="footnote" role="doc-noteref">2</a></sup></p>

<p>I also learned a lot simply by hanging out there and perusing the topics that were being posted and channels like <code class="language-plaintext highlighter-rouge">#general</code>, <code class="language-plaintext highlighter-rouge">#beginners</code> and <code class="language-plaintext highlighter-rouge">#share</code>.</p>

<p>One final community resource I’d like to recommend is the awesome wiki <a href="https://ocamlverse.github.io/">OCamlverse</a>. It complements really well the information on the official OCaml site.</p>

<h2 id="learning-resources">Learning Resources</h2>

<p>You certainly won’t find dozens of books, hundreds of tutorials and a few online courses for OCaml. It seems that the most popular resources to learn OCaml are:</p>

<ul>
  <li><a href="https://dev.realworldocaml.org/">Real World OCaml</a>: A free book about OCaml, that’s considered one of the best starting points in the community. On the flip side - it’s somewhat controversial for its decision to advocate the use of an alternative standard library (<code class="language-plaintext highlighter-rouge">Base</code> from Jane Street).</li>
  <li><a href="https://cs3110.github.io/textbook/cover.html">Cornell University’s course on OCaml</a>: It’s taught at the university, but the textbook and the video lectures are freely available online. I enjoyed the course, although it’s clearly geared towards students and not practicing programmers.</li>
  <li><a href="https://ocamlverse.github.io/">OCamlverse</a>: An OCaml community wiki. The articles there give you a lot of practical pointers about day-to-day OCaml programming and complement nicely the tutorial/manual texts.</li>
</ul>

<p>There’s also some <a href="https://ocaml.org/docs/up-and-running">tutorial-like section</a> on the official site, but it could have been structured better in my opinion.</p>

<p>I definitely think there’s a lot of room for more resources for newcomers and
that’s one area that will need work if OCaml is grow its mindshare. When everyone in the community is discussing the merits of a single book (RWO), you immediately figure out the problem is not the contents of the book, but rather the lack of alternative books.</p>

<p>While Clojure and Haskell are considered niche languages as well, there are a lot more learning resources of every flavor for them. I think that even Erlang has more resources than OCaml these days.</p>

<h2 id="a-closing-note-about-libraries">A Closing Note About Libraries</h2>

<p>A while ago I made a comment about the standard library situation <a href="https://discuss.ocaml.org/t/what-i-dislike-about-ocaml/10248/50?u=bbatsov">on Discourse</a> that triggered a a follow-up conversation about two things:</p>

<ul>
  <li>that the standard library wasn’t a major focus for OCaml’s team and they prefer for libraries to be developed independently by experts in a particular area (fair enough)</li>
  <li>that it’s actually easy to find the right libraries for each problem (it was mostly focused on strings)</li>
</ul>

<p>While, I can agree with the first point in principle, I’d still expect at least a set of well-known libraries to be widely recommended, etc. Digging for libraries while learning a language is not always fun and sometimes leads in the wrong direction. On the second point - I was amused to see back-to-back comments that were contradicting one another. First I got the follow suggestion:</p>

<blockquote>
  <p>For example, for Unicode support you need to decide between Camomile and <code class="language-plaintext highlighter-rouge">uutf</code>, depending on your needs.</p>
</blockquote>

<p>And then it got this response:</p>

<blockquote>
  <p>I’m not sure I understand this comment. I don’t think there’s anything to decide between the two things you mention.</p>

  <p>First the only thing that uutf provides, namely UTF codecs is nowaday available in <code class="language-plaintext highlighter-rouge">Stdlib.Buffer</code> and <code class="language-plaintext highlighter-rouge">Stdlib.String</code>. Except if you rely on the non-blocking stuff, which most people don’t, there’s no reason to use uutf anymore. People should move away from it and consider it deprecated.</p>

  <p>Second if you need to access Unicode character data or perform normalisations, AFAIK Camomile has not updated its Unicode data for quite some time. Last time I looked it was Unicode 3.2 which was released in 2002, twenty years ago.</p>

  <p>Since then thousands of characters, dozen of scripts and few new characters properties have been added. This makes Camomile entirely impractical to deal with the Unicode of today.</p>

  <p>So I don’t think there’s any choice to be had here. You will be better served by <code class="language-plaintext highlighter-rouge">uucp</code>, <code class="language-plaintext highlighter-rouge">uunf</code> and <code class="language-plaintext highlighter-rouge">uuseg</code> (this one not provided by Camomile).<sup id="fnref:3"><a href="#fn:3" class="footnote" rel="footnote" role="doc-noteref">3</a></sup></p>
</blockquote>

<p>And finally the acknowledgment:</p>

<blockquote>
  <p>Exactly the kind of thing newcomers or casual users would absolutely never know unless they did a lot of research.</p>
</blockquote>

<p>Indeed! Clearly finding the right libraries is not trivial in this case. Hopefully the situation will be improved with time.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I can’t say that my initial experience with OCaml was mind-blowing, but it was definitely pleasant and with time the language grows on me. I miss the simplicity and uniformity of Clojure (still my favorite programming language by far) or some of Haskell’s goodies (e.g. typeclasses, <a href="https://hackage.haskell.org/">Hackage</a> and <code class="language-plaintext highlighter-rouge">ghci</code>), but I feel OCaml strikes a very good balance between functional programming, pragmatism and performance.</p>

<p>At this point I’ve seen enough to be convinced to continue with my exploration of OCaml and dig deeper. Keep hacking!</p>

<hr />

<p>You can discuss the article on <a href="https://news.ycombinator.com/item?id=32636682">Hacker News</a> or <a href="https://discuss.ocaml.org/t/ocaml-at-first-glance/10396">OCaml’s Discourse</a>.</p>
<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p><a href="https://ersin-akinci.medium.com/confused-about-rescript-rescript-reason-reasonml-and-bucklescript-explained-ab4230555230">This article</a> covers well the confusing topic of how Reason, ReasonML and ReScript relate to one another. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
    <li id="fn:2">
      <p>Pro tip - <code class="language-plaintext highlighter-rouge">dune runtest -w --no-buffer</code> is essential! <a href="#fnref:2" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
    <li id="fn:3">
      <p>Don’t even get me started on names like <code class="language-plaintext highlighter-rouge">uucp</code>, <code class="language-plaintext highlighter-rouge">uund</code> and <code class="language-plaintext highlighter-rouge">uuseg</code>. :-) Naming continues to be hard! <a href="#fnref:3" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Bozhidar Batsov</name></author><category term="OCaml" /><category term="Clojure" /><category term="Haskell" /><summary type="html"><![CDATA[You never get a second chance to make a first impression.]]></summary></entry><entry><title type="html">Clojure Tricks: Number to Digits</title><link href="https://batsov.com/articles/2022/08/01/clojure-tricks-number-to-digits/" rel="alternate" type="text/html" title="Clojure Tricks: Number to Digits" /><published>2022-08-01T10:42:00+03:00</published><updated>2022-08-01T10:42:00+03:00</updated><id>https://batsov.com/articles/2022/08/01/clojure-tricks-number-to-digits</id><content type="html" xml:base="https://batsov.com/articles/2022/08/01/clojure-tricks-number-to-digits/"><![CDATA[<p>If you’re into programming puzzles you probably know that there’s a whole class
of problems about doing something (e.g. some calculations) with the digits of a
number. This means you need to break down a number into its digits first. I’ve
always assumed that those problems exist just because decomposing a number to
its digits is a classic example of recursion:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">digits</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w">
    </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
    </span><span class="p">(</span><span class="nb">conj</span><span class="w"> </span><span class="p">(</span><span class="nf">digits</span><span class="w"> </span><span class="p">(</span><span class="nb">quot</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="mi">10</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">rem</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="mi">10</span><span class="p">))))</span><span class="w">

</span><span class="p">(</span><span class="nf">digits</span><span class="w"> </span><span class="mi">3361346435</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; [3 3 6 1 3 4 6 4 3 5]</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>That being said, I’ve also noticed that many people are approaching the problem
differently when faced with it (including me) - they typically convert the
number to string and then convert back the digit characters into
numbers. Probably the simplest way to do this is something like this:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">digits</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">read-string</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">%</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="nf">digits</span><span class="w"> </span><span class="mi">3361346435</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; (3 3 6 1 3 4 6 4 3 5)</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Notably, this solution doesn’t require using the Java interop or any clever tricks.
If you know Java’s API a bit better you might think of leveraging <code class="language-plaintext highlighter-rouge">Character/digit</code> instead:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">digits</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">Character/digit</span><span class="w"> </span><span class="n">%</span><span class="w"> </span><span class="mi">10</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Much simpler, right? Now it’s time for the final approach to solving the problem that is relatively common - namely a simple but clever trick to convert digit characters into numbers:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">char-&gt;int</span><span class="w"> </span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="p">(</span><span class="nb">int</span><span class="w"> </span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="mi">48</span><span class="p">))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">digits</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="n">char-&gt;int</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>This relies on the fact that the integer value for <code class="language-plaintext highlighter-rouge">\0</code> is 48, for <code class="language-plaintext highlighter-rouge">\1</code> is 49 and so on. For some reason that’s my favorite solution - probably because I love programming puzzles and I like (occasionally) writing unreadable code.</p>

<p>So, who has a different approach for converting a number to its digits? I’d love to hear about it!</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="Clojure" /><category term="Trick" /><summary type="html"><![CDATA[If you’re into programming puzzles you probably know that there’s a whole class of problems about doing something (e.g. some calculations) with the digits of a number. This means you need to break down a number into its digits first. I’ve always assumed that those problems exist just because decomposing a number to its digits is a classic example of recursion:]]></summary></entry><entry><title type="html">Clojure Tricks: Zipping Things Together</title><link href="https://batsov.com/articles/2022/07/31/clojure-tricks-zipping-things-together/" rel="alternate" type="text/html" title="Clojure Tricks: Zipping Things Together" /><published>2022-07-31T14:10:00+03:00</published><updated>2022-07-31T14:10:00+03:00</updated><id>https://batsov.com/articles/2022/07/31/clojure-tricks-zipping-things-together</id><content type="html" xml:base="https://batsov.com/articles/2022/07/31/clojure-tricks-zipping-things-together/"><![CDATA[<p>Many programming languages have a function for combining the elements of multiple collections (e.g. arrays or lists) together. Typically this function is named <code class="language-plaintext highlighter-rouge">zip</code>. Here’s an example from Haskell:</p>

<div class="language-haskell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
</pre></td><td class="rouge-code"><pre><span class="n">zip</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">]</span> <span class="p">[</span><span class="sc">'a'</span><span class="p">,</span> <span class="sc">'b'</span><span class="p">]</span> <span class="c1">-- =&gt; [(1, 'a'), (2, 'b')]</span>
</pre></td></tr></tbody></table></code></pre></div></div>

<p>Clojure doesn’t have a <code class="language-plaintext highlighter-rouge">zip</code> function in the standard library, which leads many newcomers to the language to wonder what to use in its place. The answer is quite simple:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="rouge-code"><pre><span class="c1">;; let's zip a couple of lists, even if no one really uses them in Clojure</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">)</span><span class="w"> </span><span class="o">'</span><span class="p">(</span><span class="nf">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">))</span><span class="w">
</span><span class="c1">;; =&gt; ([1 4] [2 5] [3 6])</span><span class="w">

</span><span class="c1">;; works with vectors as well</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">])</span><span class="w">
</span><span class="c1">;; =&gt; ([1 4] [2 5] [3 6])</span><span class="w">

</span><span class="c1">;; actually this works with anything seq-able</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="s">"this"</span><span class="w"> </span><span class="s">"that"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; ([\t \t] [\h \h] [\i \a] [\s \t])</span><span class="w">

</span><span class="c1">;; and you can mix and match different seq types</span><span class="w">
</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="p">]</span><span class="w"> </span><span class="s">"this"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; ([1 \t] [2 \h] [3 \i] [4 \s])</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>The function <code class="language-plaintext highlighter-rouge">vector</code> takes a variable number of arguments and produces a vector out of them. And vectors happen to be the idiomatic way to represent the concept of tuples (common in other functional programming languages) in Clojure. By the way, you can zip as many sequences together as your heart desires:<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup></p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">7</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="mi">9</span><span class="p">])</span><span class="w">
</span><span class="c1">;; =&gt; ([1 4 7] [2 5 8] [3 6 9])</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>And they don’t all have to be of the same length either:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">vector</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">7</span><span class="w"> </span><span class="mi">8</span><span class="w"> </span><span class="mi">9</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">10</span><span class="w"> </span><span class="mi">11</span><span class="p">])</span><span class="w">
</span><span class="c1">;; =&gt; ([1 4 7 10] [2 5 8 11])</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>One more thing… Clojure also has a function named <code class="language-plaintext highlighter-rouge">zipmap</code> that can zip a couple of seqs into a map:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nb">zipmap</span><span class="w"> </span><span class="p">[</span><span class="no">:a</span><span class="w"> </span><span class="no">:b</span><span class="w"> </span><span class="no">:c</span><span class="w"> </span><span class="no">:d</span><span class="w"> </span><span class="no">:e</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="p">])</span><span class="w">
</span><span class="c1">;; =&gt; {:a 1, :b 2, :c 3, :d 4, :e 5}</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>That’s all I have for you today. Zip long and prosper!</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>That’s a big advantage over Haskell’s <code class="language-plaintext highlighter-rouge">zip</code> mentioned earlier, as it can only combine two lists. There’s a similar function called <code class="language-plaintext highlighter-rouge">zip3</code> that can combine three lists. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Bozhidar Batsov</name></author><category term="Clojure" /><category term="Trick" /><summary type="html"><![CDATA[Many programming languages have a function for combining the elements of multiple collections (e.g. arrays or lists) together. Typically this function is named zip. Here’s an example from Haskell:]]></summary></entry><entry><title type="html">Clojure Tricks: Replace in String</title><link href="https://batsov.com/articles/2022/07/31/clojure-tricks-replace-in-string/" rel="alternate" type="text/html" title="Clojure Tricks: Replace in String" /><published>2022-07-31T11:12:00+03:00</published><updated>2022-07-31T11:12:00+03:00</updated><id>https://batsov.com/articles/2022/07/31/clojure-tricks-replace-in-string</id><content type="html" xml:base="https://batsov.com/articles/2022/07/31/clojure-tricks-replace-in-string/"><![CDATA[<p>Today I saw a clever bit of Clojure code involving <code class="language-plaintext highlighter-rouge">clojure.string/replace</code>, that reminded me how powerful the Clojure standard library is. I guess pretty much everyone knows that <code class="language-plaintext highlighter-rouge">replace</code> is normally used to replace some part of a string using a regular expression to describe what exactly to replace:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
3
4
5
6
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nf">str/replace</span><span class="w"> </span><span class="s">"OCaml rocks!"</span><span class="w"> </span><span class="o">#</span><span class="s">"([Hh]askell)|([Oo][Cc]aml)"</span><span class="w"> </span><span class="s">"Clojure"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; "Clojure rocks!"</span><span class="w">

</span><span class="c1">;; we can refer to the match groups in the replacement string</span><span class="w">
</span><span class="p">(</span><span class="nf">str/replace</span><span class="w"> </span><span class="s">"Haskell rocks!"</span><span class="w"> </span><span class="o">#</span><span class="s">"([Hh]askell)|([Oo][Cc]aml)"</span><span class="w"> </span><span class="s">"$1 is nice, but Clojure"</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; "Haskell is nice, but Clojure rocks!"</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Pretty useful and pretty straightforward. But wait, there’s more! I had forgotten you can actually use a function for the replacement, which allows us to do more sophisticated things. Here’s how we can capitalize every word with 5 or more letters in a string:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nf">str/replace</span><span class="w"> </span><span class="s">"master of Clojure is pulling the strings"</span><span class="w"> </span><span class="o">#</span><span class="s">"\w{5,}"</span><span class="w"> </span><span class="n">str/upper-case</span><span class="p">)</span><span class="w">
</span><span class="c1">;; =&gt; "MASTER of CLOJURE is PULLING the STRINGS"</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>If you’ve got more match groups in your regular expression you can use all of them in the function that you’re using to generate the replacements:</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><table class="rouge-table"><tbody><tr><td class="rouge-gutter gl"><pre class="lineno">1
2
</pre></td><td class="rouge-code"><pre><span class="p">(</span><span class="nf">str/replace</span><span class="w"> </span><span class="s">"pom kon sor"</span><span class="w"> </span><span class="o">#</span><span class="s">"(.)o(.)"</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[[</span><span class="n">_</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">b</span><span class="p">]]</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="p">(</span><span class="nf">str/upper-case</span><span class="w"> </span><span class="n">a</span><span class="p">)</span><span class="w"> </span><span class="s">"-o-"</span><span class="w"> </span><span class="p">(</span><span class="nf">str/upper-case</span><span class="w"> </span><span class="n">b</span><span class="p">))))</span><span class="w">
</span><span class="s">"P-o-M K-o-N S-o-R"</span><span class="w">
</span></pre></td></tr></tbody></table></code></pre></div></div>

<p>Note here the use of destructuring to account that each match is essentially a vector of the full match and each group match (e.g. <code class="language-plaintext highlighter-rouge">["pom" "p" "m"]</code>).</p>

<p>That’s all I have for you today! Feel free to share with me more fun usages of <code class="language-plaintext highlighter-rouge">replace</code>!</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="Clojure" /><category term="Trick" /><summary type="html"><![CDATA[Today I saw a clever bit of Clojure code involving clojure.string/replace, that reminded me how powerful the Clojure standard library is. I guess pretty much everyone knows that replace is normally used to replace some part of a string using a regular expression to describe what exactly to replace:]]></summary></entry><entry><title type="html">Interactive Programming in a Nutshell</title><link href="https://batsov.com/articles/2021/12/24/interactive-programming-in-a-nutshell/" rel="alternate" type="text/html" title="Interactive Programming in a Nutshell" /><published>2021-12-24T10:16:00+02:00</published><updated>2021-12-24T10:16:00+02:00</updated><id>https://batsov.com/articles/2021/12/24/interactive-programming-in-a-nutshell</id><content type="html" xml:base="https://batsov.com/articles/2021/12/24/interactive-programming-in-a-nutshell/"><![CDATA[<p>Today I came across this great summary of the concept of interactive programming:</p>

<blockquote>
  <p>Development in Common Lisp is interactive. There’s no separate compile/run/debug cycle. Instead of that, the program is developed while it runs. Compilation is incremental, and functions can be created and updated on the fly. As the program is running, all objects are available and can be inspected all the time. This is much more than a simple REPL; the whole environment, from the IDE to the language is prepared for this type of development.</p>

  <p>– https://common-lisp.net/features</p>
</blockquote>

<p>Obviously, this is not something specific to Common Lisp and it applies to most Lisp dialects and many other programming languages.</p>

<p>I was first exposed to interactive programming when studying Common Lisp in 2005. Back then I came across <a href="https://www.youtube.com/watch?v=NUpAvqa5hQw">a SLIME screencast</a> by Marco Baringer that blew my mind (I was mostly programming in C++ and Java at the time).<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> Today such a workflow feels just as magical and special as it did all those years ago.</p>

<p>For me interactive programming is probably <em>the most important advantage</em> of Lisps and Emacs over other programming languages and editors. I cannot imagine any productive workflow without it!</p>

<p>I’ve written a bit about interactive programming with Clojure and Emacs <a href="https://docs.cider.mx/cider/usage/interactive_programming.html">here</a>. Still, I always feel that this is one of those concepts that you can’t really understand until you’ve experienced it. Just like the Matrix.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>I still have it on my todo list to record a similar screencast for CIDER. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;&#xfe0e;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Bozhidar Batsov</name></author><category term="Lisp" /><category term="Clojure" /><category term="Emacs" /><category term="Interactive Programming" /><summary type="html"><![CDATA[Today I came across this great summary of the concept of interactive programming:]]></summary></entry><entry><title type="html">Advent of Code 2021</title><link href="https://batsov.com/articles/2021/12/02/advent-of-code-2021/" rel="alternate" type="text/html" title="Advent of Code 2021" /><published>2021-12-02T11:29:00+02:00</published><updated>2021-12-02T11:29:00+02:00</updated><id>https://batsov.com/articles/2021/12/02/advent-of-code-2021</id><content type="html" xml:base="https://batsov.com/articles/2021/12/02/advent-of-code-2021/"><![CDATA[<p>I love programming puzzles, even if I’ve never been particularly good at solving
them. For me they were always a good way to gain some practice with a new
programming language and to push myself to think for things unrelated to my job
or my own projects. Optimizing the performance of solutions to puzzles and
reading the solutions of other people is a very educational experience as
well. In recent years I rarely had time to play with puzzles, but this year I’ll
try to find a bit of time for <a href="https://adventofcode.com/2021">Advent of Code</a>.</p>

<p>I’ll be using Clojure to solve the puzzles and I’ll post my solutions to <a href="https://github.com/bbatsov/advent-of-code2021">GitHub</a>. You can say that I’m also looking for an excuse to use <a href="https://github.com/clojure-emacs/cider/">CIDER</a> for anything else besides developing CIDER.</p>

<p>I already solved the first 4 puzzles (you get to solve 2 each day) and this was a lot of fun. Let’s see how far I’ll manage to get. If I manage to solve half the puzzles I’ll consider this a great success!</p>

<p>P.S. Don’t worry, I don’t plan to spam you daily with puzzle solutions!</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="Meta" /><category term="Clojure" /><category term="Advent of Code" /><summary type="html"><![CDATA[I love programming puzzles, even if I’ve never been particularly good at solving them. For me they were always a good way to gain some practice with a new programming language and to push myself to think for things unrelated to my job or my own projects. Optimizing the performance of solutions to puzzles and reading the solutions of other people is a very educational experience as well. In recent years I rarely had time to play with puzzles, but this year I’ll try to find a bit of time for Advent of Code.]]></summary></entry><entry><title type="html">CIDER 0.9</title><link href="https://batsov.com/articles/2015/06/16/cider-0-dot-9/" rel="alternate" type="text/html" title="CIDER 0.9" /><published>2015-06-16T15:59:00+03:00</published><updated>2015-06-16T15:59:00+03:00</updated><id>https://batsov.com/articles/2015/06/16/cider-0-dot-9</id><content type="html" xml:base="https://batsov.com/articles/2015/06/16/cider-0-dot-9/"><![CDATA[<p><a href="https://github.com/clojure-emacs/cider">CIDER</a> 0.9 (a.k.a. “EuroCIDER”) is
finally out and it’s our best release yet! (shocker, right?) It took a lot
more time than I originally anticipated, but at least we managed to ship in time
for <a href="http://euroclojure.org">EuroClojure</a>!</p>

<p>There are a ton of important changes and new features in 0.9 and now I’ll go
quickly through some of them.</p>

<!--more-->
<h2 id="new-features">New Features</h2>

<h3 id="debugger">Debugger</h3>

<p>Believe it or not CIDER now has a debugger! This was like
the most requested feature ever, so I’m sure at least some of you are
excited. The debugger was developed by the awesome
<a href="http://endlessparentheses.com">Artur Malabarba</a>. He even wrote
<a href="http://endlessparentheses.com/cider-debug-a-visual-interactive-debugger-for-clojure.html">a post about it</a>
and I guess you should read it.</p>

<h3 id="dependency-isolation">Dependency isolation</h3>

<p>CIDER’s dependencies will no longer affect your projects (read this as
<em>introduce dependency conflicts in them</em>). All the dependencies are
now isolated using source rewriting (simply put - they live in
different namespaces than the original libraries). This magic is done by
<a href="https://github.com/benedekfazekas/mranderson">mranderson</a>. Thanks to
<a href="https://github.com/benedekfazekas">Benedek Fazekas</a> for creating this
small but super helpful tool!</p>

<h3 id="rich-code-completion">Rich code completion</h3>

<p>Completion candidates are now annotated with information about the
namespace and the type of the thing being completed. It’s pretty neat.</p>

<p><img src="https://raw.githubusercontent.com/clojure-emacs/cider/master/doc/modules/ROOT/assets/img/completion-annotations.png" alt="Completion Annotations" /></p>

<p>The screenshot above features
<a href="http://company-mode.github.io/">company-mode</a>. The annotations are
not supported in <code class="language-plaintext highlighter-rouge">auto-complete-mode</code> (that’s a limitation of AC, not
a limitation of CIDER).</p>

<h3 id="misc-additions">Misc additions</h3>

<p>Here’s a short list of other important additions:</p>

<ul>
  <li>Support for Piggieback 0.2</li>
  <li>New code formatting commands (based on <a href="https://github.com/weavejester/cljfmt">cljfmt</a>)</li>
  <li>New EDN data formatting commands</li>
</ul>

<h2 id="changes">Changes</h2>

<p>There were also a few important changes. Most notably we had to
<a href="https://github.com/clojure-emacs/cider/issues/1088">kill source-tracking code evaluation</a>,
as it wasn’t playing nice with ClojureScript. This was also a hacky
solution and I still hope than one day this will be properly supported
in nREPL itself. In simple terms - var definitions evaluated by
themselves won’t have any location metadata set for them, which will
make it impossible to go their definition.  You can also help out by
voicing your support for this
<a href="http://dev.clojure.org/jira/browse/NREPL-59">nREPL ticket</a>’s patch to
be merged.</p>

<p>You’ll also notice that some commands that didn’t prompt for
confirmation in the past do so now (e.g. <code class="language-plaintext highlighter-rouge">find-var</code>).  This was done mostly for
consistency with Emacs’s own commands that do similar things. The
behavior is configurable via <code class="language-plaintext highlighter-rouge">cider-prompt-for-symbol</code>. If a ton of
people dislike the new defaults reverting them is on the table.</p>

<h2 id="all-the-gory-details">All the Gory Details</h2>

<p>There were truly a ton of changes and there’s little point in me
repeating them here. If you want to know everything have a look at the
<a href="https://github.com/clojure-emacs/cider/releases/tag/v0.9.0">release notes</a>.</p>

<h2 id="the-road-ahead">The Road Ahead</h2>

<p>Going forward our top priority will be merging some functionality from
<a href="https://github.com/clojure-emacs/refactor-nrepl">refactor-nrepl</a> and
<a href="https://github.com/clojure-emacs/clj-refactor.el">clj-refactor</a> into
CIDER itself.  Think of things like <code class="language-plaintext highlighter-rouge">find-usages</code>,
<code class="language-plaintext highlighter-rouge">extract-definition</code>, etc. Refining the debugger will be another top
priority.</p>

<p>We’ll also try to do some important internal changes:</p>

<ul>
  <li><a href="https://github.com/clojure-emacs/cider/issues/1068">reorganize the entire codebase in a more sensible manner</a></li>
  <li><a href="https://github.com/clojure-emacs/cider/issues/1099">rework nREPL response handling</a></li>
  <li><a href="https://github.com/clojure-emacs/cider/issues/709">rework the REPL to use <code class="language-plaintext highlighter-rouge">comint-mode</code></a></li>
  <li><a href="https://github.com/clojure-emacs/cider/issues/732">improve quitting and restarting</a></li>
</ul>

<p>Depending on how well we progress on those tasks the next release will
be either 0.10 or 1.0. I won’t make any commitments about its release
date (but judging from past it will likely be 3 to 6 months from now).</p>

<p>If you’re wondering why things are moving more slowly lately, here’s
the answer for you - I’ve been super busy since the beginning of the
year and haven’t had much time for open-source projects. I’m hoping
this will change, but only time will tell.  I’m very happy that a lot
of people contributed to the development of CIDER 0.9. The project
definitely doesn’t have a bus factor of one.</p>

<p>Special thanks to <a href="https://github.com/cichli">Michael Griffiths</a> who
did a ton of great work on this release. You rock!</p>

<p><strong>P.S.</strong> Recently I talked on the
<a href="http://blog.cognitect.com/cognicast">Cognicast</a> about CIDER (in
general and 0.9 in particular). You might find
<a href="http://blog.cognitect.com/cognicast/080">this episode</a> interesting.</p>

<p><strong>P.P.S.</strong> I’m rarely on IRC these days. <code class="language-plaintext highlighter-rouge">#cider</code> on
  <a href="https://clojurians.slack.com/">slack</a> and our
  <a href="https://gitter.im/clojure-emacs/cider">gitter channel</a> are now the
  official CIDER chats as far as I’m concerned.</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="Emacs" /><category term="Clojure" /><category term="CIDER" /><summary type="html"><![CDATA[CIDER 0.9 (a.k.a. “EuroCIDER”) is finally out and it’s our best release yet! (shocker, right?) It took a lot more time than I originally anticipated, but at least we managed to ship in time for EuroClojure!]]></summary></entry><entry><title type="html">Introducing inf-clojure - a Better Basic Clojure REPL for Emacs</title><link href="https://batsov.com/articles/2014/12/04/introducing-inf-clojure-a-better-basic-clojure-repl-for-emacs/" rel="alternate" type="text/html" title="Introducing inf-clojure - a Better Basic Clojure REPL for Emacs" /><published>2014-12-04T12:45:00+02:00</published><updated>2014-12-04T12:45:00+02:00</updated><id>https://batsov.com/articles/2014/12/04/introducing-inf-clojure-a-better-basic-clojure-repl-for-emacs</id><content type="html" xml:base="https://batsov.com/articles/2014/12/04/introducing-inf-clojure-a-better-basic-clojure-repl-for-emacs/"><![CDATA[<p>At <a href="http://clojure-conj.org/">Clojure/conj</a> I had the chance to shake
Rich Hickey’s hand and exchange a few words with him. When I asked him
whether he currently uses CIDER or Cursive for Clojure development he
replied that he preferred a simpler solution – <code class="language-plaintext highlighter-rouge">clojure-mode</code> &amp;
<code class="language-plaintext highlighter-rouge">inferior-lisp-mode</code>.</p>

<p>I was a bit surprised because <code class="language-plaintext highlighter-rouge">clojure-mode</code>’s
integration with <code class="language-plaintext highlighter-rouge">inferior-lisp-mode</code> sucks (big time). It has always
been extremely limited and was never really improved/extended. It has
no Clojure specific features and no code completion. I felt that Rich
and all the people using <code class="language-plaintext highlighter-rouge">inferior-lisp-mode</code> deserved something better,
so I quickly put together <a href="https://github.com/clojure-emacs/inf-clojure">inf-clojure</a>.</p>

<p><code class="language-plaintext highlighter-rouge">inf-clojure</code> provides some Clojure specific features like showing a
var’s doc or source, derives some core functionality from <code class="language-plaintext highlighter-rouge">clojure-mode</code>
and even features basic code-completion (and <code class="language-plaintext highlighter-rouge">company-mode</code>
support). That’s not much admittedly, but it’s a good start. Extending
<code class="language-plaintext highlighter-rouge">inf-clojure</code> is super easy and I expect that we’ll add a bit more
features to it along the way (e.g. macroexpansion).</p>

<p><code class="language-plaintext highlighter-rouge">inf-clojure</code> is available in MELPA and will eventually replace
completely <code class="language-plaintext highlighter-rouge">inferior-lisp-mode</code> when <code class="language-plaintext highlighter-rouge">clojure-mode</code> 4.0 is released.</p>

<p>Keep in mind that <code class="language-plaintext highlighter-rouge">inf-clojure</code> is nothing like CIDER and will never
be. CIDER will always be the powertool for Clojure programming in
Emacs. I do understand, however, that some people are overwhelmed by
CIDER and some people simply don’t need anything sophisticated. I hope
they’ll enjoy <code class="language-plaintext highlighter-rouge">inf-clojure</code>!</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="Clojure" /><category term="Emacs" /><summary type="html"><![CDATA[At Clojure/conj I had the chance to shake Rich Hickey’s hand and exchange a few words with him. When I asked him whether he currently uses CIDER or Cursive for Clojure development he replied that he preferred a simpler solution – clojure-mode &amp; inferior-lisp-mode.]]></summary></entry><entry><title type="html">A CIDER Unsession at Clojure/conj</title><link href="https://batsov.com/articles/2014/11/15/a-cider-unsession-at-clojure-slash-conj/" rel="alternate" type="text/html" title="A CIDER Unsession at Clojure/conj" /><published>2014-11-15T20:17:00+02:00</published><updated>2014-11-15T20:17:00+02:00</updated><id>https://batsov.com/articles/2014/11/15/a-cider-unsession-at-clojure-slash-conj</id><content type="html" xml:base="https://batsov.com/articles/2014/11/15/a-cider-unsession-at-clojure-slash-conj/"><![CDATA[<p>I’ll be talking about the evolution of CIDER at the
<a href="http://clojure-conj.org/">conj</a>, but I won’t be able to show much (in
terms of features) during my talk. Luckily, however, beside the talks
we also have the option for <a href="https://github.com/cognitect/clojure-conj/wiki/Clojure-conj-2014-Unsessions">unsessions</a>. Here’s my proposal for one such unsession…</p>

<p>I’d like to do a more extensive demonstration of the general
workflow with CIDER and all the cool things we’ve done recently and
I’d also like discuss with our users (and potential users) existing
problems, ideas for improvements and the future direction of the
project. If you like my idea you can show your support for it
<a href="https://github.com/cognitect/clojure-conj/wiki/Clojure-conj-2014-Unsessions#cider-demoqa">here</a>.</p>

<p>Feedback is important and I’d like to get as much as possible
to make CIDER better!</p>]]></content><author><name>Bozhidar Batsov</name></author><category term="CIDER" /><category term="Clojure" /><category term="Emacs" /><summary type="html"><![CDATA[I’ll be talking about the evolution of CIDER at the conj, but I won’t be able to show much (in terms of features) during my talk. Luckily, however, beside the talks we also have the option for unsessions. Here’s my proposal for one such unsession…]]></summary></entry></feed>