<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Owen</title>
    <description>The latest articles on Forem by Owen (@powencu).</description>
    <link>https://forem.com/powencu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3573303%2Ffa1dc3a5-41fa-41e7-ab54-1ee237890d81.jpg</url>
      <title>Forem: Owen</title>
      <link>https://forem.com/powencu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/powencu"/>
    <language>en</language>
    <item>
      <title>Dunena Update: What Happened After I Over-Engineered My First Project 😅</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 10 May 2026 03:08:24 +0000</pubDate>
      <link>https://forem.com/powencu/dunena-update-what-happened-after-i-over-engineered-my-first-project-21fa</link>
      <guid>https://forem.com/powencu/dunena-update-what-happened-after-i-over-engineered-my-first-project-21fa</guid>
      <description>&lt;p&gt;Hello again, everyone! It's Owen. 👋&lt;/p&gt;

&lt;p&gt;Back in March, I posted about &lt;a href="https://dev.to/owenbellowen/i-over-engineered-my-first-project-bridging-typescript-and-zig-with-bun-2h8n"&gt;how I over-engineered my first project&lt;/a&gt; by building a hybrid Zig + TypeScript cache engine called &lt;strong&gt;Dunena&lt;/strong&gt;, and then deployed it on Kubernetes because... honestly I still don't fully know why. 😅&lt;/p&gt;

&lt;p&gt;The response was really encouraging, especially the detailed audit from Kowshik in the comments. Since then I've been heads-down building, and Dunena has grown into something I genuinely didn't expect when I first pushed that repo.&lt;/p&gt;

&lt;p&gt;Let me catch you up.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔢 By the Numbers
&lt;/h2&gt;

&lt;p&gt;The project went from a fun experiment to a proper versioned release. We're now at &lt;strong&gt;v0.3.1&lt;/strong&gt;, with a full changelog, release pipeline, Helm charts, a Python SDK, and more. The codebase has grown across multiple packages in the monorepo and I've learned an embarrassing amount along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  🆕 What's New
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ARC Eviction Policy
&lt;/h3&gt;

&lt;p&gt;The original Dunena only had LRU. I then added LFU. Now there's a third option: &lt;strong&gt;ARC (Adaptive Replacement Cache)&lt;/strong&gt;, implemented directly in the Zig core.&lt;/p&gt;

&lt;p&gt;ARC is a hybrid — it watches both how &lt;em&gt;recently&lt;/em&gt; and how &lt;em&gt;frequently&lt;/em&gt; you access keys, and adapts automatically. The idea is that you don't have to manually tune whether recency or frequency matters more for your workload. The Zig implementation maintains four conceptual zones and adjusts the target balance on each cache miss.&lt;/p&gt;

&lt;p&gt;You can pick your policy at startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DUNENA_EVICTION_POLICY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;arc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Atomic Operations: INCR, DECR, and CAS
&lt;/h3&gt;

&lt;p&gt;One thing I kept running into was needing to update a numeric counter without doing a GET, increment, then SET dance. So I added native atomic increment and decrement to the Zig core. It parses the stored value as an integer, adds the delta, and writes it back — all inside Zig with no round trips.&lt;/p&gt;

&lt;p&gt;I also added &lt;strong&gt;Compare-and-Swap (CAS)&lt;/strong&gt; with version tracking. Every cache entry now carries a version number that increments on write. If you want to update a key only when you're sure it hasn't changed since you last read it, you can use CAS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; PUT http://localhost:3000/cache/mykey/cas &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"value": "new-value", "expectedVersion": 3}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the version doesn't match, you get a 409 instead of silently overwriting someone else's change. It's a small thing but it opens the door to building coordination patterns on top of Dunena.&lt;/p&gt;




&lt;h3&gt;
  
  
  Distributed Locks
&lt;/h3&gt;

&lt;p&gt;Speaking of coordination — there's now a full &lt;strong&gt;distributed lock service&lt;/strong&gt;. Locks are stored in the cache with TTL for automatic release, so a crashed process won't hold a lock forever. You can acquire, release, extend, and force-release locks via the API or CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dunena lock-acquire my-job worker-1 30000
dunena lock-release my-job worker-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Cache Replication
&lt;/h3&gt;

&lt;p&gt;Dunena now supports &lt;strong&gt;write-through replication&lt;/strong&gt; to secondary instances. When you write to the primary, it fans out the mutation to registered replicas — either synchronously (waiting for confirmation) or asynchronously (fire and forget). This is useful if you want a hot standby or want to keep caches warm across regions.&lt;/p&gt;

&lt;p&gt;I want to be upfront: this is not clustering. It's intentionally simple. Dunena still uses SQLite and is still a single-writer system. But for the most common "I want redundancy" use case, this works.&lt;/p&gt;




&lt;h3&gt;
  
  
  Expanded Database Proxy Connectors
&lt;/h3&gt;

&lt;p&gt;The database proxy originally only supported PostgreSQL, MySQL, and HTTP APIs. It now also supports &lt;strong&gt;MongoDB&lt;/strong&gt;, &lt;strong&gt;Redis&lt;/strong&gt;, and &lt;strong&gt;Elasticsearch&lt;/strong&gt; as backend connectors — all using dynamic imports so they're optional peer dependencies. If you don't install &lt;code&gt;mongodb&lt;/code&gt;, the connector just isn't available; nothing breaks.&lt;/p&gt;

&lt;p&gt;The pattern is the same regardless of backend: register a connector, then query through it with automatic cache-aside behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dunena db-proxy-register mongo-users mongodb mongodb://localhost/mydb
dunena db-proxy-query mongo-users &lt;span class="s2"&gt;"users.find"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Python SDK
&lt;/h3&gt;

&lt;p&gt;This was a big one. There's now an &lt;strong&gt;official Python SDK&lt;/strong&gt; for Dunena at &lt;code&gt;sdks/python/&lt;/code&gt;, installable as the &lt;code&gt;dunena&lt;/code&gt; package. It wraps the full REST API with both sync and async clients (powered by &lt;code&gt;httpx&lt;/code&gt;), typed dataclasses for responses, and a clean exception hierarchy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dunena&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dunena&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;Dunena&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optional&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;world&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;  &lt;span class="c1"&gt;# "world"
&lt;/span&gt;
    &lt;span class="c1"&gt;# Durable storage
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Alice&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user:42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The async version works the same way with &lt;code&gt;AsyncDunena&lt;/code&gt; and &lt;code&gt;async with&lt;/code&gt;. Go and Rust SDKs are still on the backlog.&lt;/p&gt;




&lt;h3&gt;
  
  
  Health Check Enhancements (responding to Kowshik's feedback!)
&lt;/h3&gt;

&lt;p&gt;One of the things Kowshik pointed out was that production health checks need more than just &lt;code&gt;{ "status": "ok" }&lt;/code&gt;. The &lt;code&gt;/health&lt;/code&gt; endpoint now returns structured diagnostics:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.3.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"uptime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"checks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"zigCore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"latencyMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sqlite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"up"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"latencyMs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"memory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"heapUsedMB"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"rssMB"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;180&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cache"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"entries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5421&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"hitRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.87&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are also two new probe endpoints that Kubernetes can use properly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /health/live&lt;/code&gt; — just returns 200, confirms the process is alive&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /health/ready&lt;/code&gt; — checks SQLite is writable before saying ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The k8s manifests and Helm chart now point probes at these instead of the generic &lt;code&gt;/health&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  k6 Benchmark Suite
&lt;/h3&gt;

&lt;p&gt;Kowshik also asked about load testing. The honest answer in March was "I don't have one." That's fixed now. There's a proper k6 benchmark suite at &lt;code&gt;scripts/bench/&lt;/code&gt; with scripts for basic CRUD throughput, batch operations, and a realistic 80/20 read/write mixed workload.&lt;/p&gt;

&lt;p&gt;The thresholds are enforced too: p95 &amp;lt; 10ms for GETs, p95 &amp;lt; 15ms for SETs, and less than 1% error rate. These run as part of the release preparation workflow.&lt;/p&gt;




&lt;h3&gt;
  
  
  Helm Chart and Terraform
&lt;/h3&gt;

&lt;p&gt;The deployment story got a lot better. There's now a full &lt;strong&gt;Helm chart&lt;/strong&gt; at &lt;code&gt;deploy/helm/dunena/&lt;/code&gt; that exposes all config as values, handles PVC creation, wires up the new health probes, and manages auth token secrets properly.&lt;/p&gt;

&lt;p&gt;There's also a &lt;strong&gt;Terraform module&lt;/strong&gt; for deploying to AWS ECS Fargate with EFS for persistent SQLite storage. The EFS approach sidesteps the SQLite single-writer problem cleanly since there's still only one task running against it, but storage is detached from the container lifecycle.&lt;/p&gt;




&lt;h3&gt;
  
  
  Next.js Documentation
&lt;/h3&gt;

&lt;p&gt;The documentation site (previously a static HTML file served from the server) has been migrated to &lt;strong&gt;Next.js&lt;/strong&gt; with static export. It now has a proper sidebar, dark/light theme, mobile layout, search, and an interactive API explorer powered by Scalar.&lt;/p&gt;




&lt;h2&gt;
  
  
  🤔 What I've Learned Since March
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;AI agents got better at the FFI boundary, but still need watching.&lt;/strong&gt; I still use Claude and Gemini heavily, but I've gotten better at catching when generated code changes a Zig type without updating the corresponding FFI declaration in TypeScript. The rule I now follow without exception: any change to &lt;code&gt;exports.zig&lt;/code&gt; gets a diff against &lt;code&gt;ffi.ts&lt;/code&gt; before it gets committed. The CI pipeline type-checks this, but catching it manually first saves a confusing crash later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;ReleaseSafe&lt;/code&gt; is the right default.&lt;/strong&gt; This came up in Kowshik's comment and I want to reinforce it. Building Zig with &lt;code&gt;-Doptimize=ReleaseSafe&lt;/code&gt; (which is what &lt;code&gt;bun run build:zig&lt;/code&gt; does) keeps bounds checking active. Panics become clean process aborts rather than silent undefined behavior. The performance cost is small and worth it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLite is fine, actually.&lt;/strong&gt; I got a bit anxious after all the comments about scaling SQLite, but for what Dunena is — a single-writer cache layer — SQLite with WAL mode is genuinely excellent. The replication feature lets you propagate writes to replicas. For horizontal read scaling, you disable the DB layer and use only the in-memory Zig cache per instance. It's not Postgres, but it doesn't need to be.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔭 What's Still Coming
&lt;/h2&gt;

&lt;p&gt;There are a few things still on the backlog that I want to be honest about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis RESP protocol adapter&lt;/strong&gt; — so Dunena can act as a drop-in replacement for Redis clients without any code changes on the client side. This is a big one and still in design phase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GraphQL API endpoint&lt;/strong&gt; — for batched queries, especially useful with the database proxy layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenTelemetry tracing&lt;/strong&gt; — alongside the existing Prometheus metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go and Rust SDKs&lt;/strong&gt; — the Python SDK was first but there's more to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket integration tests&lt;/strong&gt; — I'm not going to pretend these are fully covered yet.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🙏 Thanks
&lt;/h2&gt;

&lt;p&gt;Genuinely, thank you to everyone who starred the repo, and reached out. Building in public is kind of terrifying but the feedback has been really useful and pushed the project forward in ways I wouldn't have figured out alone.&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/PowenCu/dunena" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
🔗 &lt;strong&gt;&lt;a href="https://powencu.github.io/dunena/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you've got feedback, ideas, or want to contribute — PRs and issues are very welcome. And if you've built something with Dunena or tried the Python SDK, I'd genuinely love to hear about it in the comments. 👇&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>zig</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>I Over-Engineered My First Project: Bridging TypeScript and Zig with Bun! 🚀</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Mon, 16 Mar 2026 02:29:06 +0000</pubDate>
      <link>https://forem.com/powencu/i-over-engineered-my-first-project-bridging-typescript-and-zig-with-bun-2h8n</link>
      <guid>https://forem.com/powencu/i-over-engineered-my-first-project-bridging-typescript-and-zig-with-bun-2h8n</guid>
      <description>&lt;p&gt;Hello, hello! It's me Owen again!&lt;/p&gt;

&lt;p&gt;I've been inactive for awhile and thought maybe I should post again (Even if this is my second post fully). Some people say that coding project should start with To-do lists, REST APIs, Generators, etc.&lt;/p&gt;

&lt;p&gt;Instead, I decided to dive completely into the deep end. I wanted to build something fast, learn about memory management, and figure out how different languages talk to each other. &lt;/p&gt;

&lt;p&gt;So, I built &lt;strong&gt;Dunena&lt;/strong&gt;—a high-performance, hybrid-architecture monorepo. It leverages &lt;strong&gt;Bun&lt;/strong&gt; and &lt;strong&gt;TypeScript&lt;/strong&gt; for the web layer, and delegates heavy CPU tasks to &lt;strong&gt;Zig&lt;/strong&gt; via a Foreign Function Interface (FFI). Oh, and I deployed it on Kubernetes. Because why not? 😅 (But don't worry about that since I'm still new to Docker and Kubernetes.)&lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/OwenBellowen/dunena" rel="noopener noreferrer"&gt;Check out the Dunena Repository on GitHub here!&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
🔗 &lt;strong&gt;&lt;a href="https://owenbellowen.github.io/dunena/" rel="noopener noreferrer"&gt;Check the documentation here!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is a breakdown of what I built, how it works, and the massive amount of things I learned along the way.&lt;/p&gt;


&lt;h3&gt;
  
  
  🏗️ What is Dunena?
&lt;/h3&gt;

&lt;p&gt;At its core, Dunena is a backend platform designed to handle requests quickly and efficiently. It features routing, WebSockets, pub/sub services, and a caching layer. &lt;/p&gt;

&lt;p&gt;But the real magic is under the hood. I wanted the rapid development speed of TypeScript, but I didn't want Node/Bun to get bogged down by heavy computations like compression, bloom filters, or complex stat calculations. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Tech Stack:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Runtime &amp;amp; Monorepo Manager:&lt;/strong&gt; Bun 🥟&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Primary Language:&lt;/strong&gt; TypeScript (Strict mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Performance Core:&lt;/strong&gt; Zig ⚡&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; SQLite 🗄️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; Docker &amp;amp; Kubernetes 🐳 (Again I'm new to this so bare in mind)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  🧠 The Architecture
&lt;/h3&gt;

&lt;p&gt;The coolest (and scariest) part of this project is the FFI bridge. Here is how a request goes from TypeScript to near bare-metal execution in Zig.&lt;/p&gt;

&lt;p&gt;First, I write the high-performance logic in Zig and export it using the C Application Binary Interface (ABI):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight zig"&gt;&lt;code&gt;&lt;span class="c"&gt;// zig/src/exports.zig&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;@import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"std"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;// Exporting a function so Bun can read it via the C ABI&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;compute_heavy_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;i32&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Imagine some incredibly complex, CPU-blocking math here&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_val&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in my TypeScript platform package, I use Bun's native &lt;code&gt;dlopen&lt;/code&gt; to load the compiled Zig shared library and bridge the function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// packages/platform/src/bridge/ffi.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dlopen&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FFIType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;suffix&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bun:ffi&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Load the compiled Zig library&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`../../zig/zig-out/lib/libdunena_core.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;compute_heavy_stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;FFIType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;returns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FFIType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Now I can call Zig directly from TypeScript!&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runStats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;symbols&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compute_heavy_stats&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a client hits my Bun server (&lt;code&gt;apps/server/src/index.ts&lt;/code&gt;), the platform handles the API routing, hands the heavy computation off to Zig, and returns the result instantly.&lt;/p&gt;




&lt;h3&gt;
  
  
  🤖 The "AI" Elephant in the Room
&lt;/h3&gt;

&lt;p&gt;I want to be totally transparent: &lt;strong&gt;I used AI coding agents to help build this.&lt;/strong&gt; Using tools like Claude and Gemini was incredible for speeding up the boilerplate, setting up the monorepo structure, and scaffolding the initial file architecture. It felt like having a senior developer sitting next to me typing out the boring stuff.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;However...&lt;/strong&gt; AI agents are terrifyingly bad at manually managing memory across an FFI boundary. &lt;/p&gt;

&lt;p&gt;If the AI changed a data type in Zig but forgot to update the exact corresponding FFI definition in TypeScript, the server would just crash with a memory access violation. The AI helped me move fast, but &lt;strong&gt;I still had to do the brutal, hair-pulling debugging and fixing.&lt;/strong&gt; Figuring out how to safely pass pointers, prevent memory leaks, and get Kubernetes to play nice with an attached SQLite volume was all human effort. It taught me not to blindly trust generated code, especially when dealing with low-level systems.&lt;/p&gt;




&lt;h3&gt;
  
  
  🧗 The Biggest Challenges
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Managing Memory Across the Void&lt;/strong&gt;&lt;br&gt;
When you pass data between TypeScript and Zig, there are no safety nets. Bun’s garbage collector has no idea what Zig is doing. Learning how to manually manage memory and use &lt;code&gt;defer&lt;/code&gt; statements in Zig was a huge hurdle!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. SQLite in Kubernetes&lt;/strong&gt;&lt;br&gt;
Deploying an SQLite database (which is essentially a physical file) attached to a K8s pod via Persistent Volume Claims (PVC) was tricky. It works great for a single pod, but I quickly realized that if I scale this horizontally, I might run into database locking issues. &lt;/p&gt;




&lt;h3&gt;
  
  
  🚀 What's Next?
&lt;/h3&gt;

&lt;p&gt;This project is far from "finished." I'm currently maintaining this project on my own, but would love to see anyone who'd try and contribute!&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Connect!
&lt;/h3&gt;

&lt;p&gt;Since this is my first major project, I would absolutely love any feedback, code reviews, or advice from the community. &lt;/p&gt;

&lt;p&gt;🔗 &lt;strong&gt;&lt;a href="https://github.com/OwenBellowen/dunena" rel="noopener noreferrer"&gt;Check out the code on GitHub&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
🔗 &lt;strong&gt;&lt;a href="https://owenbellowen.github.io/dunena/" rel="noopener noreferrer"&gt;Check the documentation here!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Have you ever tried mixing languages like this or fighting with FFI boundaries? Let me know in the comments! 👇&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>zig</category>
      <category>typescript</category>
      <category>programming</category>
    </item>
    <item>
      <title>Elba Lang</title>
      <dc:creator>Owen</dc:creator>
      <pubDate>Sun, 19 Oct 2025 04:08:36 +0000</pubDate>
      <link>https://forem.com/powencu/elba-lang-408g</link>
      <guid>https://forem.com/powencu/elba-lang-408g</guid>
      <description>&lt;h2&gt;
  
  
  Elba — A modern, statically-typed programming language with multiple compilation backends
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/OwenBellowen/elba" rel="noopener noreferrer"&gt;GitHub → OwenBellowen/elba&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As someone deeply interested in programming languages, compilers, and full-stack systems (yes, that’s me: a student, TypeScript/Zig/Rust dev), I’m excited to introduce &lt;strong&gt;Elba&lt;/strong&gt; — a project I’ve been working on that brings together clarity, performance, and tooling in one language.&lt;/p&gt;

&lt;p&gt;Note: I have no intentions yet on making this into a full project. Although I would continue working on this.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 What is Elba?
&lt;/h2&gt;

&lt;p&gt;Elba is a statically-typed programming language designed for clarity, performance, and developer productivity.&lt;br&gt;&lt;br&gt;
It offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Static type checking &lt;strong&gt;with type inference&lt;/strong&gt; — so you get all the safety of static typing without &lt;em&gt;always&lt;/em&gt; writing verbose annotations.
&lt;/li&gt;
&lt;li&gt;Generics — write reusable, type-safe code.
&lt;/li&gt;
&lt;li&gt;Union types, optional types (&lt;code&gt;T?&lt;/code&gt;) for null safety — fewer runtime surprises.
&lt;/li&gt;
&lt;li&gt;A module system, first-class functions, rich arrays, structs with methods.
&lt;/li&gt;
&lt;li&gt;Multiple backends: AST interpreter for quick prototyping, IR interpreter for faster execution, a C code generator, and an LLVM backend for native performance. &lt;/li&gt;
&lt;li&gt;A standard library covering math, strings, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: think “modern language with the expressiveness of high-level code” + “compiled speed” + “tooling and REPL to iterate fast”.&lt;/p&gt;


&lt;h2&gt;
  
  
  ✨ Why build Elba?
&lt;/h2&gt;

&lt;p&gt;Because I believe we can push the boundaries of what a new language can offer. Specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type safety meets productivity&lt;/strong&gt;: We want the benefits of static typing (fewer bugs) without getting bogged down in ceremony.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple backend flexibility&lt;/strong&gt;: Sometimes you just want a quick REPL or interpreter; other times you need native speed. Elba gives you both.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;For compiler / language-enthusiasts&lt;/strong&gt;: If you love messing around with languages, building tooling, or exploring alternative type systems (hello Zig and Rust fans), this is a playground.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern developer experience&lt;/strong&gt;: REPL, error-reporting, benchmarking, IR visualization — all included.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  🛠️ Getting Started
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Zig (version 0.15.2 or later) &lt;/li&gt;
&lt;li&gt;(Optional) LLVM 20 for native backend
&lt;/li&gt;
&lt;li&gt;(Optional) GCC or Clang for C code generation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Build from source
&lt;/h3&gt;

&lt;p&gt;You can follow the setup on the &lt;code&gt;README.md&lt;/code&gt; or below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/OwenBellowen/elba.git
&lt;span class="nb"&gt;cd &lt;/span&gt;elba
zig build
./zig-out/bin/elba &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Quick Test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./zig-out/bin/elba examples/hello_world.elba
./zig-out/bin/elba repl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full documentation and more examples live in the &lt;code&gt;examples/&lt;/code&gt; directory and the repo’s docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Example code snippet
&lt;/h2&gt;

&lt;p&gt;Here’s a small example showing Elba’s generics + optional types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// examples/generic_example.elba&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt;&lt;span class="nf"&gt;.new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.second&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;maybeNum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;maybeNil&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i64&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maybeNum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maybeNil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"x = {x}, y = {y}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Pair&lt;/span&gt;&lt;span class="nf"&gt;.new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;p2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="nf"&gt;.swap&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"swapped: {p2.first}, {p2.second}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>zig</category>
      <category>opensource</category>
      <category>git</category>
    </item>
  </channel>
</rss>
