<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Learning-Zig on despatches</title><link>https://icle.es/tags/learning-zig/</link><description>Recent content in Learning-Zig on despatches</description><generator>Hugo</generator><language>en</language><lastBuildDate>Thu, 18 Sep 2025 10:37:25 +0100</lastBuildDate><atom:link href="https://icle.es/tags/learning-zig/index.xml" rel="self" type="application/rss+xml"/><item><title>Auto reload WASM with zig+lume</title><link>https://icle.es/2025/09/16/auto-reload-wasm-with-zig-lume/</link><pubDate>Tue, 16 Sep 2025 15:56:42 +0100</pubDate><guid>https://icle.es/2025/09/16/auto-reload-wasm-with-zig-lume/</guid><description>&lt;p>I’ve been taking some time off to rest and recover from health issues that made
it hard to focus. To ease back in, I’ve started a small project:
&lt;a href="https://icle.es/excursions/shine.md">shine&lt;/a>&lt;/p>
&lt;p>The project would do well to be multiplatform - mobile and web. The obvious
choice was &lt;a href="https://icle.es/tags/flutter">flutter&lt;/a> and I have enjoyed working with it before.&lt;/p>
&lt;p>However, as I&amp;rsquo;m currently in love with &lt;a href="https://icle.es/tags/zig">zig&lt;/a>, I wanted to work with
that instead.&lt;/p>
&lt;h2 id="libraries">Libraries&lt;/h2>
&lt;h3 id="graphics">Graphics&lt;/h3>
&lt;p>I&amp;rsquo;ve been playing with &lt;a href="https://icle.es/tags/raylib">raylib&lt;/a> and that was my initial instinct.
However, raylib
&lt;a href="https://github.com/raysan5/raylib/discussions/2681">does not support iOs&lt;/a> and
&lt;a href="https://github.com/raysan5/raylib/discussions/3626">has issues with wasm&lt;/a>&lt;/p></description><content:encoded><![CDATA[<p>I’ve been taking some time off to rest and recover from health issues that made
it hard to focus. To ease back in, I’ve started a small project:
<a href="https://icle.es/excursions/shine.md">shine</a></p>
<p>The project would do well to be multiplatform - mobile and web. The obvious
choice was <a href="https://icle.es/tags/flutter">flutter</a> and I have enjoyed working with it before.</p>
<p>However, as I&rsquo;m currently in love with <a href="https://icle.es/tags/zig">zig</a>, I wanted to work with
that instead.</p>
<h2 id="libraries">Libraries</h2>
<h3 id="graphics">Graphics</h3>
<p>I&rsquo;ve been playing with <a href="https://icle.es/tags/raylib">raylib</a> and that was my initial instinct.
However, raylib
<a href="https://github.com/raysan5/raylib/discussions/2681">does not support iOs</a> and
<a href="https://github.com/raysan5/raylib/discussions/3626">has issues with wasm</a></p>
<p>I considered a few options, including</p>
<ul>
<li><a href="https://www.libsdl.org/">sdl</a>, which looked great but was perhaps a little
too low level for me.</li>
<li><a href="https://github.com/Jack-Ji/jok">jok</a> - does not support mobile and possibly
has a little more than I needed.</li>
</ul>
<p>In the end, I decided to go with <a href="https://github.com/floooh/sokol">sokol</a> and
<a href="https://github.com/floooh/sokol-zig">sokol-zig</a>.</p>
<p>While a little more lower level than raylib, it has:</p>
<ul>
<li>a modern clean api</li>
<li>first class mobile support</li>
<li>first class wasm support</li>
</ul>
<h3 id="ui">UI</h3>
<p>I&rsquo;ve been working with <a href="https://icle.es/tags/dvui">dvui</a> a lot recently. Unfortunately, it
doesn&rsquo;t support sokol. <a href="https://github.com/SpexGuy/Zig-ImGui">imgui</a> is a better
option.</p>
<p>There is even a
<a href="https://github.com/floooh/sokol-zig-imgui-sample">template project that I could start from</a>.</p>
<h2 id="wasm-first">WASM first</h2>
<p>To keep things straightforward, I decided to start with wasm. If I make the site
mobile friendly, I could see how it goes and see if it needs a mobile version.</p>
<p>I will need some shared data storage and have been considering
<a href="https://supabase.com/">supabase</a>, which has <a href="https://icle.es/tags/javascript">javascript</a>
libs. By using <a href="https://icle.es/tags/wasm">wasm</a>, I can effectively shim in js functions to
handle that instead of having to write bare rest calls from zig.</p>
<h3 id="structuring-the-project">Structuring the project</h3>
<p>Is this a zig project with a web component, vice versa or indeed two independent
parts that work together.</p>
<p>I did a fair amount of web searching to see if there was some guidance I could I
find for a good way to structure a relatively straightforward zig+js project.</p>
<p>I could not find one. In the end, I decided to keep it fairly straightforward.</p>
```
- shine/
  - src/ # zig code
  - web/ # all the web stuff
```
<h3 id="frontend">Frontend</h3>
<p>After a bit of research, and realising that I will probably need a little bit of
supporting content around <a href="https://icle.es/excursions/shine.md">shine</a>, I decided to go
with <a href="https://lume.land/">lume</a></p>
<p>I used the <a href="https://github.com/lumeland/theme-simple-blog">simple-blog theme</a> as
a template to start from. I could have just pulled the template in but I wanted
a custom homepage.</p>
<p>When I tried to add an <code>index.md</code>, it complained about two files wanting to
write <code>index.html</code>. From what I could find, the easiest way to override the
homepage was to just pick up the theme and edit it - which was easy enough.</p>
<h3 id="wasm--frontend">WASM =&gt; frontend</h3>
<p>I didn&rsquo;t want to copy over the wasm and the js file every time, so I added a
couple of steps to <code>build.zig</code> right after the <code>link_step</code> (also included below)</p>
```zig
// build.zig
// create a build step which invokes the Emscripten linker
const link_step = try sokol.emLinkStep(b, .{
    .lib_main = shine,
    .target = opts.mod_main.resolved_target.?,
    .optimize = opts.mod_main.optimize.?,
    .emsdk = dep_emsdk,
    .use_webgl2 = true,
    .use_emmalloc = true,
    .use_filesystem = false,
    .shell_file_path = opts.dep_sokol.path("src/sokol/web/shell.html"),
});
// attach to default target
b.getInstallStep().dependOn(&link_step.step);

// Copy shine.js from default emscripten output
const js_install = b.addInstallFileWithDir(
    b.path("zig-out/web/shine.js"),
    .{ .custom = "../web/src/static/shine" },
    "shine.js",
);
js_install.step.dependOn(&link_step.step);
b.getInstallStep().dependOn(&js_install.step);

// Copy shine.wasm from default emscripten output
const wasm_install = b.addInstallFileWithDir(
    b.path("zig-out/web/shine.wasm"),
    .{ .custom = "../web/src/static/shine" },
    "shine.wasm",
);
wasm_install.step.dependOn(&link_step.step);
```
<p>These steps will copy across the wasm and the js file across to <code>static/shine</code>.
I wanted to put the js in <code>src/js</code> and the wasm in the static dir. However, the
js file expects the wasm in the same dir. <del>I tried overriding <code>locateFile</code> but
it didn&rsquo;t
work.</del>(<a href="https://icle.es/lume/wasm.md">you can use a different location by overriding <code>locateFile</code></a>)</p>
```html
<!-- index.vto -->
<script>
  window.Module = {
    locateFile: (path, prefix) => {
      if (path.endsWith(".wasm")) {
        return "/static/shine/shine.wasm";
      }
      return prefix + path;
    },
  };
</script>
<script src="/js/shine.js"></script>
```
<p>I was able to get lume to process the javascript file by <code>add</code>ing it.</p>
```javascript
// _config.ts
site.add("static/shine/shine.js");
```
<h2 id="conclusion">Conclusion</h2>
<p>With all of these set up, I was able to run:</p>
```bash
zig build -Dtarget=wasm32-emscripten --watch
```
```

```
<p>in one window. This command will rebuild wasm and provide it to lume whenever
the zig code changes.</p>
```bash
deno task serve
```
<p>Running this in another window will mean that lume will rebuild on any changes,
including a new wasm file and redeploy. The redeploy will trigger an auto-reload
of the page as well if I have it in a browser.</p>
<p>I now effectively have automated reload with changes if I make changes in either
zig or the frontend.</p>
<p>I don&rsquo;t have <em>hot</em> reload - but this is pretty good for now.</p>
]]></content:encoded></item><item><title>init &amp; deinit in Zig</title><link>https://icle.es/2025/04/27/init-deinit-in-zig/</link><pubDate>Sun, 27 Apr 2025 17:01:57 +0100</pubDate><guid>https://icle.es/2025/04/27/init-deinit-in-zig/</guid><description>&lt;p>When I was ten, my grandmother passed away. As was custom where we lived, my
family moved into her house - a full household with uncles and aunts. I stayed
there for about nine months.&lt;/p>
&lt;p>My youngest uncle was a Computing Studies teacher at a local college. He also
taught private classes at home. I couldn’t get enough.&lt;/p>
&lt;p>I don’t know what most ten-year-olds dream about, but my dream was to learn C. I
saved ₹300 - a lot of money in 1994 - to buy a book called &lt;em>Encyclopedia C&lt;/em>. I
read it cover to cover, understood maybe 10% of it, and reread it years later to
pick up more.&lt;/p>
&lt;p>But I never actually programmed in C.&lt;/p></description><content:encoded><![CDATA[<p>When I was ten, my grandmother passed away. As was custom where we lived, my
family moved into her house - a full household with uncles and aunts. I stayed
there for about nine months.</p>
<p>My youngest uncle was a Computing Studies teacher at a local college. He also
taught private classes at home. I couldn’t get enough.</p>
<p>I don’t know what most ten-year-olds dream about, but my dream was to learn C. I
saved ₹300 - a lot of money in 1994 - to buy a book called <em>Encyclopedia C</em>. I
read it cover to cover, understood maybe 10% of it, and reread it years later to
pick up more.</p>
<p>But I never actually programmed in C.</p>
<h2 id="the-long-detour">The Long Detour</h2>
<p>Life took me through a range of other languages instead: Prolog (strangely, what
my school machines had), Visual Basic, ASP, PHP, Java, Python, JavaScript, Go,
Rust. I tinkered with C++ when messing with game engines, but never quite got
around to C.</p>
<p>Some of the early fears carried through - memory management was intimidating:
<code>malloc</code>, <code>free</code>, and in C++, <code>new</code> and <code>delete</code>.</p>
<p>Over time, I began to overcome the fear of systems languages - first through
Java, then Go. But I never revisited C, and I never quite got over the fear of
manual memory management.</p>
<p>In hindsight, these concepts weren’t really designed for a ten-year-old to
grasp. It makes sense that they felt out of reach.</p>
<h2 id="allocator-confusion">Allocator Confusion</h2>
<p>Zig had me curious for a while, and some recent health issues gave me the space
to explore it. I’ve been building a small game in Zig, and it’s been feeding
that original desire to learn C - just with a bit more clarity.</p>
<p>I was still intimidated by memory allocation though, and went as far as I could
without using an allocator.</p>
<p>Eventually, I had to use one. I understood the convention of <code>init</code> and
<code>deinit</code>, and the idea of allocators in general.</p>
<p>But I was confused about how <code>deinit</code> worked in the context of <code>ArenaAllocator</code>.</p>
<blockquote>
<p>A little learning is a dangerous thing</p>
<p>&ndash; Alexander Pope</p></blockquote>
<p>If the arena frees memory for you, wouldn’t calling <code>deinit</code> on individual
objects inside it risk double-freeing?</p>
<p>If I skip calling <code>deinit</code> on a struct that normally needs it, will I miss other
cleanup tasks?</p>
<p>And does this mean the arena allocator isn’t a true drop-in replacement if I
have to skip <code>deinit</code>?</p>
<p>At the time, the answer wasn’t clear - and I couldn’t find documentation that
resolved it.</p>
<h2 id="clarity">Clarity</h2>
<p>Thankfully, the
<a href="https://ziggit.dev/t/deinit-and-arena-allocator/9856">super friendly folk at Ziggit</a>
helped clarify things.</p>
<h3 id="arenaallocator-handles-it"><code>ArenaAllocator</code> handles it</h3>
<p><code>ArenaAllocator</code> <em>is</em> a drop-in replacement for other allocators. If you
<code>deinit</code> objects using memory from the arena, and those objects try to free that
memory, the operation is effectively (though not exactly) a no-op. There’s no
risk of double-free.</p>
<blockquote>
<p>It’s always safe to free / destroy memory from an arena, as long as you treat
it as freed of course. But it won’t actually be released until the arena is
deinit’ed.</p>
<p>&ndash; <a href="https://ziggit.dev/u/mnemnion/summary">mnemnion</a></p></blockquote>
<p>Even if some memory is freed manually before the arena is cleared, it’s handled
safely.</p>
<p>I was overthinking it.</p>
<h3 id="deinit-should-still-be-called"><code>deinit</code> should still be called</h3>
<p><code>deinit</code> exists for cleanup logic - not just memory. It should always be called
where appropriate, regardless of the allocator. That part doesn’t change.</p>
<h3 id="further-learning">Further learning</h3>
<p>Zig also encourages a light touch. One of the impacts of this is that the object
itself should not hold on to the allocator in the <code>init</code> and use it in <code>deinit</code>.
It could, but the better way would be to accept the <code>allocator</code> in both the
<code>init</code> and the <code>deinit</code>.</p>
<p>This convention is further reinforced by
<a href="https://ziglang.org/download/0.14.0/release-notes.html#Embracing-Unmanaged-Style-Containers">zig deprecating the <code>managed</code> variants of collections</a></p>
<h2 id="thanks">Thanks</h2>
<p>In many ways, this was about cleaning up more than just memory.</p>
<p>Special thanks to the helpful folks at <a href="https://ziggit.dev/">ziggit.dev</a>.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://ziggit.dev/t/deinit-and-arena-allocator/9856">Full discussion on ziggit.dev</a></li>
<li><a href="https://github.com/ziglang/zig/blob/d92649da80a526f2e2b2f220c05b81becf4fa627/lib/std/heap/arena_allocator.zig#L253-L267">Implementation of <code>ArenaAllocator</code></a></li>
</ul>]]></content:encoded></item></channel></rss>