<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: c</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/c.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2026-02-22T23:58:43+00:00</updated><author><name>Simon Willison</name></author><entry><title>The Claude C Compiler: What It Reveals About the Future of Software</title><link href="https://simonwillison.net/2026/Feb/22/ccc/#atom-tag" rel="alternate"/><published>2026-02-22T23:58:43+00:00</published><updated>2026-02-22T23:58:43+00:00</updated><id>https://simonwillison.net/2026/Feb/22/ccc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.modular.com/blog/the-claude-c-compiler-what-it-reveals-about-the-future-of-software"&gt;The Claude C Compiler: What It Reveals About the Future of Software&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
On February 5th Anthropic's Nicholas Carlini wrote about a project to use &lt;a href="https://www.anthropic.com/engineering/building-c-compiler"&gt;parallel Claudes to build a C compiler&lt;/a&gt; on top of the brand new Opus 4.6&lt;/p&gt;
&lt;p&gt;Chris Lattner (Swift, LLVM, Clang, Mojo) knows more about C compilers than most. He just published this review of the code.&lt;/p&gt;
&lt;p&gt;Some points that stood out to me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Good software depends on judgment, communication, and clear abstraction. AI has amplified this.&lt;/li&gt;
&lt;li&gt;AI coding is automation of implementation, so design and stewardship become more important.&lt;/li&gt;
&lt;li&gt;Manual rewrites and translation work are becoming AI-native tasks, automating a large category of engineering effort.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Chris is generally impressed with CCC (the Claude C Compiler):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Taken together, CCC looks less like an experimental research compiler and more like a competent textbook implementation, the sort of system a strong undergraduate team might build early in a project before years of refinement. That alone is remarkable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's a long way from being a production-ready compiler though:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Several design choices suggest optimization toward passing tests rather than building general abstractions like a human would. [...] These flaws are informative rather than surprising, suggesting that current AI systems excel at assembling known techniques and optimizing toward measurable success criteria, while struggling with the open-ended generalization required for production-quality systems.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The project also leads to deep open questions about how agentic engineering interacts with licensing and IP for both open source and proprietary code:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If AI systems trained on decades of publicly available code can reproduce familiar structures, patterns, and even specific implementations, where exactly is the boundary between learning and copying?&lt;/p&gt;
&lt;/blockquote&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/compilers"&gt;compilers&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/open-source"&gt;open-source&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nicholas-carlini"&gt;nicholas-carlini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/agentic-engineering"&gt;agentic-engineering&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="compilers"/><category term="open-source"/><category term="ai"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="nicholas-carlini"/><category term="coding-agents"/><category term="agentic-engineering"/></entry><entry><title>Opus 4.6 and Codex 5.3</title><link href="https://simonwillison.net/2026/Feb/5/two-new-models/#atom-tag" rel="alternate"/><published>2026-02-05T20:29:20+00:00</published><updated>2026-02-05T20:29:20+00:00</updated><id>https://simonwillison.net/2026/Feb/5/two-new-models/#atom-tag</id><summary type="html">
    &lt;p&gt;Two major new model releases today, within about 15 minutes of each other.&lt;/p&gt;
&lt;p&gt;Anthropic &lt;a href="https://www.anthropic.com/news/claude-opus-4-6"&gt;released Opus 4.6&lt;/a&gt;. Here's &lt;a href="https://gist.github.com/simonw/a6806ce41b4c721e240a4548ecdbe216"&gt;its pelican&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Slightly wonky bicycle frame but an excellent pelican, very clear beak and pouch, nice feathers." src="https://static.simonwillison.net/static/2026/opus-4.6-pelican.png" /&gt;&lt;/p&gt;
&lt;p&gt;OpenAI &lt;a href="https://openai.com/index/introducing-gpt-5-3-codex/"&gt;release GPT-5.3-Codex&lt;/a&gt;, albeit only via their Codex app, not yet in their API. Here's &lt;a href="https://gist.github.com/simonw/bfc4a83f588ac762c773679c0d1e034b"&gt;its pelican&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Not nearly as good - the bicycle is a bit mangled, the pelican not nearly as well rendered - it's more of a line drawing." src="https://static.simonwillison.net/static/2026/codex-5.3-pelican.png" /&gt;&lt;/p&gt;
&lt;p&gt;I've had a bit of preview access to both of these models and to be honest I'm finding it hard to find a good angle to write about them - they're both &lt;em&gt;really good&lt;/em&gt;, but so were their predecessors Codex 5.2 and Opus 4.5. I've been having trouble finding tasks that those previous models couldn't handle but the new ones are able to ace.&lt;/p&gt;
&lt;p&gt;The most convincing story about capabilities of the new model so far is Nicholas Carlini from Anthropic talking about Opus 4.6 and &lt;a href="https://www.anthropic.com/engineering/building-c-compiler"&gt;Building a C compiler with a team of parallel Claudes&lt;/a&gt; - Anthropic's version of Cursor's &lt;a href="https://simonwillison.net/2026/Jan/23/fastrender/"&gt;FastRender project&lt;/a&gt;.&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/openai"&gt;openai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nicholas-carlini"&gt;nicholas-carlini&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pelican-riding-a-bicycle"&gt;pelican-riding-a-bicycle&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm-release"&gt;llm-release&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/parallel-agents"&gt;parallel-agents&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="ai"/><category term="openai"/><category term="generative-ai"/><category term="llms"/><category term="anthropic"/><category term="nicholas-carlini"/><category term="pelican-riding-a-bicycle"/><category term="llm-release"/><category term="parallel-agents"/></entry><entry><title>FLUX.2-klein-4B Pure C Implementation</title><link href="https://simonwillison.net/2026/Jan/18/flux2-klein-4b/#atom-tag" rel="alternate"/><published>2026-01-18T23:58:58+00:00</published><updated>2026-01-18T23:58:58+00:00</updated><id>https://simonwillison.net/2026/Jan/18/flux2-klein-4b/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/antirez/flux2.c"&gt;FLUX.2-klein-4B Pure C Implementation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
On 15th January Black Forest Labs, a lab formed by the creators of the original Stable Diffusion, released &lt;a href="https://huggingface.co/black-forest-labs/FLUX.2-klein-4B"&gt;black-forest-labs/FLUX.2-klein-4B&lt;/a&gt; - an Apache 2.0 licensed 4 billion parameter version of their FLUX.2 family.&lt;/p&gt;
&lt;p&gt;Salvatore Sanfilippo (antirez) decided to build a pure C and dependency-free implementation to run the model, with assistance from Claude Code and Claude Opus 4.5.&lt;/p&gt;
&lt;p&gt;Salvatore shared &lt;a href="https://news.ycombinator.com/item?id=46670279#46671233"&gt;this note&lt;/a&gt; on Hacker News:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Something that may be interesting for the reader of this thread: this project was possible only once I started to tell Opus that it &lt;em&gt;needed&lt;/em&gt; to take a file with all the implementation notes, and also accumulating all the things we discovered during the development process. And also, the file had clear instructions to be taken updated, and to be processed ASAP after context compaction. This kinda enabled Opus to do such a big coding task in a reasonable amount of time without loosing track. Check the file IMPLEMENTATION_NOTES.md in the GitHub repo for more info.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here's that &lt;a href="https://github.com/antirez/flux2.c/blob/main/IMPLEMENTATION_NOTES.md"&gt;IMPLEMENTATION_NOTES.md&lt;/a&gt; file.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=46670279"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/salvatore-sanfilippo"&gt;salvatore-sanfilippo&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/stable-diffusion"&gt;stable-diffusion&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/text-to-image"&gt;text-to-image&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="salvatore-sanfilippo"/><category term="ai"/><category term="stable-diffusion"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="text-to-image"/><category term="coding-agents"/><category term="claude-code"/></entry><entry><title>MicroQuickJS</title><link href="https://simonwillison.net/2025/Dec/23/microquickjs/#atom-tag" rel="alternate"/><published>2025-12-23T20:53:40+00:00</published><updated>2025-12-23T20:53:40+00:00</updated><id>https://simonwillison.net/2025/Dec/23/microquickjs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/bellard/mquickjs"&gt;MicroQuickJS&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
New project from programming legend Fabrice Bellard, of ffmpeg and QEMU and QuickJS and &lt;a href="https://bellard.org"&gt;so much more&lt;/a&gt; fame:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;MicroQuickJS (aka. MQuickJS) is a Javascript engine targetted at embedded systems. It compiles and runs Javascript programs with as low as 10 kB of RAM. The whole engine requires about 100 kB of ROM (ARM Thumb-2 code) including the C library. The speed is comparable to QuickJS.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It supports &lt;a href="https://github.com/bellard/mquickjs/blob/17ce6fe54c1ea4f500f26636bd22058fce2ce61a/README.md#javascript-subset-reference"&gt;a subset of full JavaScript&lt;/a&gt;, though it looks like a rich and full-featured subset to me.&lt;/p&gt;
&lt;p&gt;One of my ongoing interests is sandboxing: mechanisms for executing untrusted code - from end users or generated by LLMs - in an environment that restricts memory usage and applies a strict time limit and restricts file or network access. Could MicroQuickJS be useful in that context?&lt;/p&gt;
&lt;p&gt;I fired up Claude Code for web (on my iPhone) and kicked off &lt;a href="https://simonwillison.net/2025/Nov/6/async-code-research/"&gt;an asynchronous research project&lt;/a&gt; to see explore that question:&lt;/p&gt;
&lt;p&gt;My full prompt &lt;a href="https://github.com/simonw/research/pull/50#issue-3757781692"&gt;is here&lt;/a&gt;. It started like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Clone https://github.com/bellard/mquickjs to /tmp&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Investigate this code as the basis for a safe sandboxing environment for running untrusted code such that it cannot exhaust memory or CPU or access files or the network&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;First try building python bindings for this using FFI - write a script that builds these by checking out the code to /tmp and building against that, to avoid copying the C code in this repo permanently. Write and execute tests with pytest to exercise it as a sandbox&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Then build a "real" Python extension not using FFI and experiment with that&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Then try compiling the C to WebAssembly and exercising it via both node.js and Deno, with a similar suite of tests [...]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I later added to the interactive session:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Does it have a regex engine that might allow a resource exhaustion attack from an expensive regex?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(The answer was no - the regex engine calls the interrupt handler even during pathological expression backtracking, meaning that any configured time limit should still hold.)&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://gistpreview.github.io/?6e07c54db7bb8ed8aa0eccfe4a384679"&gt;the full transcript&lt;/a&gt; and the &lt;a href="https://github.com/simonw/research/blob/main/mquickjs-sandbox/README.md"&gt;final report&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some key observations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MicroQuickJS is &lt;em&gt;very&lt;/em&gt; well suited to the sandbox problem. It has robust near and time limits baked in, it doesn't expose any dangerous primitive like filesystem of network access and even has a regular expression engine that protects against exhaustion attacks (provided you configure a time limit).&lt;/li&gt;
&lt;li&gt;Claude span up and tested a Python library that calls a MicroQuickJS shared library (involving a little bit of extra C), a compiled a Python binding and a library that uses the original MicroQuickJS CLI tool. All of those approaches work well.&lt;/li&gt;
&lt;li&gt;Compiling to WebAssembly was a little harder. It got a version working in Node.js and Deno and Pyodide, but the Python libraries wasmer and wasmtime proved harder, apparently because "mquickjs uses setjmp/longjmp for error handling". It managed to get to a working wasmtime version with &lt;a href="https://github.com/simonw/research/blob/main/mquickjs-sandbox/README.md#working-solution"&gt;a gross hack&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm really excited about this. MicroQuickJS is tiny, full featured, looks robust and comes from excellent pedigree. I think this makes for a very solid new entrant in the quest for a robust sandbox.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I had Claude Code build &lt;a href="https://tools.simonwillison.net/microquickjs"&gt;tools.simonwillison.net/microquickjs&lt;/a&gt;, an interactive web playground for trying out the WebAssembly build of MicroQuickJS, adapted from my previous &lt;a href="https://tools.simonwillison.net/quickjs"&gt;QuickJS plaground&lt;/a&gt;. My QuickJS page loads 2.28 MB (675 KB transferred). The MicroQuickJS one loads 303 KB (120 KB transferred).&lt;/p&gt;
&lt;p&gt;Here are &lt;a href="https://github.com/simonw/tools/pull/180#issue-3758595291"&gt;the prompts I used&lt;/a&gt; for that.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/nodejs"&gt;nodejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sandboxing"&gt;sandboxing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/deno"&gt;deno&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pyodide"&gt;pyodide&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude-code"&gt;claude-code&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/fabrice-bellard"&gt;fabrice-bellard&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="javascript"/><category term="nodejs"/><category term="python"/><category term="sandboxing"/><category term="ai"/><category term="webassembly"/><category term="deno"/><category term="pyodide"/><category term="generative-ai"/><category term="llms"/><category term="claude-code"/><category term="fabrice-bellard"/></entry><entry><title>Constant-time support lands in LLVM: Protecting cryptographic code at the compiler level</title><link href="https://simonwillison.net/2025/Nov/25/constant-time-support-lands-in-llvm/#atom-tag" rel="alternate"/><published>2025-11-25T18:32:23+00:00</published><updated>2025-11-25T18:32:23+00:00</updated><id>https://simonwillison.net/2025/Nov/25/constant-time-support-lands-in-llvm/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.trailofbits.com/2025/11/25/constant-time-support-lands-in-llvm-protecting-cryptographic-code-at-the-compiler-level/"&gt;Constant-time support lands in LLVM: Protecting cryptographic code at the compiler level&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Substantial LLVM contribution from Trail of Bits. Timing attacks against cryptography algorithms are a gnarly problem: if an attacker can precisely time a cryptographic algorithm they can often derive details of the key based on how long it takes to execute.&lt;/p&gt;
&lt;p&gt;Cryptography implementers know this and deliberately use constant-time comparisons to avoid these attacks... but sometimes an optimizing compiler will undermine these measures and reintroduce timing vulnerabilities.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Trail of Bits has developed constant-time coding support for LLVM 21, providing developers with compiler-level guarantees that their cryptographic implementations remain secure against branching-related timing attacks. This work introduces the &lt;code&gt;__builtin_ct_select&lt;/code&gt; family of intrinsics and supporting infrastructure that prevents the Clang compiler, and potentially other compilers built with LLVM, from inadvertently breaking carefully crafted constant-time code.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/occlzx/constant_time_support_lands_llvm"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cryptography"&gt;cryptography&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llvm"&gt;llvm&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="cryptography"/><category term="llvm"/></entry><entry><title>Fun-reliable side-channels for cross-container communication</title><link href="https://simonwillison.net/2025/Nov/12/h4x0rchat/#atom-tag" rel="alternate"/><published>2025-11-12T16:04:03+00:00</published><updated>2025-11-12T16:04:03+00:00</updated><id>https://simonwillison.net/2025/Nov/12/h4x0rchat/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://h4x0r.org/funreliable/"&gt;Fun-reliable side-channels for cross-container communication&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Here's a very clever hack for communicating between different processes running in different containers on the same machine. It's based on clever abuse of POSIX advisory locks which allow a process to create and detect locks across byte offset ranges:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These properties combined are enough to provide a basic cross-container side-channel primitive, because a process in one container can set a read-lock at some interval on &lt;code&gt;/proc/self/ns/time&lt;/code&gt;, and a process in another container can observe the presence of that lock by querying for a hypothetically intersecting write-lock.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I dumped &lt;a href="https://github.com/crashappsec/h4x0rchat/blob/main/h4x0rchat.c"&gt;the C proof-of-concept&lt;/a&gt; into GPT-5 for &lt;a href="https://chatgpt.com/share/6914aad2-397c-8006-b404-b9ddbd900c8f"&gt;a code-level explanation&lt;/a&gt;, then had it help me figure out how to run it in Docker. Here's the recipe that worked for me:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /tmp
wget https://github.com/crashappsec/h4x0rchat/blob/9b9d0bd5b2287501335acca35d070985e4f51079/h4x0rchat.c
docker run --rm -it -v "$PWD:/src" \
  -w /src gcc:13 bash -lc 'gcc -Wall -O2 \
  -o h4x0rchat h4x0rchat.c &amp;amp;&amp;amp; ./h4x0rchat'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run that &lt;code&gt;docker run&lt;/code&gt; line in two separate terminal windows and you can chat between the two of them like this:&lt;/p&gt;
&lt;p&gt;&lt;a style="text-decoration: none; border-bottom: none" href="https://static.simonwillison.net/static/2025/h4x0rchat.gif"&gt;&lt;img style="max-width: 100%" alt="Animated demo. Two terminal windows. Both run that command, then start a l33t speak chat interface. Each interface asks the user for a name, then messages that are typed in one are instantly displayed in the other and vice-versa." src="https://static.simonwillison.net/static/2025/h4x0rchat.gif"&gt;&lt;/a&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/3z4pro/fun_reliable_side_channels_for_cross"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/docker"&gt;docker&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="docker"/></entry><entry><title>Scaling HNSWs</title><link href="https://simonwillison.net/2025/Nov/11/scaling-hnsws/#atom-tag" rel="alternate"/><published>2025-11-11T23:38:39+00:00</published><updated>2025-11-11T23:38:39+00:00</updated><id>https://simonwillison.net/2025/Nov/11/scaling-hnsws/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://antirez.com/news/156"&gt;Scaling HNSWs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Salvatore Sanfilippo spent much of this year working on &lt;a href="https://github.com/redis/redis/blob/8.2.3/modules/vector-sets/README.md"&gt;vector sets for Redis&lt;/a&gt;, which first shipped in &lt;a href="https://redis.io/blog/redis-8-ga/"&gt;Redis 8 in May&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A big part of that work involved implementing HNSW - Hierarchical Navigable Small World - an indexing technique first introduced in &lt;a href="https://arxiv.org/abs/1603.09320"&gt;this 2016 paper&lt;/a&gt; by Yu. A. Malkov and D. A. Yashunin.&lt;/p&gt;
&lt;p&gt;Salvatore's detailed notes on the Redis implementation here offer an immersive trip through a fascinating modern field of computer science. He describes several new contributions he's made to the HNSW algorithm, mainly around efficient deletion and updating of existing indexes.&lt;/p&gt;
&lt;p&gt;Since embedding vectors are notoriously memory-hungry I particularly appreciated this note about how you can scale a large HNSW vector set across many different nodes and run parallel queries against them for both reads and writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[...] if you have different vectors about the same use case split in different instances / keys, you can ask VSIM for the same query vector into all the instances, and add the WITHSCORES option (that returns the cosine distance) and merge the results client-side, and you have magically scaled your hundred of millions of vectors into multiple instances, splitting your dataset N times [One interesting thing about such a use case is that you can query the N instances in parallel using multiplexing, if your client library is smart enough].&lt;/p&gt;
&lt;p&gt;Another very notable thing about HNSWs exposed in this raw way, is that you can finally scale writes very easily. Just hash your element modulo N, and target the resulting Redis key/instance. Multiple instances can absorb the (slow, but still fast for HNSW standards) writes at the same time, parallelizing an otherwise very slow process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It's always exciting to see new implementations of fundamental algorithms and data structures like this make it into Redis because Salvatore's C code is so clearly commented and pleasant to read - here's &lt;a href="https://github.com/redis/redis/blob/8.2.3/modules/vector-sets/hnsw.c"&gt;vector-sets/hnsw.c&lt;/a&gt; and &lt;a href="https://github.com/redis/redis/blob/8.2.3/modules/vector-sets/vset.c"&gt;vector-sets/vset.c&lt;/a&gt;.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=45887466"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/algorithms"&gt;algorithms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/computer-science"&gt;computer-science&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/data-structures"&gt;data-structures&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/salvatore-sanfilippo"&gt;salvatore-sanfilippo&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vector-search"&gt;vector-search&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/embeddings"&gt;embeddings&lt;/a&gt;&lt;/p&gt;



</summary><category term="algorithms"/><category term="c"/><category term="computer-science"/><category term="data-structures"/><category term="redis"/><category term="salvatore-sanfilippo"/><category term="vector-search"/><category term="embeddings"/></entry><entry><title>Geoffrey Huntley is cursed</title><link href="https://simonwillison.net/2025/Sep/9/cursed/#atom-tag" rel="alternate"/><published>2025-09-09T09:31:21+00:00</published><updated>2025-09-09T09:31:21+00:00</updated><id>https://simonwillison.net/2025/Sep/9/cursed/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://ghuntley.com/cursed/"&gt;I ran Claude in a loop for three months, and it created a genz programming language called cursed&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Geoffrey Huntley vibe-coded an entirely new programming language using Claude:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The programming language is called "cursed". It's cursed in its lexical structure, it's cursed in how it was built, it's cursed that this is possible, it's cursed in how cheap this was, and it's cursed through how many times I've sworn at Claude.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Geoffrey's initial prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Hey, can you make me a programming language like Golang but all the lexical keywords are swapped so they're Gen Z slang?&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then he pushed it to keep on iterating over a three month period.&lt;/p&gt;
&lt;p&gt;Here's Hello World:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vibe main
yeet "vibez"

slay main() {
    vibez.spill("Hello, World!")
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And here's &lt;a href="https://github.com/ghuntley/cursed/blob/ecda33d496e1562e0e02efb25b6936ad94e79b72/test_suite/leetcode_comprehensive_suite/binary_search/704_binary_search_backup.%F0%9F%92%80"&gt;binary search&lt;/a&gt;, part of &lt;a href="https://github.com/ghuntley/cursed/tree/zig/test_suite/leetcode_comprehensive_suite"&gt;17+ LeetCode problems&lt;/a&gt; that run as part of the test suite:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;slay binary_search(nums normie[], target normie) normie {
    sus left normie = 0
    sus right normie = len(nums) - 1    
    bestie (left &amp;lt;= right) {
        sus mid normie = left + (right - left) / 2
        ready (nums[mid] == target) {
            damn mid
        }
        ready (nums[mid] &amp;lt; target) {
            left = mid + 1
        } otherwise {
            right = mid - 1
        }
    }
    damn -1
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a &lt;em&gt;substantial&lt;/em&gt; project. The repository currently has &lt;a href="https://github.com/ghuntley/cursed/commits/zig/"&gt;1,198 commits&lt;/a&gt;. It has both an interpreter mode and a compiler mode, and can compile programs to native binaries (via LLVM) for macOS, Linux and Windows.&lt;/p&gt;
&lt;p&gt;It looks like it was mostly built using Claude running via &lt;a href="https://ampcode.com/"&gt;Sourcegraph's Amp&lt;/a&gt;, which produces &lt;a href="https://github.com/ghuntley/cursed/commit/ec5be8a4c4f6e82f6b93774a9b3b3f88308680dd"&gt;detailed commit messages&lt;/a&gt;. The commits include links to archived Amp sessions but sadly those don't appear to be publicly visible.&lt;/p&gt;
&lt;p&gt;The first version was written in C, then Geoffrey had Claude port it to Rust and then Zig. &lt;a href="https://twitter.com/GeoffreyHuntley/status/1965295152962097550"&gt;His cost estimate&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Technically it costs about 5k usd to build your own compiler now because cursed was implemented first in c, then rust, now zig. So yeah, it’s not one compiler it’s three editions of it. For a total of $14k USD.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://x.com/GeoffreyHuntley/status/1965258228314636524"&gt;@GeoffreyHuntley&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming-languages"&gt;programming-languages&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/zig"&gt;zig&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/anthropic"&gt;anthropic&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/claude"&gt;claude&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vibe-coding"&gt;vibe-coding&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/geoffrey-huntley"&gt;geoffrey-huntley&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="programming-languages"/><category term="ai"/><category term="rust"/><category term="zig"/><category term="generative-ai"/><category term="llms"/><category term="ai-assisted-programming"/><category term="anthropic"/><category term="claude"/><category term="vibe-coding"/><category term="geoffrey-huntley"/></entry><entry><title>tidwall/pogocache</title><link href="https://simonwillison.net/2025/Jul/21/pogocache/#atom-tag" rel="alternate"/><published>2025-07-21T23:58:53+00:00</published><updated>2025-07-21T23:58:53+00:00</updated><id>https://simonwillison.net/2025/Jul/21/pogocache/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/tidwall/pogocache"&gt;tidwall/pogocache&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
New project from Josh Baker, author of the excellent &lt;code&gt;tg&lt;/code&gt; C geospatial libarry (&lt;a href="https://simonwillison.net/2023/Sep/23/tg-polygon-indexing/"&gt;covered previously&lt;/a&gt;) and various other &lt;a href="https://github.com/tidwall"&gt;interesting projects&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pogocache is fast caching software built from scratch with a focus on low latency and cpu efficency.&lt;/p&gt;
&lt;p&gt;Faster: Pogocache is faster than Memcache, Valkey, Redis, Dragonfly, and Garnet. It has the lowest latency per request, providing the quickest response times. It's optimized to scale from one to many cores, giving you the best single-threaded and multithreaded performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Faster than Memcache and Redis is a big claim! The README includes a &lt;a href="https://github.com/tidwall/pogocache/blob/main/README.md#design-details"&gt;design details&lt;/a&gt; section that explains how the system achieves that performance, using a sharded hashmap inspired by Josh's &lt;a href="https://github.com/tidwall/shardmap"&gt;shardmap&lt;/a&gt; project and clever application of threads.&lt;/p&gt;
&lt;p&gt;Performance aside, the most interesting thing about Pogocache is the server interface it provides: it emulates the APIs for Redis and Memcached, provides a simple HTTP API &lt;em&gt;and&lt;/em&gt; lets you talk to it over the PostgreSQL wire protocol as well!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;psql -h localhost -p 9401
=&amp;gt; SET first Tom;
=&amp;gt; SET last Anderson;
=&amp;gt; SET age 37;

$ curl http://localhost:9401/last
Anderson
&lt;/code&gt;&lt;/pre&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=44638076"&gt;Show HN&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/caching"&gt;caching&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/http"&gt;http&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/memcached"&gt;memcached&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redis"&gt;redis&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="caching"/><category term="http"/><category term="memcached"/><category term="postgresql"/><category term="redis"/></entry><entry><title>Writing C for curl</title><link href="https://simonwillison.net/2025/Apr/8/writing-c-for-curl/#atom-tag" rel="alternate"/><published>2025-04-08T21:43:35+00:00</published><updated>2025-04-08T21:43:35+00:00</updated><id>https://simonwillison.net/2025/Apr/8/writing-c-for-curl/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://daniel.haxx.se/blog/2025/04/07/writing-c-for-curl/"&gt;Writing C for curl&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Daniel Stenberg maintains &lt;code&gt;curl&lt;/code&gt; - a library that deals with the most hostile of environments, parsing content from the open internet - as 180,000 lines of C89 code.&lt;/p&gt;
&lt;p&gt;He enforces a strict 80 character line width for readability, zero compiler warnings, avoids "bad" functions like &lt;code&gt;gets&lt;/code&gt;, &lt;code&gt;sprintf&lt;/code&gt;, &lt;code&gt;strcat&lt;/code&gt;, &lt;code&gt;strtok&lt;/code&gt; and &lt;code&gt;localtime&lt;/code&gt; (CI fails if it spots them, I found &lt;a href="https://github.com/curl/curl/blob/304b01b8cf86ae95e5d79378879d2ddfb77fc5d1/scripts/checksrc.pl#L50-L74"&gt;that script here&lt;/a&gt;) and curl has their own custom dynamic buffer and parsing functions.&lt;/p&gt;
&lt;p&gt;They take particular care around error handling:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In curl we always check for errors and we bail out &lt;em&gt;without leaking any memory&lt;/em&gt; if (when!) they happen.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I like their commitment to API/ABI robustness:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Every function and interface that is publicly accessible must never be changed in a way that risks breaking the API or ABI. For this reason and to make it easy to spot the functions that need this extra precautions, we have a strict rule: public functions are prefixed with “curl_” and no other functions use that prefix.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/jooshq/writing_c_for_curl"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/curl"&gt;curl&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/daniel-stenberg"&gt;daniel-stenberg&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="curl"/><category term="daniel-stenberg"/></entry><entry><title>Clay UI library</title><link href="https://simonwillison.net/2024/Dec/21/clay-ui-library/#atom-tag" rel="alternate"/><published>2024-12-21T23:12:17+00:00</published><updated>2024-12-21T23:12:17+00:00</updated><id>https://simonwillison.net/2024/Dec/21/clay-ui-library/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.nicbarker.com/clay"&gt;Clay UI library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Fascinating project by Nic Barker, who describes Clay like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;His &lt;a href="https://www.youtube.com/watch?v=DYWTw19_8r4"&gt;intro video&lt;/a&gt; to the library is outstanding: I learned a ton about how UI layout works from this, and the animated visual explanations are clear, tasteful and really helped land the different concepts:&lt;/p&gt;
&lt;p&gt;&lt;lite-youtube videoid="DYWTw19_8r4"
  title="Introducing Clay - High Performance UI Layout in C"
  playlabel="Play: Introducing Clay - High Performance UI Layout in C"
&gt; &lt;/lite-youtube&gt;&lt;/p&gt;

&lt;p&gt;Clay is a C library delivered in a single ~2000 line &lt;a href="https://github.com/nicbarker/clay/blob/main/clay.h"&gt;clay.h&lt;/a&gt; dependency-free header file. It only handles layout calculations: if you want to render the result you need to add an additional rendering layer.&lt;/p&gt;
&lt;p&gt;In a fascinating demo of the library, the &lt;a href="https://www.nicbarker.com/clay"&gt;Clay site itself&lt;/a&gt; is rendered using Clay C compiled to WebAssembly! You can even switch between the default HTML renderer and an alternative based on Canvas.&lt;/p&gt;
&lt;p&gt;This isn't necessarily a great idea: because the layout is entirely handled using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements positioned using &lt;code&gt;transform: translate(0px, 70px)&lt;/code&gt; style CSS attempting to select text across multiple boxes behaves strangely, and it's not clear to me what the accessibility implications are.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: &lt;a href="https://toot.cafe/@matt/113693374074675126"&gt;Matt Campbell&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The accessibility implications are as serious as you might guess. The links aren't properly labeled, there's no semantic markup such as headings, and since there's a div for every line, continuous reading with a screen reader is choppy, that is, it pauses at the end of every physical line.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It does make for a very compelling demo of what Clay is capable of though, especially when you resize your browser window and the page layout is recalculated in real-time via the Clay WebAssembly bridge.&lt;/p&gt;
&lt;p&gt;You can hit "D" on the website and open up a custom Clay debugger showing the hierarchy of layout elements on the page:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Clay website on the left, on the right is a panel showing a tree of UI layout elements, one has been selected and is showing details in a box at the bottom of the panel: Bounding Box: { x: 278, y: 13, width: 101, height: 24}, Layout Direction: LEFT_TO_RIGHT, Sizing: width: FITQ, height: FITQ, Padding: {x:8,uy:0}" src="https://static.simonwillison.net/static/2024/clay-debug.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;This also means that the entire page is defined using C code! Given that, I find the code itself &lt;a href="https://github.com/nicbarker/clay/blob/35d72e5fba6872be48d15ed9d84269a86cd72b4e/examples/clay-official-website/main.c#L124-L139"&gt;surprisingly readable&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight highlight-source-c"&gt;&lt;pre&gt;&lt;span class="pl-smi"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;DeclarativeSyntaxPageDesktop&lt;/span&gt;() {
  &lt;span class="pl-en"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxPageDesktop"&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_GROW&lt;/span&gt;(), &lt;span class="pl-en"&gt;CLAY_SIZING_FIT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;min&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;windowHeight&lt;/span&gt; &lt;span class="pl-c1"&gt;-&lt;/span&gt; &lt;span class="pl-c1"&gt;50&lt;/span&gt; }) }, .&lt;span class="pl-s1"&gt;childAlignment&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-c1"&gt;0&lt;/span&gt;, &lt;span class="pl-c1"&gt;CLAY_ALIGN_Y_CENTER&lt;/span&gt;}, .&lt;span class="pl-s1"&gt;padding&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {.&lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;50&lt;/span&gt;} })) {
    &lt;span class="pl-c1"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxPage"&lt;/span&gt;), &lt;span class="pl-c1"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_GROW&lt;/span&gt;(), &lt;span class="pl-en"&gt;CLAY_SIZING_GROW&lt;/span&gt;() }, .&lt;span class="pl-s1"&gt;childAlignment&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-c1"&gt;0&lt;/span&gt;, &lt;span class="pl-c1"&gt;CLAY_ALIGN_Y_CENTER&lt;/span&gt; }, .&lt;span class="pl-s1"&gt;padding&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-c1"&gt;32&lt;/span&gt;, &lt;span class="pl-c1"&gt;32&lt;/span&gt; }, .&lt;span class="pl-s1"&gt;childGap&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;32&lt;/span&gt; }), &lt;span class="pl-en"&gt;CLAY_BORDER&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;left&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-c1"&gt;2&lt;/span&gt;, &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; }, .&lt;span class="pl-s1"&gt;right&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-c1"&gt;2&lt;/span&gt;, &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; } })) {
      &lt;span class="pl-c1"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxPageLeftText"&lt;/span&gt;), &lt;span class="pl-c1"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_PERCENT&lt;/span&gt;(&lt;span class="pl-c1"&gt;0.5&lt;/span&gt;) }, .&lt;span class="pl-c1"&gt;layoutDirection&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;CLAY_TOP_TO_BOTTOM&lt;/span&gt;, .&lt;span class="pl-c1"&gt;childGap&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;8&lt;/span&gt; })) {
        &lt;span class="pl-en"&gt;CLAY_TEXT&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_STRING&lt;/span&gt;(&lt;span class="pl-s"&gt;"Declarative Syntax"&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_TEXT_CONFIG&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;fontSize&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;52&lt;/span&gt;, .&lt;span class="pl-c1"&gt;fontId&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;FONT_ID_TITLE_56&lt;/span&gt;, .&lt;span class="pl-c1"&gt;textColor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; }));
        &lt;span class="pl-en"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxSpacer"&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_GROW&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;max&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;16&lt;/span&gt; }) } })) {}
        &lt;span class="pl-en"&gt;CLAY_TEXT&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_STRING&lt;/span&gt;(&lt;span class="pl-s"&gt;"Flexible and readable declarative syntax with nested UI element hierarchies."&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_TEXT_CONFIG&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;fontSize&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;28&lt;/span&gt;, .&lt;span class="pl-c1"&gt;fontId&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;FONT_ID_BODY_36&lt;/span&gt;, .&lt;span class="pl-c1"&gt;textColor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; }));
        &lt;span class="pl-en"&gt;CLAY_TEXT&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_STRING&lt;/span&gt;(&lt;span class="pl-s"&gt;"Mix elements with standard C code like loops, conditionals and functions."&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_TEXT_CONFIG&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;fontSize&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;28&lt;/span&gt;, .&lt;span class="pl-c1"&gt;fontId&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;FONT_ID_BODY_36&lt;/span&gt;, .&lt;span class="pl-c1"&gt;textColor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; }));
        &lt;span class="pl-en"&gt;CLAY_TEXT&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_STRING&lt;/span&gt;(&lt;span class="pl-s"&gt;"Create your own library of re-usable components from UI primitives like text, images and rectangles."&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_TEXT_CONFIG&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;fontSize&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;28&lt;/span&gt;, .&lt;span class="pl-c1"&gt;fontId&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;FONT_ID_BODY_36&lt;/span&gt;, .&lt;span class="pl-c1"&gt;textColor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;COLOR_RED&lt;/span&gt; }));
      }
      &lt;span class="pl-en"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxPageRightImage"&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_PERCENT&lt;/span&gt;(&lt;span class="pl-c1"&gt;0.50&lt;/span&gt;) }, .&lt;span class="pl-c1"&gt;childAlignment&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {.&lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;CLAY_ALIGN_X_CENTER&lt;/span&gt;} })) {
        &lt;span class="pl-c1"&gt;CLAY&lt;/span&gt;(&lt;span class="pl-en"&gt;CLAY_ID&lt;/span&gt;(&lt;span class="pl-s"&gt;"SyntaxPageRightImageInner"&lt;/span&gt;), &lt;span class="pl-en"&gt;CLAY_LAYOUT&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sizing&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; { &lt;span class="pl-en"&gt;CLAY_SIZING_GROW&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;max&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;568&lt;/span&gt; }) } }), &lt;span class="pl-c1"&gt;CLAY_IMAGE&lt;/span&gt;({ .&lt;span class="pl-s1"&gt;sourceDimensions&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; {&lt;span class="pl-c1"&gt;1136&lt;/span&gt;, &lt;span class="pl-c1"&gt;1194&lt;/span&gt;}, .&lt;span class="pl-s1"&gt;sourceURL&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;CLAY_STRING&lt;/span&gt;(&lt;span class="pl-s"&gt;"/clay/images/declarative.png"&lt;/span&gt;) })) {}
      }
    }
  }
}&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I'm not ready to ditch HTML and CSS for writing my web pages in C compiled to WebAssembly just yet, but as an exercise in understanding layout engines (and a potential tool for building non-web interfaces in the future) this is a really interesting project to dig into.&lt;/p&gt;
&lt;p&gt;To clarify here: I don't think the web layout / WebAssembly thing is the key idea behind Clay at all - I think it's a neat demo of the library, but it's not what Clay is &lt;em&gt;for&lt;/em&gt;. It's certainly an interesting way to provide a demo of a layout library!&lt;/p&gt;
&lt;p&gt;Nic &lt;a href="https://bsky.app/profile/nicbarker.com/post/3ldu44rxyx22h"&gt;confirms&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You totally nailed it, the fact that you can compile to wasm and run in HTML stemmed entirely from a “wouldn’t it be cool if…” It was designed for my C projects first and foremost!&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=42463123"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/accessibility"&gt;accessibility&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/css"&gt;css&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/html"&gt;html&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/webassembly"&gt;webassembly&lt;/a&gt;&lt;/p&gt;



</summary><category term="accessibility"/><category term="c"/><category term="css"/><category term="html"/><category term="webassembly"/></entry><entry><title>Database Remote-Copy Tool For SQLite (draft)</title><link href="https://simonwillison.net/2024/Oct/4/sqlite-rsync/#atom-tag" rel="alternate"/><published>2024-10-04T20:57:39+00:00</published><updated>2024-10-04T20:57:39+00:00</updated><id>https://simonwillison.net/2024/Oct/4/sqlite-rsync/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://sqlite.org/draft/rsync.html"&gt;Database Remote-Copy Tool For SQLite (draft)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Neat new SQLite utilities often show up in branches of the SQLite repository. Here's a new one from last month: &lt;code&gt;sqlite3-rsync&lt;/code&gt;, providing tools for efficiently creating and updating copies of WAL-mode SQLite databases on either the same machine or across remote machines via SSH.&lt;/p&gt;
&lt;p&gt;The way it works is neat, inspired by &lt;code&gt;rsync&lt;/code&gt; (hence the tool's name):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The protocol is for the replica to send a cryptographic hash of each of its pages over to the origin side, then the origin sends back the complete content of any page for which the hash does not match.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;SQLite's default page size is 4096 bytes and a hash is 20 bytes, so if nothing has changed then the client will transmit 0.5% of the database size in hashes and get nothing back in return.&lt;/p&gt;
&lt;p&gt;The tool takes full advantage of &lt;a href="https://sqlite.org/wal.html"&gt;SQLite's WAL mode&lt;/a&gt; - when you run it you'll get an exact snapshot of the database state as it existed at the moment the copy was initiated, even if the source database continues to apply changes.&lt;/p&gt;
&lt;p&gt;I wrote up &lt;a href="https://til.simonwillison.net/sqlite/compile-sqlite3-rsync"&gt;a TIL on how to compile it&lt;/a&gt; - short version:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /tmp
git clone https://github.com/sqlite/sqlite.git
cd sqlite
git checkout sqlite3-rsync
./configure
make sqlite3.c
cd tool
gcc -o sqlite3-rsync sqlite3-rsync.c ../sqlite3.c -DSQLITE_ENABLE_DBPAGE_VTAB
./sqlite3-rsync --help
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; It turns out you can now just run &lt;code&gt;./configure &amp;amp;&amp;amp; make sqlite_rsync&lt;/code&gt; in the root checkout.&lt;/p&gt;
&lt;p&gt;Something I’ve worried about in the past is that if I want to make a snapshot backup of a SQLite database I need enough additional free disk space to entirely duplicate the current database first (using the backup mechanism or &lt;code&gt;VACUUM INTO&lt;/code&gt;). This tool fixes that - I don’t need any extra disk space at all, since the pages that have been updated will be transmitted directly over the wire in 4096 byte chunks.&lt;/p&gt;
&lt;p&gt;I tried feeding the &lt;a href="https://github.com/sqlite/sqlite/blob/sqlite3-rsync/tool/sqlite3-rsync.c"&gt;1800 lines of C&lt;/a&gt; through OpenAI’s &lt;code&gt;o1-preview&lt;/code&gt; with the prompt “Explain the protocol over SSH part of this” and &lt;a href="https://chatgpt.com/share/6701450c-bc9c-8006-8c9e-468ab6f67e4b"&gt;got a pretty great high level explanation&lt;/a&gt; - &lt;a href="https://gist.github.com/simonw/ffbf90e0602df04c2f6b387de42acba4"&gt;markdown copy here&lt;/a&gt;.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/2ngsl1/database_remote_copy_tool_for_sqlite"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/o1"&gt;o1&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="sqlite"/><category term="o1"/></entry><entry><title>Introducing sqlite-lembed: A SQLite extension for generating text embeddings locally</title><link href="https://simonwillison.net/2024/Jul/25/sqlite-lembed-rembed/#atom-tag" rel="alternate"/><published>2024-07-25T20:30:01+00:00</published><updated>2024-07-25T20:30:01+00:00</updated><id>https://simonwillison.net/2024/Jul/25/sqlite-lembed-rembed/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://alexgarcia.xyz/blog/2024/sqlite-lembed-init/index.html"&gt;Introducing sqlite-lembed: A SQLite extension for generating text embeddings locally&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Alex Garcia's latest SQLite extension is a C wrapper around the &lt;a href="https://github.com/ggerganov/llama.cpp"&gt;llama.cpp&lt;/a&gt; that exposes just its embedding support, allowing you to register a GGUF file containing an embedding model:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO temp.lembed_models(name, model)
  select 'all-MiniLM-L6-v2',
  lembed_model_from_file('all-MiniLM-L6-v2.e4ce9877.q8_0.gguf');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then use it to calculate embeddings as part of a SQL query:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;select lembed(
  'all-MiniLM-L6-v2',
  'The United States Postal Service is an independent agency...'
); -- X'A402...09C3' (1536 bytes)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;all-MiniLM-L6-v2.e4ce9877.q8_0.gguf&lt;/code&gt; here is a 24MB file, so this should run quite happily even on machines without much available RAM.&lt;/p&gt;
&lt;p&gt;What if you don't want to run the models locally at all? Alex has another new extension for that, described in &lt;strong&gt;&lt;a href="https://alexgarcia.xyz/blog/2024/sqlite-rembed-init/index.html"&gt;Introducing sqlite-rembed: A SQLite extension for generating text embeddings from remote APIs&lt;/a&gt;&lt;/strong&gt;. The &lt;code&gt;rembed&lt;/code&gt; is for remote embeddings, and this extension uses Rust to call multiple remotely-hosted embeddings APIs, registered like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;INSERT INTO temp.rembed_clients(name, options)
  VALUES ('text-embedding-3-small', 'openai');
select rembed(
  'text-embedding-3-small',
  'The United States Postal Service is an independent agency...'
); -- X'A452...01FC', Blob&amp;lt;6144 bytes&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's &lt;a href="https://github.com/asg017/sqlite-rembed/blob/v0.0.1-alpha.9/src/clients.rs"&gt;the Rust code&lt;/a&gt; that implements Rust wrapper functions for HTTP JSON APIs from OpenAI, Nomic, Cohere, Jina, Mixedbread and localhost servers provided by Ollama and Llamafile.&lt;/p&gt;
&lt;p&gt;Both of these extensions are designed to complement Alex's &lt;a href="https://github.com/asg017/sqlite-vec"&gt;sqlite-vec&lt;/a&gt; extension, which is nearing a first stable release.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://data-folks.masto.host/@alexgarciaxyz/112848900983450306"&gt;@alexgarciaxyz&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rust"&gt;rust&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/alex-garcia"&gt;alex-garcia&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/embeddings"&gt;embeddings&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llama-cpp"&gt;llama-cpp&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="sqlite"/><category term="rust"/><category term="alex-garcia"/><category term="embeddings"/><category term="llama-cpp"/></entry><entry><title>Tagged Pointer Strings (2015)</title><link href="https://simonwillison.net/2024/May/8/tagged-pointer-strings-2015/#atom-tag" rel="alternate"/><published>2024-05-08T14:23:13+00:00</published><updated>2024-05-08T14:23:13+00:00</updated><id>https://simonwillison.net/2024/May/8/tagged-pointer-strings-2015/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://mikeash.com/pyblog/friday-qa-2015-07-31-tagged-pointer-strings.html"&gt;Tagged Pointer Strings (2015)&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Mike Ash digs into a fascinating implementation detail of macOS.&lt;/p&gt;
&lt;p&gt;Tagged pointers provide a way to embed a literal value in a pointer reference. Objective-C pointers on macOS are 64 bit, providing plenty of space for representing entire values. If the least significant bit is 1 (the pointer is a 64 bit odd number) then the pointer is "tagged" and represents a value, not a memory reference.&lt;/p&gt;
&lt;p&gt;Here's where things get really clever. Storing an integer value up to 60 bits is easy. But what about strings?&lt;/p&gt;
&lt;p&gt;There's enough space for three UTF-16 characters, with 12 bits left over. But if the string fits ASCII we can store 7 characters.&lt;/p&gt;
&lt;p&gt;Drop everything except &lt;code&gt;a-z A-Z.0-9&lt;/code&gt; and we need 6 bits per character, allowing 10 characters to fit in the pointer.&lt;/p&gt;
&lt;p&gt;Apple take this a step further: if the string contains just &lt;code&gt;eilotrm.apdnsIc ufkMShjTRxgC4013&lt;/code&gt; ("b" is apparently uncommon enough to be ignored here) they can store 11 characters in that 60 bits!

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/5417dx/storing_data_pointers#c_noslq0"&gt;Lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/objective-c"&gt;objective-c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/strings"&gt;strings&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="objective-c"/><category term="strings"/></entry><entry><title>I'm writing a new vector search SQLite Extension</title><link href="https://simonwillison.net/2024/May/3/sqlite-vec/#atom-tag" rel="alternate"/><published>2024-05-03T03:16:39+00:00</published><updated>2024-05-03T03:16:39+00:00</updated><id>https://simonwillison.net/2024/May/3/sqlite-vec/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://alexgarcia.xyz/blog/2024/building-new-vector-search-sqlite/index.html"&gt;I&amp;#x27;m writing a new vector search SQLite Extension&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Alex Garcia is working on &lt;code&gt;sqlite-vec&lt;/code&gt;, a spiritual successor to his &lt;code&gt;sqlite-vss&lt;/code&gt; project. The new SQLite C extension will have zero other dependencies (&lt;code&gt;sqlite-vss&lt;/code&gt; used some tricky C++ libraries) and will work using virtual tables, storing chunks of vectors in shadow tables to avoid needing to load everything into memory at once.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vectors"&gt;vectors&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/alex-garcia"&gt;alex-garcia&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vector-search"&gt;vector-search&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/embeddings"&gt;embeddings&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="sqlite"/><category term="vectors"/><category term="alex-garcia"/><category term="vector-search"/><category term="embeddings"/></entry><entry><title>llm.c</title><link href="https://simonwillison.net/2024/Apr/9/llmc/#atom-tag" rel="alternate"/><published>2024-04-09T15:24:33+00:00</published><updated>2024-04-09T15:24:33+00:00</updated><id>https://simonwillison.net/2024/Apr/9/llmc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/karpathy/llm.c"&gt;llm.c&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Andrej Karpathy implements LLM training—initially for GPT-2, other architectures to follow—in just over 1,000 lines of C on top of CUDA. Includes a tutorial about implementing LayerNorm by porting an implementation from Python.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/karpathy/status/1777427944971083809"&gt;@karpathy&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/andrej-karpathy"&gt;andrej-karpathy&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gpt-2"&gt;gpt-2&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="ai"/><category term="andrej-karpathy"/><category term="generative-ai"/><category term="llms"/><category term="gpt-2"/></entry><entry><title>Hello World</title><link href="https://simonwillison.net/2024/Apr/9/hello-world/#atom-tag" rel="alternate"/><published>2024-04-09T01:06:46+00:00</published><updated>2024-04-09T01:06:46+00:00</updated><id>https://simonwillison.net/2024/Apr/9/hello-world/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://thecoder08.github.io/hello-world.html"&gt;Hello World&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Lennon McLean dives deep down the rabbit hole of what happens when you execute the binary compiled from “Hello world” in C on a Linux system, digging into the details of ELF executables, objdump disassembly, the C standard library, stack frames, null-terminated strings and taking a detour through musl because it’s easier to read than Glibc.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=39967709"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/linux"&gt;linux&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="linux"/></entry><entry><title>Building and testing C extensions for SQLite with ChatGPT Code Interpreter</title><link href="https://simonwillison.net/2024/Mar/23/building-c-extensions-for-sqlite-with-chatgpt-code-interpreter/#atom-tag" rel="alternate"/><published>2024-03-23T17:50:30+00:00</published><updated>2024-03-23T17:50:30+00:00</updated><id>https://simonwillison.net/2024/Mar/23/building-c-extensions-for-sqlite-with-chatgpt-code-interpreter/#atom-tag</id><summary type="html">
    &lt;p&gt;I wrote yesterday about how I used &lt;a href="https://simonwillison.net/2024/Mar/22/claude-and-chatgpt-case-study/"&gt;Claude and ChatGPT Code Interpreter for simple ad-hoc side quests&lt;/a&gt; - in that case, for converting a shapefile to GeoJSON and merging it into a single polygon.&lt;/p&gt;

&lt;p&gt;Today I have a much more ambitious example.&lt;/p&gt;

&lt;p&gt;I was thinking this morning about vector similarity, and how I really like the pattern of storing encoded floating point vectors in BLOB columns in a SQLite database table and then using a custom SQL function to decode them and calculate cosine similarity between them.&lt;/p&gt;
&lt;p&gt;I've written code for this a few times in Python, with Python functions that get registered with SQLite as custom SQL functions. Here's &lt;a href="https://github.com/simonw/llm/blob/fb63c92cd27053700daa5420a0d1ad8fdfb718bd/llm/embeddings.py#L240-L287"&gt;an example&lt;/a&gt; from my &lt;a href="https://llm.datasette.io/"&gt;LLM&lt;/a&gt; tool.&lt;/p&gt;
&lt;p&gt;What I'd really like is a SQLite C extension that does this faster - avoiding the overhead of making function calls from SQLite back to Python.&lt;/p&gt;
&lt;p&gt;Then I remembered that &lt;a href="https://simonwillison.net/tags/codeinterpreter/"&gt;ChatGPT Code Interpreter&lt;/a&gt; has Python, SQLite and access to &lt;code&gt;gcc&lt;/code&gt;. Could I get it to build and test that C extension for me, entirely within its own environment?&lt;/p&gt;
&lt;p&gt;It turns out that works!&lt;/p&gt;
&lt;h4 id="get-chatgpt-in-the-mood"&gt;Absurdly, the first step is getting ChatGPT in the right "mood"&lt;/h4&gt;
&lt;p&gt;One of the infuriating things about working with ChatGPT Code Interpreter is that it often denies abilities that you know it has.&lt;/p&gt;
&lt;p&gt;I've found it to be quite resistant to compiling C code in the past. Here's a prompting sequence trick that usually works for me:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use your code interpreter tool to show me the version of your Python and SQLite&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It generated and ran this code:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;sys&lt;/span&gt;

&lt;span class="pl-s1"&gt;python_version&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;sys&lt;/span&gt;.&lt;span class="pl-s1"&gt;version&lt;/span&gt;
&lt;span class="pl-s1"&gt;sqlite_version&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;.&lt;span class="pl-s1"&gt;sqlite_version&lt;/span&gt;

&lt;span class="pl-s1"&gt;python_version&lt;/span&gt;, &lt;span class="pl-s1"&gt;sqlite_version&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Which output:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;('3.11.8 (main, Mar 12 2024, 11:41:52) [GCC 12.2.0]', '3.40.1')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we need it to acknowledge that it has access to &lt;code&gt;gcc&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now use subprocess.run() to call "gcc --version" and tell me that version&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If all goes well it will run something like this:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;

&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;.&lt;span class="pl-en"&gt;run&lt;/span&gt;([&lt;span class="pl-s"&gt;"gcc"&lt;/span&gt;, &lt;span class="pl-s"&gt;"--version"&lt;/span&gt;], &lt;span class="pl-s1"&gt;capture_output&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;, &lt;span class="pl-s1"&gt;text&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)
&lt;span class="pl-s1"&gt;gcc_version&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt;.&lt;span class="pl-s1"&gt;stdout&lt;/span&gt;.&lt;span class="pl-en"&gt;split&lt;/span&gt;(&lt;span class="pl-s"&gt;'&lt;span class="pl-cce"&gt;\n&lt;/span&gt;'&lt;/span&gt;)[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]

&lt;span class="pl-s1"&gt;gcc_version&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Outputting:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;'gcc (Debian 12.2.0-14) 12.2.0'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This &lt;em&gt;may&lt;/em&gt; be enough for it to start happily compiling C code (which it can do with subsequent calls to &lt;code&gt;gcc&lt;/code&gt;). If not, a trick I've &lt;a href="https://simonwillison.net/2023/Oct/17/open-questions/#open-questions.037.jpeg"&gt;used successfully in the past&lt;/a&gt; is "try running this command: gcc helloworld.c - and show me the error message you get". But hopefully that won't be necessary.&lt;/p&gt;
&lt;h4 id="a-basic-extension"&gt;Compiling a basic SQLite extension&lt;/h4&gt;
&lt;p&gt;If you ask it for a SQLite extension it will default to typing out the code for you to copy and paste elsewhere. We want that code saved to its own disk so it can run a compiler later.&lt;/p&gt;
&lt;p&gt;Try this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Write a SQLite extension in C that provides a math_sin(a) function. Save that extension file to disk, then give me a link to download it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We don't actually care about downloading the file, but this provides an excuse (do we need one? I don't know!) for saving it to disk.&lt;/p&gt;
&lt;p&gt;It ran this:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-s1"&gt;sin_extension_c&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"""&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;sqlite3ext.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;SQLITE_EXTENSION_INIT1&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;static void math_sin(sqlite3_context *context, int argc, sqlite3_value **argv) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    double input = sqlite3_value_double(argv[0]);&lt;/span&gt;
&lt;span class="pl-s"&gt;    double result = sin(input);&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_result_double(context, result);&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;#ifdef _WIN32&lt;/span&gt;
&lt;span class="pl-s"&gt;__declspec(dllexport)&lt;/span&gt;
&lt;span class="pl-s"&gt;#endif&lt;/span&gt;
&lt;span class="pl-s"&gt;int sqlite3_sin_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    SQLITE_EXTENSION_INIT2(pApi)&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_create_function(db, "math_sin", 1, SQLITE_UTF8, NULL, math_sin, NULL, NULL);&lt;/span&gt;
&lt;span class="pl-s"&gt;    return 0;&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;"""&lt;/span&gt;

&lt;span class="pl-k"&gt;with&lt;/span&gt; &lt;span class="pl-en"&gt;open&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;, &lt;span class="pl-s"&gt;"w"&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;file&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;file&lt;/span&gt;.&lt;span class="pl-en"&gt;write&lt;/span&gt;(&lt;span class="pl-s1"&gt;sin_extension_c&lt;/span&gt;)

&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And gave me a link to download the file.&lt;/p&gt;
&lt;p&gt;Next, I prompted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now use subprocess.run to compile it with gcc, like how you showed me the gcc version earlier&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I'm trying to avoid it claiming it can't compile code by referencing back to the earlier successful invocation of &lt;code&gt;gcc --version&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When I tried this just now it worked without complaining... but found a compilation bug in the C code:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-s1"&gt;compile_command&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; [&lt;span class="pl-s"&gt;"gcc"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-fPIC"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-shared"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-o"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.so"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;]
&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;.&lt;span class="pl-en"&gt;run&lt;/span&gt;(&lt;span class="pl-s1"&gt;compile_command&lt;/span&gt;, &lt;span class="pl-s1"&gt;capture_output&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;, &lt;span class="pl-s1"&gt;text&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-s1"&gt;result&lt;/span&gt;.&lt;span class="pl-s1"&gt;stdout&lt;/span&gt;, &lt;span class="pl-s1"&gt;result&lt;/span&gt;.&lt;span class="pl-s1"&gt;stderr&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;(
    '',
     '/mnt/data/sin_extension.c: In function ‘sqlite3_sin_init’:\n/mnt/data/sin_extension.c:17:61: error: ‘NULL’ undeclared (first use in this function)\n   17 |     sqlite3_create_function(db, "math_sin", 1, SQLITE_UTF8, NULL, math_sin, NULL, NULL);\n      |                                                             ^~~~\n/mnt/data/sin_extension.c:5:1: note: ‘NULL’ is defined in header ‘&amp;lt;stddef.h&amp;gt;’; did you forget to ‘#include &amp;lt;stddef.h&amp;gt;’?\n    4 | #include &amp;lt;math.h&amp;gt;\n  +++ |+#include &amp;lt;stddef.h&amp;gt;\n    5 | \n/mnt/data/sin_extension.c:17:61: note: each undeclared identifier is reported only once for each function it appears in\n   17 |     sqlite3_create_function(db, "math_sin", 1, SQLITE_UTF8, NULL, math_sin, NULL, NULL);\n      |                                                             ^~~~\n')
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ChatGPT added:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It looks like there was an error during the compilation process. The error message suggests that &lt;code&gt;NULL&lt;/code&gt; is undeclared because the &lt;code&gt;&amp;lt;stddef.h&amp;gt;&lt;/code&gt; header file, which defines &lt;code&gt;NULL&lt;/code&gt;, was not included.&lt;/p&gt;
&lt;p&gt;I'll update the C code to include this header and attempt the compilation again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It said it was going to update the C code but didn't actually do that at all - it just stopped. So I said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do that&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And it did! Here's the code it successfully ran:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-c"&gt;# Update the C code to include &amp;lt;stddef.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s1"&gt;sin_extension_c_updated&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"""&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;sqlite3ext.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;SQLITE_EXTENSION_INIT1&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;stddef.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;static void math_sin(sqlite3_context *context, int argc, sqlite3_value **argv) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    double input = sqlite3_value_double(argv[0]);&lt;/span&gt;
&lt;span class="pl-s"&gt;    double result = sin(input);&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_result_double(context, result);&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;#ifdef _WIN32&lt;/span&gt;
&lt;span class="pl-s"&gt;__declspec(dllexport)&lt;/span&gt;
&lt;span class="pl-s"&gt;#endif&lt;/span&gt;
&lt;span class="pl-s"&gt;int sqlite3_sin_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    SQLITE_EXTENSION_INIT2(pApi)&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_create_function(db, "math_sin", 1, SQLITE_UTF8, NULL, math_sin, NULL, NULL);&lt;/span&gt;
&lt;span class="pl-s"&gt;    return 0;&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;"""&lt;/span&gt;

&lt;span class="pl-k"&gt;with&lt;/span&gt; &lt;span class="pl-en"&gt;open&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;, &lt;span class="pl-s"&gt;"w"&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;file&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;file&lt;/span&gt;.&lt;span class="pl-en"&gt;write&lt;/span&gt;(&lt;span class="pl-s1"&gt;sin_extension_c_updated&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Compile the updated C code&lt;/span&gt;
&lt;span class="pl-s1"&gt;compile_command_updated&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; [&lt;span class="pl-s"&gt;"gcc"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-fPIC"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-shared"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-o"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.so"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;]
&lt;span class="pl-s1"&gt;result_updated&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;.&lt;span class="pl-en"&gt;run&lt;/span&gt;(&lt;span class="pl-s1"&gt;compile_command_updated&lt;/span&gt;, &lt;span class="pl-s1"&gt;capture_output&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;, &lt;span class="pl-s1"&gt;text&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-s1"&gt;result_updated&lt;/span&gt;.&lt;span class="pl-s1"&gt;stdout&lt;/span&gt;, &lt;span class="pl-s1"&gt;result_updated&lt;/span&gt;.&lt;span class="pl-s1"&gt;stderr&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Both &lt;code&gt;stdout&lt;/code&gt; and &lt;code&gt;stderr&lt;/code&gt; were blank, indicating a successfully compiled SQLite extension!&lt;/p&gt;
&lt;h4 id="trying-it-in-python"&gt;Trying it out in Python&lt;/h4&gt;
&lt;p&gt;With the SQLite extension compiled the next step is to see if it actually works. I said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now load that extension into SQLite in Python and try it out&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It wrote and then ran the following:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;

&lt;span class="pl-c"&gt;# Connect to an in-memory SQLite database&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;.&lt;span class="pl-en"&gt;connect&lt;/span&gt;(&lt;span class="pl-s"&gt;":memory:"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;enable_load_extension&lt;/span&gt;(&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Load the compiled extension&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;load_extension&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.so"&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Test the math_sin function&lt;/span&gt;
&lt;span class="pl-s1"&gt;cursor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;cursor&lt;/span&gt;()
&lt;span class="pl-s1"&gt;cursor&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"SELECT math_sin(1.57079632679)"&lt;/span&gt;)  &lt;span class="pl-c"&gt;# sin(pi/2) should be close to 1&lt;/span&gt;
&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;cursor&lt;/span&gt;.&lt;span class="pl-en"&gt;fetchone&lt;/span&gt;()

&lt;span class="pl-s1"&gt;result&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]&lt;/pre&gt;
&lt;p&gt;... and it got an error:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;---------------------------------------------------------------------------
OperationalError                          Traceback (most recent call last)
Cell In[6], line 8
      5 conn.enable_load_extension(True)
      7 # Load the compiled extension
----&amp;gt; 8 conn.load_extension("/mnt/data/sin_extension.so")
     10 # Test the math_sin function
     11 cursor = conn.cursor()

OperationalError: /mnt/data/sin_extension.so: undefined symbol: sqlite3_sinextension_init
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's where the real magic of Code Interpreter kicked in.  Without any further interaction from me, it said the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It looks like there was an error loading the extension into SQLite. The error message indicates that the symbol &lt;code&gt;sqlite3_sinextension_init&lt;/code&gt; is undefined. This is likely because the entry point function for the extension is not named correctly.&lt;/p&gt;
&lt;p&gt;In the C code, the entry point function is named &lt;code&gt;sqlite3_sin_init&lt;/code&gt;. However, SQLite expects the entry point function to be named &lt;code&gt;sqlite3_extension_init&lt;/code&gt; or &lt;code&gt;sqlite3_&amp;lt;extension_name&amp;gt;_init&lt;/code&gt;. In this case, the expected name would be &lt;code&gt;sqlite3_sinextension_init&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I'll update the C code to rename the entry point function to &lt;code&gt;sqlite3_sinextension_init&lt;/code&gt; and recompile the extension. ​
​&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-c"&gt;# Update the C code to rename the entry point function&lt;/span&gt;
&lt;span class="pl-s1"&gt;sin_extension_c_final&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;"""&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;sqlite3ext.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;SQLITE_EXTENSION_INIT1&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;#include &amp;lt;stddef.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;static void math_sin(sqlite3_context *context, int argc, sqlite3_value **argv) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    double input = sqlite3_value_double(argv[0]);&lt;/span&gt;
&lt;span class="pl-s"&gt;    double result = sin(input);&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_result_double(context, result);&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;&lt;/span&gt;
&lt;span class="pl-s"&gt;#ifdef _WIN32&lt;/span&gt;
&lt;span class="pl-s"&gt;__declspec(dllexport)&lt;/span&gt;
&lt;span class="pl-s"&gt;#endif&lt;/span&gt;
&lt;span class="pl-s"&gt;int sqlite3_sinextension_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {&lt;/span&gt;
&lt;span class="pl-s"&gt;    SQLITE_EXTENSION_INIT2(pApi)&lt;/span&gt;
&lt;span class="pl-s"&gt;    sqlite3_create_function(db, "math_sin", 1, SQLITE_UTF8, NULL, math_sin, NULL, NULL);&lt;/span&gt;
&lt;span class="pl-s"&gt;    return 0;&lt;/span&gt;
&lt;span class="pl-s"&gt;}&lt;/span&gt;
&lt;span class="pl-s"&gt;"""&lt;/span&gt;

&lt;span class="pl-k"&gt;with&lt;/span&gt; &lt;span class="pl-en"&gt;open&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;, &lt;span class="pl-s"&gt;"w"&lt;/span&gt;) &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-s1"&gt;file&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;file&lt;/span&gt;.&lt;span class="pl-en"&gt;write&lt;/span&gt;(&lt;span class="pl-s1"&gt;sin_extension_c_final&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Recompile the updated C code&lt;/span&gt;
&lt;span class="pl-s1"&gt;compile_command_final&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; [&lt;span class="pl-s"&gt;"gcc"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-fPIC"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-shared"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-o"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.so"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/sin_extension.c"&lt;/span&gt;]
&lt;span class="pl-s1"&gt;result_final&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;.&lt;span class="pl-en"&gt;run&lt;/span&gt;(&lt;span class="pl-s1"&gt;compile_command_final&lt;/span&gt;, &lt;span class="pl-s1"&gt;capture_output&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;, &lt;span class="pl-s1"&gt;text&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-s1"&gt;result_final&lt;/span&gt;.&lt;span class="pl-s1"&gt;stdout&lt;/span&gt;, &lt;span class="pl-s1"&gt;result_final&lt;/span&gt;.&lt;span class="pl-s1"&gt;stderr&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The compilation succeeded... so it said:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The updated SQLite extension has been successfully recompiled with the correct entry point function name. Let's try loading the extension into SQLite again and test the &lt;code&gt;math_sin&lt;/code&gt; function. ​&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then it ran this:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-c"&gt;# Reconnect to the in-memory SQLite database&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;close&lt;/span&gt;()
&lt;span class="pl-s1"&gt;conn&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;.&lt;span class="pl-en"&gt;connect&lt;/span&gt;(&lt;span class="pl-s"&gt;":memory:"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;enable_load_extension&lt;/span&gt;(&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Load the recompiled extension&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;load_extension&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/sin_extension.so"&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Test the math_sin function again&lt;/span&gt;
&lt;span class="pl-s1"&gt;cursor&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;cursor&lt;/span&gt;()
&lt;span class="pl-s1"&gt;cursor&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"SELECT math_sin(1.57079632679)"&lt;/span&gt;)  &lt;span class="pl-c"&gt;# sin(pi/2) should be close to 1&lt;/span&gt;
&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;cursor&lt;/span&gt;.&lt;span class="pl-en"&gt;fetchone&lt;/span&gt;()

&lt;span class="pl-s1"&gt;result&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]&lt;/pre&gt;
&lt;p&gt;And it worked! The output was:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;1.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ChatGPT has now written a working SQLite extension in C, compiled it, loaded it into Python and tested it for us!&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://chat.openai.com/share/df179c23-3fce-4568-ba85-fbabef34e2e1"&gt;the full transcript&lt;/a&gt; of this ChatGPT session.&lt;/p&gt;
&lt;h4 id="more-ambitious"&gt;Something more ambitious: vector comparison functions&lt;/h4&gt;
&lt;p&gt;My actual goal here was more ambitious: I wanted a SQL function that could calculate cosine similarity between two vectors stored as BLOBs in SQLite.&lt;/p&gt;
&lt;p&gt;I won't provide a blow-by-blow account of how I got there, but I started with this prompt:&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;encode&lt;/span&gt;(&lt;span class="pl-s1"&gt;values&lt;/span&gt;):
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;struct&lt;/span&gt;.&lt;span class="pl-en"&gt;pack&lt;/span&gt;(&lt;span class="pl-s"&gt;"&amp;lt;"&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-s"&gt;"f"&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;len&lt;/span&gt;(&lt;span class="pl-s1"&gt;values&lt;/span&gt;), &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;values&lt;/span&gt;)


&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;decode&lt;/span&gt;(&lt;span class="pl-s1"&gt;binary&lt;/span&gt;):
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;struct&lt;/span&gt;.&lt;span class="pl-en"&gt;unpack&lt;/span&gt;(&lt;span class="pl-s"&gt;"&amp;lt;"&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-s"&gt;"f"&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; (&lt;span class="pl-en"&gt;len&lt;/span&gt;(&lt;span class="pl-s1"&gt;binary&lt;/span&gt;) &lt;span class="pl-c1"&gt;//&lt;/span&gt; &lt;span class="pl-c1"&gt;4&lt;/span&gt;), &lt;span class="pl-s1"&gt;binary&lt;/span&gt;)


&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;cosine_similarity&lt;/span&gt;(&lt;span class="pl-s1"&gt;a&lt;/span&gt;, &lt;span class="pl-s1"&gt;b&lt;/span&gt;):
    &lt;span class="pl-s1"&gt;dot_product&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sum&lt;/span&gt;(&lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;y&lt;/span&gt; &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;x&lt;/span&gt;, &lt;span class="pl-s1"&gt;y&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-en"&gt;zip&lt;/span&gt;(&lt;span class="pl-s1"&gt;a&lt;/span&gt;, &lt;span class="pl-s1"&gt;b&lt;/span&gt;))
    &lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sum&lt;/span&gt;(&lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt;) &lt;span class="pl-c1"&gt;**&lt;/span&gt; &lt;span class="pl-c1"&gt;0.5&lt;/span&gt;
    &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sum&lt;/span&gt;(&lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;x&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-s1"&gt;b&lt;/span&gt;) &lt;span class="pl-c1"&gt;**&lt;/span&gt; &lt;span class="pl-c1"&gt;0.5&lt;/span&gt;
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;dot_product&lt;/span&gt; &lt;span class="pl-c1"&gt;/&lt;/span&gt; (&lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt;)&lt;/pre&gt;
&lt;p&gt;These are Python functions for working with vectors that are stored in SQLite as BLOBs where each BLOB value is a sequence of floating point numbers as binary&lt;/p&gt;
&lt;p&gt;Write a new SQLite extension in C that provides three SQL functions:&lt;/p&gt;
&lt;p&gt;vector_decode(blob) -&amp;gt; returns a string that is a JSON formatted array of floats, eg "[1.1, 2.1, 3.5]"&lt;/p&gt;
&lt;p&gt;vector_encode(string_of_json) -&amp;gt; returns a binary blob for that string. This does not need to use a full JSON parser, it just needs to work with an array that starts with [ and ends with ] and has comma separated floats, ignoring whitespace&lt;/p&gt;
&lt;p&gt;vector_similarity(blob1, blob2) -&amp;gt; returns floating point cosine similarity for those two encoded vectors&lt;/p&gt;
&lt;p&gt;Write it as a file on disk, then compile it and try it out&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I pasted in my existing Python code and told it to write me a SQLite extension based on that code.&lt;/p&gt;
&lt;p&gt;I do this kind of thing a lot: prompting LLMs with code examples, often written in different languages. Code is a &lt;em&gt;really&lt;/em&gt; good way to communicate requirements with them.&lt;/p&gt;
&lt;p&gt;This kicked off a frustrating sequence of interactions. It wrote the extension as a file called &lt;code&gt;vector_extension.c&lt;/code&gt;, compiled it, hit a bug, then wrote a fix in a new file called &lt;code&gt;vector_extension_fixed.c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;But... when it tried to compile the new file, it hit errors because the C init function no longer matched the filename. So, like someone rolling their own version control based on duplicated files, it created &lt;code&gt;vector_extension_final_fixed.c&lt;/code&gt; and that broke for the same reason...&lt;/p&gt;
&lt;p&gt;When it got to &lt;code&gt;vector_extension_final_corrected.c&lt;/code&gt; I took pity on it and cut it off!&lt;/p&gt;
&lt;p&gt;This is a classic Code Interpreter problem: an error loop, where it keeps on trying but making variants of the same mistake, and (being a big bag of next-token-predicting matrix algebra) doesn't have the ability to learn from and correct itself.&lt;/p&gt;
&lt;p&gt;Here's the &lt;a href="https://chat.openai.com/share/a52ee3e4-7a91-48ee-a16e-3f680a65edf2"&gt;full transcript of that conversation&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id="clearing-state"&gt;Clearing state and continuing&lt;/h4&gt;
&lt;p&gt;The best way out of an error loop is to clear state and start again.&lt;/p&gt;
&lt;p&gt;I opened a brand new ChatGPT session and fed it a copy of the code it had previously written that I thought was most likely to work - literally pasting it into the prompt directly:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Save this to a file called /mnt/data/vector.c and then give me a link to download the file:&lt;/p&gt;
&lt;div class="highlight highlight-source-c"&gt;&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;sqlite3ext.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-smi"&gt;SQLITE_EXTENSION_INIT1&lt;/span&gt;

&lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-s1"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;vector_decode&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3_context&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;argc&lt;/span&gt;, &lt;span class="pl-smi"&gt;sqlite3_value&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;argv&lt;/span&gt;) {
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;unsigned &lt;span class="pl-smi"&gt;char&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;blob&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_blob&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;size&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_bytes&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]) / &lt;span class="pl-k"&gt;sizeof&lt;/span&gt;(&lt;span class="pl-smi"&gt;float&lt;/span&gt;);
    &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;values&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; (&lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;)&lt;span class="pl-s1"&gt;blob&lt;/span&gt;;

    &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;malloc&lt;/span&gt;(&lt;span class="pl-s1"&gt;size&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-c1"&gt;12&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-c1"&gt;2&lt;/span&gt;); &lt;span class="pl-c"&gt;// Max 10 digits per float + comma + space&lt;/span&gt;
    &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;result&lt;/span&gt;;
    &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;&lt;span class="pl-c1"&gt;++&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;'['&lt;/span&gt;;
    &lt;span class="pl-k"&gt;for&lt;/span&gt; (&lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pl-s1"&gt;size&lt;/span&gt;; &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;i&lt;/span&gt;) {
        &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;) {
            &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;&lt;span class="pl-c1"&gt;++&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;','&lt;/span&gt;;
            &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;&lt;span class="pl-c1"&gt;++&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;' '&lt;/span&gt;;
        }
        &lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-en"&gt;sprintf&lt;/span&gt;(&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;, &lt;span class="pl-s"&gt;"%.2f"&lt;/span&gt;, &lt;span class="pl-s1"&gt;values&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;]);
    }
    &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;&lt;span class="pl-c1"&gt;++&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;']'&lt;/span&gt;;
    &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;'\0'&lt;/span&gt;;

    &lt;span class="pl-en"&gt;sqlite3_result_text&lt;/span&gt;(&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-s1"&gt;result&lt;/span&gt;, &lt;span class="pl-c1"&gt;-1&lt;/span&gt;, &lt;span class="pl-c1"&gt;SQLITE_TRANSIENT&lt;/span&gt;);
    &lt;span class="pl-en"&gt;free&lt;/span&gt;(&lt;span class="pl-s1"&gt;result&lt;/span&gt;);
}

&lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-smi"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;vector_encode&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3_context&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;argc&lt;/span&gt;, &lt;span class="pl-smi"&gt;sqlite3_value&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;argv&lt;/span&gt;) {
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;json&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; (&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;)&lt;span class="pl-en"&gt;sqlite3_value_text&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;;
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;json&lt;/span&gt;;

    &lt;span class="pl-k"&gt;while&lt;/span&gt; (&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;) {
        &lt;span class="pl-k"&gt;if&lt;/span&gt; (&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;==&lt;/span&gt; &lt;span class="pl-c1"&gt;','&lt;/span&gt;) &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;count&lt;/span&gt;;
        &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;;
    }
    &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;count&lt;/span&gt;; &lt;span class="pl-c"&gt;// Number of floats is one more than the number of commas&lt;/span&gt;

    &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;values&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;malloc&lt;/span&gt;(&lt;span class="pl-s1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;sizeof&lt;/span&gt;(&lt;span class="pl-smi"&gt;float&lt;/span&gt;));
    &lt;span class="pl-s1"&gt;ptr&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;json&lt;/span&gt; &lt;span class="pl-c1"&gt;+&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt;; &lt;span class="pl-c"&gt;// Skip the opening '['&lt;/span&gt;
    &lt;span class="pl-k"&gt;for&lt;/span&gt; (&lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pl-s1"&gt;count&lt;/span&gt;; &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;i&lt;/span&gt;) {
        &lt;span class="pl-s1"&gt;values&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;] &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;strtof&lt;/span&gt;(&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;, (&lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;)&lt;span class="pl-c1"&gt;&amp;amp;&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;);
        &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;ptr&lt;/span&gt;; &lt;span class="pl-c"&gt;// Skip the comma or closing ']'&lt;/span&gt;
    }

    &lt;span class="pl-en"&gt;sqlite3_result_blob&lt;/span&gt;(&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-s1"&gt;values&lt;/span&gt;, &lt;span class="pl-s1"&gt;count&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;sizeof&lt;/span&gt;(&lt;span class="pl-smi"&gt;float&lt;/span&gt;), &lt;span class="pl-c1"&gt;SQLITE_TRANSIENT&lt;/span&gt;);
    &lt;span class="pl-en"&gt;free&lt;/span&gt;(&lt;span class="pl-s1"&gt;values&lt;/span&gt;);
}

&lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-smi"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;vector_similarity&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3_context&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;argc&lt;/span&gt;, &lt;span class="pl-smi"&gt;sqlite3_value&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;argv&lt;/span&gt;) {
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;a&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; (&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;)&lt;span class="pl-en"&gt;sqlite3_value_blob&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]);
    &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;b&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; (&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;)&lt;span class="pl-en"&gt;sqlite3_value_blob&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;1&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;size&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_bytes&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]) / &lt;span class="pl-k"&gt;sizeof&lt;/span&gt;(&lt;span class="pl-smi"&gt;float&lt;/span&gt;);

    &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-s1"&gt;dot_product&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;, &lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;, &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;;
    &lt;span class="pl-k"&gt;for&lt;/span&gt; (&lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;; &lt;span class="pl-s1"&gt;i&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt; &lt;span class="pl-s1"&gt;size&lt;/span&gt;; &lt;span class="pl-c1"&gt;++&lt;/span&gt;&lt;span class="pl-s1"&gt;i&lt;/span&gt;) {
        &lt;span class="pl-s1"&gt;dot_product&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;] &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;b&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;];
        &lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;] &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;];
        &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt; &lt;span class="pl-c1"&gt;+=&lt;/span&gt; &lt;span class="pl-s1"&gt;b&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;] &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;b&lt;/span&gt;[&lt;span class="pl-s1"&gt;i&lt;/span&gt;];
    }
    &lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqrtf&lt;/span&gt;(&lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt;);
    &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqrtf&lt;/span&gt;(&lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt;);

    &lt;span class="pl-smi"&gt;float&lt;/span&gt; &lt;span class="pl-s1"&gt;similarity&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;dot_product&lt;/span&gt; / (&lt;span class="pl-s1"&gt;magnitude_a&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;magnitude_b&lt;/span&gt;);
    &lt;span class="pl-en"&gt;sqlite3_result_double&lt;/span&gt;(&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-s1"&gt;similarity&lt;/span&gt;);
}

&lt;span class="pl-k"&gt;#ifdef&lt;/span&gt; &lt;span class="pl-s1"&gt;_WIN32&lt;/span&gt;
__declspec(&lt;span class="pl-s1"&gt;dllexport&lt;/span&gt;)
&lt;span class="pl-k"&gt;#endif&lt;/span&gt;
&lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_vector_init&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;db&lt;/span&gt;, &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;pzErrMsg&lt;/span&gt;, &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;sqlite3_api_routines&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;pApi&lt;/span&gt;) {
    &lt;span class="pl-c1"&gt;SQLITE_EXTENSION_INIT2&lt;/span&gt;(&lt;span class="pl-smi"&gt;pApi&lt;/span&gt;)
    &lt;span class="pl-en"&gt;sqlite3_create_function&lt;/span&gt;(&lt;span class="pl-smi"&gt;db&lt;/span&gt;, "&lt;span class="pl-smi"&gt;vector_decode&lt;/span&gt;", &lt;span class="pl-c1"&gt;1&lt;/span&gt;, &lt;span class="pl-smi"&gt;SQLITE_UTF8&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;, &lt;span class="pl-smi"&gt;vector_decode&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;);
    &lt;span class="pl-en"&gt;sqlite3_create_function&lt;/span&gt;(&lt;span class="pl-s1"&gt;db&lt;/span&gt;, &lt;span class="pl-s"&gt;"vector_encode"&lt;/span&gt;, &lt;span class="pl-c1"&gt;1&lt;/span&gt;, &lt;span class="pl-c1"&gt;SQLITE_UTF8&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;, &lt;span class="pl-s1"&gt;vector_encode&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;);
    &lt;span class="pl-en"&gt;sqlite3_create_function&lt;/span&gt;(&lt;span class="pl-s1"&gt;db&lt;/span&gt;, &lt;span class="pl-s"&gt;"vector_similarity"&lt;/span&gt;, &lt;span class="pl-c1"&gt;2&lt;/span&gt;, &lt;span class="pl-c1"&gt;SQLITE_UTF8&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;, &lt;span class="pl-s1"&gt;vector_similarity&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;, &lt;span class="pl-c1"&gt;NULL&lt;/span&gt;);
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-c1"&gt;SQLITE_OK&lt;/span&gt;;
}&lt;span class="pl-k"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;p&gt;Then I used the "Use your code interpreter tool to show me the version of your Python and SQLite" trick, then "Now use subprocess.run() to call "gcc --version" and tell me that version", and then:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Now run this: ["gcc", "-shared", "-fPIC", "-o", "/mnt/data/vector.so", "/mnt/data/vector.c", "-lsqlite3"]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That's the compile command the previous session had been using - I figured just copying that across would likely work.&lt;/p&gt;
&lt;p&gt;And it did!&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-c"&gt;# Compile the C code into a shared library using GCC&lt;/span&gt;
&lt;span class="pl-s1"&gt;compile_result&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;subprocess&lt;/span&gt;.&lt;span class="pl-en"&gt;run&lt;/span&gt;([&lt;span class="pl-s"&gt;"gcc"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-shared"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-fPIC"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-o"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/vector.so"&lt;/span&gt;, &lt;span class="pl-s"&gt;"/mnt/data/vector.c"&lt;/span&gt;, &lt;span class="pl-s"&gt;"-lsqlite3"&lt;/span&gt;], &lt;span class="pl-s1"&gt;capture_output&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;, &lt;span class="pl-s1"&gt;text&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Check if there were any errors during compilation&lt;/span&gt;
&lt;span class="pl-k"&gt;if&lt;/span&gt; &lt;span class="pl-s1"&gt;compile_result&lt;/span&gt;.&lt;span class="pl-s1"&gt;returncode&lt;/span&gt; &lt;span class="pl-c1"&gt;!=&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;compilation_error&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;compile_result&lt;/span&gt;.&lt;span class="pl-s1"&gt;stderr&lt;/span&gt;
&lt;span class="pl-k"&gt;else&lt;/span&gt;:
    &lt;span class="pl-s1"&gt;compilation_error&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;None&lt;/span&gt;

&lt;span class="pl-s1"&gt;compilation_error&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;I prompted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Load the resulting extension into SQLite in Python and try out the new functions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was the moment of truth. Would it work? Would it even know how to use the new functions, given all it had seen so far was their implementation in C?&lt;/p&gt;
&lt;p&gt;Here's what it did:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;json&lt;/span&gt;

&lt;span class="pl-c"&gt;# Connect to an in-memory SQLite database&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;sqlite3&lt;/span&gt;.&lt;span class="pl-en"&gt;connect&lt;/span&gt;(&lt;span class="pl-s"&gt;":memory:"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;enable_load_extension&lt;/span&gt;(&lt;span class="pl-c1"&gt;True&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Load the compiled shared library&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;load_extension&lt;/span&gt;(&lt;span class="pl-s"&gt;"/mnt/data/vector.so"&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Create a sample table with vector data&lt;/span&gt;
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"CREATE TABLE vectors (id INTEGER PRIMARY KEY, vector BLOB)"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"INSERT INTO vectors (vector) VALUES (vector_encode('[1.0, 2.0, 3.0]'))"&lt;/span&gt;)
&lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"INSERT INTO vectors (vector) VALUES (vector_encode('[3.0, 2.0, 1.0]'))"&lt;/span&gt;)

&lt;span class="pl-c"&gt;# Test the vector_decode function&lt;/span&gt;
&lt;span class="pl-s1"&gt;decoded_vector&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"SELECT vector_decode(vector) FROM vectors"&lt;/span&gt;).&lt;span class="pl-en"&gt;fetchall&lt;/span&gt;()
&lt;span class="pl-s1"&gt;decoded_vector&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; [&lt;span class="pl-s1"&gt;json&lt;/span&gt;.&lt;span class="pl-en"&gt;loads&lt;/span&gt;(&lt;span class="pl-s1"&gt;row&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]) &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;row&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-s1"&gt;decoded_vector&lt;/span&gt;]

&lt;span class="pl-c"&gt;# Test the vector_similarity function&lt;/span&gt;
&lt;span class="pl-s1"&gt;similarity&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;conn&lt;/span&gt;.&lt;span class="pl-en"&gt;execute&lt;/span&gt;(&lt;span class="pl-s"&gt;"SELECT vector_similarity(vector, vector) FROM vectors"&lt;/span&gt;).&lt;span class="pl-en"&gt;fetchall&lt;/span&gt;()
&lt;span class="pl-s1"&gt;similarity&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; [&lt;span class="pl-s1"&gt;row&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;] &lt;span class="pl-k"&gt;for&lt;/span&gt; &lt;span class="pl-s1"&gt;row&lt;/span&gt; &lt;span class="pl-c1"&gt;in&lt;/span&gt; &lt;span class="pl-s1"&gt;similarity&lt;/span&gt;]

&lt;span class="pl-s1"&gt;decoded_vector&lt;/span&gt;, &lt;span class="pl-s1"&gt;similarity&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre style="white-space: pre-wrap"&gt;&lt;code&gt;([[1.0, 2.0, 3.0], [3.0, 2.0, 1.0]], [0.9999999403953552, 0.9999999403953552])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it added commentary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The extension was successfully loaded into SQLite, and the new functions were tested:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;vector_decode&lt;/code&gt; function successfully decoded the vectors from the database, resulting in &lt;code&gt;[[1.0, 2.0, 3.0], [3.0, 2.0, 1.0]]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;vector_similarity&lt;/code&gt; function successfully calculated the similarity of each vector with itself, resulting in &lt;code&gt;[0.9999999403953552, 0.9999999403953552]&lt;/code&gt;, which is essentially 1.0 as expected for identical vectors. ​&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;We got there! I now have a full, working prototype of a SQLite C extension for vector comparison functions, and I didn't have to write a single line of C code myself.&lt;/p&gt;
&lt;p&gt;I continued prompting - I got it to do a performance comparison against the original Python implementation, and even had it brainstorm potential security bugs in the C code and try to exploit a few of them. Take a look at &lt;a href="https://chat.openai.com/share/29bd1d15-66ed-4902-8eb1-3e9c7b820af2"&gt;the full transcript of that session&lt;/a&gt; for details.&lt;/p&gt;
&lt;h4 id="running-on-macos"&gt;It runs on macOS too&lt;/h4&gt;
&lt;p&gt;With a few extra hints from ChatGPT (I asked how to compile it on a Mac), I downloaded that &lt;code&gt;vector.c&lt;/code&gt; file to my laptop and got the following to work:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre style="white-space: pre-wrap"&gt;/tmp % mv &lt;span class="pl-k"&gt;~&lt;/span&gt;/Downloads/vector.c &lt;span class="pl-c1"&gt;.&lt;/span&gt;
/tmp % gcc -shared -fPIC -o vector.dylib -I/opt/homebrew/Cellar/sqlite/3.45.1/include vector.c -lsqlite3
/tmp % python&lt;/pre&gt;&lt;/div&gt;
&lt;div class="highlight highlight-text-python-console"&gt;&lt;pre style="white-space: pre-wrap"&gt;Python 3.10.10 (main, Mar 21 2023, 13:41:05) [Clang 14.0.6 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.
&amp;gt;&amp;gt;&amp;gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; sqlite3
&amp;gt;&amp;gt;&amp;gt; conn &lt;span class="pl-k"&gt;=&lt;/span&gt; sqlite3.connect(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;:memory:&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&amp;gt;&amp;gt;&amp;gt; conn.enable_load_extension(&lt;span class="pl-c1"&gt;True&lt;/span&gt;)
&amp;gt;&amp;gt;&amp;gt; conn.load_extension(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;/tmp/vector.dylib&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&amp;gt;&amp;gt;&amp;gt; conn.execute(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;CREATE TABLE vectors (id INTEGER PRIMARY KEY, vector BLOB)&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&amp;lt;sqlite3.Cursor object at 0x1047fecc0&amp;gt;
&amp;gt;&amp;gt;&amp;gt; conn.execute(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;INSERT INTO vectors (vector) VALUES (vector_encode('[1.0, 2.0, 3.0]'))&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&amp;lt;sqlite3.Cursor object at 0x1047fee40&amp;gt;
&amp;gt;&amp;gt;&amp;gt; conn.execute(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;INSERT INTO vectors (vector) VALUES (vector_encode('[3.0, 2.0, 1.0]'))&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;)
&amp;lt;sqlite3.Cursor object at 0x1047fecc0&amp;gt;
&amp;gt;&amp;gt;&amp;gt; decoded_vector &lt;span class="pl-k"&gt;=&lt;/span&gt; conn.execute(&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;SELECT vector_decode(vector) FROM vectors&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;).fetchall()
&amp;gt;&amp;gt;&amp;gt; decoded_vector
[('[1.00, 2.00, 3.00]',), ('[3.00, 2.00, 1.00]',)]&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So I've now seen that C extension run on both Linux and macOS.&lt;/p&gt;
&lt;h4 id="whole-project-on-my-phone"&gt;I did this whole project on my phone&lt;/h4&gt;
&lt;p&gt;Here's the thing I enjoy most about using Code Interpreter for these kinds of prototypes: since the prompts are short, and there's usually a delay of 30s+ between each prompt while it does its thing, I can do the whole thing on my phone while doing other things.&lt;/p&gt;
&lt;p&gt;In this particular case I started out in bed, then got up, fed the dog, made coffee and pottered around the house for a bit - occasionally glancing back at my screen and poking it in a new direction with another prompt.&lt;/p&gt;
&lt;p&gt;This almost doesn't count as a project at all. It began as mild curiosity, and I only started taking it seriously when it became apparent that it was likely to produce a working result.&lt;/p&gt;
&lt;p&gt;I only switched to my laptop right at the end, to try out the macOS compilation steps.&lt;/p&gt;
&lt;p&gt;Total time invested: around an hour, but that included various other morning activities (coffee, dog maintenance, letting out the chickens.)&lt;/p&gt;
&lt;p&gt;Which leads to the dilemma that affects so many of my weird little ChatGPT experiments:&lt;/p&gt;
&lt;h4 id="the-dilemma"&gt;The dilemma: do I finish this project?&lt;/h4&gt;
&lt;p&gt;Thanks to Code Interpreter I now have a working prototype of something I would &lt;em&gt;never&lt;/em&gt; have attempted to build on my own. My knowledge of C is thin enough that I don't remotely have the confidence to try something like this myself.&lt;/p&gt;
&lt;p&gt;Taking what I've got so far and turning it into code that I would feel responsible using - and sharing with other people - requires the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I need to manually test it &lt;em&gt;really&lt;/em&gt; thoroughly. I haven't actually done the work to ensure it's returning the right results yet!&lt;/li&gt;
&lt;li&gt;I need to make sure I understand every line of C code that it's written for me&lt;/li&gt;
&lt;li&gt;I then need to review that code, and make sure it's sensible and logic-error-free&lt;/li&gt;
&lt;li&gt;I need to audit it for security&lt;/li&gt;
&lt;li&gt;I need to add comprehensive automated tests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I should probably drop the &lt;code&gt;vector_encode()&lt;/code&gt; and &lt;code&gt;vector_decode()&lt;/code&gt; functions entirely - parsing a JSON-like string in C is fraught with additional risk already, and those aren't performance critical - just having a fast &lt;code&gt;vector_similarity()&lt;/code&gt; function that worked against BLOBs would give me the performance gain I'm looking for.&lt;/p&gt;
&lt;p&gt;All of this is a &lt;em&gt;lot&lt;/em&gt; of extra work. ChatGPT can help me in various ways with each of those steps, but it's still on me to do the work and make absolutely sure that I'm confident in my understanding beyond just what got hallucinated at me by a bunch of black-box matrices.&lt;/p&gt;
&lt;p&gt;This project was not in my plans for the weekend. I'm not going to put that work in right now - so "SQLite C extension for vector similarity" will be added to my ever-growing list of half-baked ideas that LLMs helped me prototype way beyond what I would have been able to do on my own.&lt;/p&gt;
&lt;p&gt;So I'm going to blog about it, and move on. I may well revisit this - the performance gains over my Python functions looked to be 16-83x (according to a benchmark that ChatGPT ran for me which I have not taken the time to verify) which is a &lt;em&gt;very&lt;/em&gt; material improvement. But for the moment I have so many other things I need to prioritize.&lt;/p&gt;
&lt;p&gt;If anyone else wants to take this and turn it into something usable, please be my guest!&lt;/p&gt;

&lt;h4 id="bonus-haversine"&gt;Bonus: haversine() in C&lt;/h4&gt;
&lt;p&gt;I took Cleo for a walk on the beach and had the idea to try implementing a &lt;code&gt;haversine(lat1, lon1, lat2, lon2)&lt;/code&gt; SQL function in C, for fast calculation of the approximate distance between two points on earth. This could enable fast-enough brute force "points closest to X, Y" searches against medium sized tables of locations.&lt;/p&gt;
&lt;p&gt;Here's &lt;a href="https://chat.openai.com/share/77996768-66ed-474a-8e33-c7ddcc4c18ff"&gt;the full transcript&lt;/a&gt; and the loosely tested C extension code that resulted from the session -  once again, all created using the ChatGPT iPhone app to interact with Code Interpreter:&lt;/p&gt;
&lt;div class="highlight highlight-source-c"&gt;&lt;pre&gt;&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;sqlite3ext.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;math.h&amp;gt;&lt;/span&gt;
&lt;span class="pl-k"&gt;#include&lt;/span&gt; &lt;span class="pl-s"&gt;&amp;lt;stddef.h&amp;gt;&lt;/span&gt; &lt;span class="pl-c"&gt;// Add this line&lt;/span&gt;

&lt;span class="pl-smi"&gt;SQLITE_EXTENSION_INIT1&lt;/span&gt;

&lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-s1"&gt;double&lt;/span&gt; &lt;span class="pl-en"&gt;deg2rad&lt;/span&gt;(&lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;deg&lt;/span&gt;) {
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-s1"&gt;deg&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; (&lt;span class="pl-c1"&gt;M_PI&lt;/span&gt; / &lt;span class="pl-c1"&gt;180&lt;/span&gt;);
}

&lt;span class="pl-k"&gt;static&lt;/span&gt; &lt;span class="pl-smi"&gt;void&lt;/span&gt; &lt;span class="pl-en"&gt;haversine&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3_context&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;context&lt;/span&gt;, &lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-s1"&gt;argc&lt;/span&gt;, &lt;span class="pl-smi"&gt;sqlite3_value&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;argv&lt;/span&gt;) {
    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;lat1&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_double&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;lon1&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_double&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;1&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;lat2&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_double&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;2&lt;/span&gt;]);
    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;lon2&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_value_double&lt;/span&gt;(&lt;span class="pl-s1"&gt;argv&lt;/span&gt;[&lt;span class="pl-c1"&gt;3&lt;/span&gt;]);

    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;earth_radius&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;6371000&lt;/span&gt;; &lt;span class="pl-c"&gt;// meters&lt;/span&gt;

    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;dLat&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;deg2rad&lt;/span&gt;(&lt;span class="pl-s1"&gt;lat2&lt;/span&gt; &lt;span class="pl-c1"&gt;-&lt;/span&gt; &lt;span class="pl-s1"&gt;lat1&lt;/span&gt;);
    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;dLon&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;deg2rad&lt;/span&gt;(&lt;span class="pl-s1"&gt;lon2&lt;/span&gt; &lt;span class="pl-c1"&gt;-&lt;/span&gt; &lt;span class="pl-s1"&gt;lon1&lt;/span&gt;);

    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;sin&lt;/span&gt;(&lt;span class="pl-s1"&gt;dLat&lt;/span&gt; / &lt;span class="pl-c1"&gt;2&lt;/span&gt;) &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;sin&lt;/span&gt;(&lt;span class="pl-s1"&gt;dLat&lt;/span&gt; / &lt;span class="pl-c1"&gt;2&lt;/span&gt;) &lt;span class="pl-c1"&gt;+&lt;/span&gt;
               &lt;span class="pl-en"&gt;cos&lt;/span&gt;(&lt;span class="pl-en"&gt;deg2rad&lt;/span&gt;(&lt;span class="pl-s1"&gt;lat1&lt;/span&gt;)) &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;cos&lt;/span&gt;(&lt;span class="pl-en"&gt;deg2rad&lt;/span&gt;(&lt;span class="pl-s1"&gt;lat2&lt;/span&gt;)) &lt;span class="pl-c1"&gt;*&lt;/span&gt;
               &lt;span class="pl-en"&gt;sin&lt;/span&gt;(&lt;span class="pl-s1"&gt;dLon&lt;/span&gt; / &lt;span class="pl-c1"&gt;2&lt;/span&gt;) &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;sin&lt;/span&gt;(&lt;span class="pl-s1"&gt;dLon&lt;/span&gt; / &lt;span class="pl-c1"&gt;2&lt;/span&gt;);

    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;c&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;2&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;atan2&lt;/span&gt;(&lt;span class="pl-en"&gt;sqrt&lt;/span&gt;(&lt;span class="pl-s1"&gt;a&lt;/span&gt;), &lt;span class="pl-en"&gt;sqrt&lt;/span&gt;(&lt;span class="pl-c1"&gt;1&lt;/span&gt; &lt;span class="pl-c1"&gt;-&lt;/span&gt; &lt;span class="pl-s1"&gt;a&lt;/span&gt;));

    &lt;span class="pl-smi"&gt;double&lt;/span&gt; &lt;span class="pl-s1"&gt;distance&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-s1"&gt;earth_radius&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-s1"&gt;c&lt;/span&gt;;

    &lt;span class="pl-en"&gt;sqlite3_result_int&lt;/span&gt;(&lt;span class="pl-s1"&gt;context&lt;/span&gt;, (&lt;span class="pl-smi"&gt;int&lt;/span&gt;)&lt;span class="pl-en"&gt;round&lt;/span&gt;(&lt;span class="pl-s1"&gt;distance&lt;/span&gt;));
}

&lt;span class="pl-k"&gt;#ifdef&lt;/span&gt; &lt;span class="pl-s1"&gt;_WIN32&lt;/span&gt;
__declspec(&lt;span class="pl-s1"&gt;dllexport&lt;/span&gt;)
&lt;span class="pl-k"&gt;#endif&lt;/span&gt;
&lt;span class="pl-smi"&gt;int&lt;/span&gt; &lt;span class="pl-en"&gt;sqlite3_extension_init&lt;/span&gt;(&lt;span class="pl-smi"&gt;sqlite3&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;db&lt;/span&gt;, &lt;span class="pl-smi"&gt;char&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;pzErrMsg&lt;/span&gt;, &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;sqlite3_api_routines&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt;&lt;span class="pl-s1"&gt;pApi&lt;/span&gt;) {
    &lt;span class="pl-c1"&gt;SQLITE_EXTENSION_INIT2&lt;/span&gt;(&lt;span class="pl-smi"&gt;pApi&lt;/span&gt;)
    &lt;span class="pl-en"&gt;sqlite3_create_function&lt;/span&gt;(&lt;span class="pl-smi"&gt;db&lt;/span&gt;, "&lt;span class="pl-smi"&gt;haversine&lt;/span&gt;", &lt;span class="pl-c1"&gt;4&lt;/span&gt;, &lt;span class="pl-smi"&gt;SQLITE_UTF8&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;, &lt;span class="pl-smi"&gt;haversine&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;, &lt;span class="pl-smi"&gt;NULL&lt;/span&gt;);
    &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;;
}&lt;span class="pl-k"&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since this one boils down to just floating point numbers I may even attempt to turn this into production code!&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chatgpt"&gt;chatgpt&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai-assisted-programming"&gt;ai-assisted-programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/code-interpreter"&gt;code-interpreter&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/coding-agents"&gt;coding-agents&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="c"/><category term="projects"/><category term="sqlite"/><category term="ai"/><category term="generative-ai"/><category term="chatgpt"/><category term="llms"/><category term="ai-assisted-programming"/><category term="code-interpreter"/><category term="coding-agents"/></entry><entry><title>Beej's Guide to Networking Concepts</title><link href="https://simonwillison.net/2024/Jan/30/beejs-guide-to-networking-concepts/#atom-tag" rel="alternate"/><published>2024-01-30T22:08:56+00:00</published><updated>2024-01-30T22:08:56+00:00</updated><id>https://simonwillison.net/2024/Jan/30/beejs-guide-to-networking-concepts/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://beej.us/guide/bgnet0/"&gt;Beej&amp;#x27;s Guide to Networking Concepts&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Beej's &lt;a href="https://beej.us/guide/bgnet/"&gt;Guide to Network Programming&lt;/a&gt; is a legendary tutorial on network programming in C, continually authored and updated by Brian "Beej" Hall since 1995.&lt;/p&gt;
&lt;p&gt;This is NOT that. Beej's Guide to Networking Concepts is brand new - started in March 2023 - and illustrates a whole bunch of networking concepts using Python instead of C.&lt;/p&gt;
&lt;p&gt;From the forward:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is it Beej’s Guide to Network Programming in Python? Well, kinda, actually. The C book is more about how C’s (well, Unix’s) network API works. And this book is more about the concepts underlying it, using Python as a vehicle.&lt;/p&gt;
&lt;/blockquote&gt;

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/ehewh7/beej_s_guide_networking_concepts"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/networking"&gt;networking&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="networking"/><category term="python"/></entry><entry><title>Quoting Ned Batchelder</title><link href="https://simonwillison.net/2024/Jan/24/ned-batchelder/#atom-tag" rel="alternate"/><published>2024-01-24T18:25:21+00:00</published><updated>2024-01-24T18:25:21+00:00</updated><id>https://simonwillison.net/2024/Jan/24/ned-batchelder/#atom-tag</id><summary type="html">
    &lt;blockquote cite="https://nedbatchelder.com/blog/202401/you_probably_dont_need_to_learn_c.html"&gt;&lt;p&gt;Find a level of abstraction that works for what you need to do. When you have trouble there, look beneath that abstraction. You won’t be seeing how things really work, you’ll be seeing a lower-level abstraction that could be helpful. Sometimes what you need will be an abstraction one level up. Is your Python loop too slow? Perhaps you need a C loop. Or perhaps you need numpy array operations.&lt;/p&gt;
&lt;p&gt;You (probably) don’t need to learn C.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p class="cite"&gt;&amp;mdash; &lt;a href="https://nedbatchelder.com/blog/202401/you_probably_dont_need_to_learn_c.html"&gt;Ned Batchelder&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/abstractions"&gt;abstractions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ned-batchelder"&gt;ned-batchelder&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/programming"&gt;programming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="abstractions"/><category term="c"/><category term="ned-batchelder"/><category term="programming"/><category term="python"/></entry><entry><title>jo</title><link href="https://simonwillison.net/2023/Oct/8/jo/#atom-tag" rel="alternate"/><published>2023-10-08T05:20:09+00:00</published><updated>2023-10-08T05:20:09+00:00</updated><id>https://simonwillison.net/2023/Oct/8/jo/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/jpmens/jo"&gt;jo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Neat little C utility (available via brew/apt-get install etc) for conveniently outputting JSON from a shell: “jo -p name=jo n=17 parser=false” will output a JSON object with string, integer and boolean values, and you can nest it to create nested objects. Looks very handy.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/4wiwig/shell_tip_print_json_with_printf#c_p9pihd"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/json"&gt;json&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="json"/></entry><entry><title>TG: Polygon indexing</title><link href="https://simonwillison.net/2023/Sep/23/tg-polygon-indexing/#atom-tag" rel="alternate"/><published>2023-09-23T04:32:14+00:00</published><updated>2023-09-23T04:32:14+00:00</updated><id>https://simonwillison.net/2023/Sep/23/tg-polygon-indexing/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/tidwall/tg/blob/v0.1.0/docs/POLYGON_INDEXING.md"&gt;TG: Polygon indexing&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
TG is a brand new geospatial library by Josh Baker, author of the Tile38 in-memory spatial server (kind of a geospatial Redis). TG is written in pure C and delivered as a single C file, reminiscent of the SQLite amalgamation.&lt;/p&gt;

&lt;p&gt;TG looks really interesting. It implements almost the exact subset of geospatial functionality that I find most useful: point-in-polygon, intersect, WKT, WKB, and GeoJSON—all with no additional dependencies.&lt;/p&gt;

&lt;p&gt;The most interesting thing about it is the way it handles indexing. In this documentation Josh describes two approaches he uses to speeding up point-in-polygon and intersection using a novel approach that goes beyond the usual RTree implementation.&lt;/p&gt;

&lt;p&gt;I think this could make the basis of a really useful SQLite extension—a lighter-weight alternative to SpatiaLite.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=37619100"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/geospatial"&gt;geospatial&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/spatialite"&gt;spatialite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/geojson"&gt;geojson&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/tg"&gt;tg&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="geospatial"/><category term="spatialite"/><category term="sqlite"/><category term="geojson"/><category term="tg"/></entry><entry><title>Dynamic linker tricks: Using LD_PRELOAD to cheat, inject features and investigate programs</title><link href="https://simonwillison.net/2023/Sep/8/dynamic-linker-tricks/#atom-tag" rel="alternate"/><published>2023-09-08T22:05:10+00:00</published><updated>2023-09-08T22:05:10+00:00</updated><id>https://simonwillison.net/2023/Sep/8/dynamic-linker-tricks/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/"&gt;Dynamic linker tricks: Using LD_PRELOAD to cheat, inject features and investigate programs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This tutorial by Rafał Cieślak from 2013 filled in a bunch of gaps in my knowledge about how C works on Linux.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=37439125"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/linux"&gt;linux&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="linux"/></entry><entry><title>redbean</title><link href="https://simonwillison.net/2022/Feb/17/redbean/#atom-tag" rel="alternate"/><published>2022-02-17T06:01:18+00:00</published><updated>2022-02-17T06:01:18+00:00</updated><id>https://simonwillison.net/2022/Feb/17/redbean/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://redbean.dev/"&gt;redbean&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
“redbean makes it possible to share web applications that run offline as a single-file αcτµαlly pδrταblε εxεcµταblε zip archive which contains your assets. All you need to do is download the redbean.com program below, change the filename to .zip, add your content in a zip editing tool, and then change the extension back to .com”.&lt;/p&gt;

&lt;p&gt;redbean is implemented as a single C file with a dazzling array of clever tricks—most impressively, the single executable works on Linux, macOS, Windows and various BSDs!&lt;/p&gt;

&lt;p&gt;It embeds Lua, and in June last year added SQLite too—so self-contained distributable web applications built with Redbean can now use Lua and SQLite for dynamic scripting. Performance sounds incredible: “redbean can serve 1 million+ gzip encoded responses per second on a cheap personal computer”.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/c6ogym/redbean_single_file_distributable_web"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/lua"&gt;lua&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/redbean"&gt;redbean&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cosmopolitan"&gt;cosmopolitan&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="lua"/><category term="sqlite"/><category term="redbean"/><category term="cosmopolitan"/></entry><entry><title>Running C unit tests with pytest</title><link href="https://simonwillison.net/2022/Feb/12/running-c-unit-tests-with-pytest/#atom-tag" rel="alternate"/><published>2022-02-12T17:14:35+00:00</published><updated>2022-02-12T17:14:35+00:00</updated><id>https://simonwillison.net/2022/Feb/12/running-c-unit-tests-with-pytest/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://p403n1x87.github.io/running-c-unit-tests-with-pytest.html"&gt;Running C unit tests with pytest&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Brilliant, detailed tutorial by Gabriele Tornetta on testing C code using pytest, which also doubles up as a ctypes tutorial. There’s a lot of depth here—in addition to exercising C code through ctypes, Gabriele shows how to run each test in a separate process so that segmentation faults don’t fail the entire suite,  then adds code to run the compiler as part of the pytest run, and then shows how to use gdb trickery to generate more useful stack traces.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=30301880"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ctypes"&gt;ctypes&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/pytest"&gt;pytest&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="ctypes"/><category term="testing"/><category term="pytest"/></entry><entry><title>Mypyc</title><link href="https://simonwillison.net/2022/Jan/30/mypyc/#atom-tag" rel="alternate"/><published>2022-01-30T01:31:12+00:00</published><updated>2022-01-30T01:31:12+00:00</updated><id>https://simonwillison.net/2022/Jan/30/mypyc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://mypyc.readthedocs.io/en/latest/introduction.html"&gt;Mypyc&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Spotted this in the Black release notes: “Black is now compiled with mypyc for an overall 2x speed-up”. Mypyc is a tool that compiles Python modules (written in a subset of Python) to C extensions—similar to Cython but using just Python syntax, taking advantage of type annotations to perform type checking and type inference. It’s part of the mypy type checking project, which has been using it since 2019 to gain a 4x performance improvement over regular Python.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://black.readthedocs.io/en/stable/change_log.html#id1"&gt;Black release notes&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/performance"&gt;performance&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mypy"&gt;mypy&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="performance"/><category term="python"/><category term="mypy"/></entry><entry><title>How to look at the stack with gdb</title><link href="https://simonwillison.net/2021/May/24/how-to-look-at-the-stack-with-gdb/#atom-tag" rel="alternate"/><published>2021-05-24T18:23:48+00:00</published><updated>2021-05-24T18:23:48+00:00</updated><id>https://simonwillison.net/2021/May/24/how-to-look-at-the-stack-with-gdb/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://jvns.ca/blog/2021/05/17/how-to-look-at-the-stack-in-gdb/"&gt;How to look at the stack with gdb&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Useful short tutorial on gdb from first principles.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/debugger"&gt;debugger&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/julia-evans"&gt;julia-evans&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="debugger"/><category term="julia-evans"/></entry><entry><title>cosmopolitan libc</title><link href="https://simonwillison.net/2021/Feb/27/cosmopolitan-libc/#atom-tag" rel="alternate"/><published>2021-02-27T06:02:11+00:00</published><updated>2021-02-27T06:02:11+00:00</updated><id>https://simonwillison.net/2021/Feb/27/cosmopolitan-libc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://justine.lol/cosmopolitan/index.html"&gt;cosmopolitan libc&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
“Cosmopolitan makes C a build-once run-anywhere language, similar to Java, except it doesn’t require interpreters or virtual machines be installed beforehand. [...] Instead, it reconfigures stock GCC to output a POSIX-approved polyglot format that runs natively on Linux + Mac + Windows + FreeBSD + OpenBSD + BIOS with the best possible performance and the tiniest footprint imaginable.” This is a spectacular piece of engineering.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=26271117"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/cosmopolitan"&gt;cosmopolitan&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="cosmopolitan"/></entry><entry><title>Unravelling `not` in Python</title><link href="https://simonwillison.net/2020/Nov/27/unravelling-not-python/#atom-tag" rel="alternate"/><published>2020-11-27T17:59:28+00:00</published><updated>2020-11-27T17:59:28+00:00</updated><id>https://simonwillison.net/2020/Nov/27/unravelling-not-python/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://snarky.ca/unravelling-not-in-python/"&gt;Unravelling `not` in Python&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Part of a series where Brett Cannon looks at how fundamental Python syntactic sugar works, including a clearly explained dive into the underlying op codes and C implementation.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://django-news.com/issues/51"&gt;Django News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/brett-cannon"&gt;brett-cannon&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="python"/><category term="brett-cannon"/></entry><entry><title>CG-SQL</title><link href="https://simonwillison.net/2020/Oct/22/cg-sql/#atom-tag" rel="alternate"/><published>2020-10-22T18:25:42+00:00</published><updated>2020-10-22T18:25:42+00:00</updated><id>https://simonwillison.net/2020/Oct/22/cg-sql/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/facebookincubator/CG-SQL"&gt;CG-SQL&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This is the toolkit the Facebook Messenger team wrote to bring stored procedures to SQLite. It implements a custom version of the T-SQL language which it uses to generate C code that can then be compiled into a SQLite module.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/ricardoanderegg/status/1319324540812644352"&gt;@ricardoanderegg&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/c"&gt;c&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/facebook"&gt;facebook&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;&lt;/p&gt;



</summary><category term="c"/><category term="facebook"/><category term="sqlite"/></entry></feed>