<?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>DEV Community: Natan Guzinski</title>
    <description>The latest articles on DEV Community by Natan Guzinski (@natan_guzinski_120c49e589).</description>
    <link>https://dev.to/natan_guzinski_120c49e589</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4006811%2F16b076b2-a174-47af-9a35-1395ce2eaf4f.png</url>
      <title>DEV Community: Natan Guzinski</title>
      <link>https://dev.to/natan_guzinski_120c49e589</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/natan_guzinski_120c49e589"/>
    <language>en</language>
    <item>
      <title>Building My Own Programming Language From Scratch as my First C Project, No Tutorials, No Shortcuts, No Mercy</title>
      <dc:creator>Natan Guzinski</dc:creator>
      <pubDate>Fri, 18 Sep 2026 19:59:06 +0000</pubDate>
      <link>https://dev.to/natan_guzinski_120c49e589/building-my-own-programming-language-from-scratch-as-my-first-c-project-no-tutorials-no-4e58</link>
      <guid>https://dev.to/natan_guzinski_120c49e589/building-my-own-programming-language-from-scratch-as-my-first-c-project-no-tutorials-no-4e58</guid>
      <description>&lt;p&gt;Three months ago I had never written a single line of C. Today I have a working statically typed programming language with its own bytecode compiler, its own virtual machine, and its own hand rolled garbage collector, and not one line of it comes from a library, a framework, or someone else's runtime. Everything from the scanner that reads your source code to the memory manager that cleans up after your program runs was built by me, from nothing.&lt;/p&gt;

&lt;p&gt;Meet Oli-Nat.&lt;/p&gt;

&lt;p&gt;What Even Is This&lt;/p&gt;

&lt;p&gt;Oli-Nat is a full programming language pipeline written entirely in C. Source code goes in one end, and it comes out the other as executable behavior, with every single stage of that journey hand built along the way. Here's what that pipeline actually looks like.&lt;/p&gt;

&lt;p&gt;Source code first passes through a lazy, token at a time scanner that recognizes keywords through a trie style switch statement rather than a slow string comparison chain. From there it hits a two pass Pratt parser, where the first pass silently scans ahead to register every function and class signature in the program, so that by the time the second pass runs the actual compiler, mutual recursion and forward references just work with zero extra effort from the programmer. That second pass builds a full abstract syntax tree while simultaneously running a static type checker that rejects invalid programs before they ever get the chance to run. Once a program passes that gauntlet, it gets compiled into custom bytecode and handed off to a stack based virtual machine that executes it instruction by instruction, closures, classes, inheritance, and all.&lt;/p&gt;

&lt;p&gt;And underneath all of that sits a tri color mark and sweep garbage collector that I designed and implemented myself, tracing live objects from the value stack, the call frame stack, open upvalues, and the global variable table, so memory gets reclaimed automatically without ever leaking or crashing your program out from under you.&lt;/p&gt;

&lt;p&gt;Why Would Anyone Do This to Themselves&lt;/p&gt;

&lt;p&gt;Because reading about how compilers work and actually building one are two completely different experiences. You can read a hundred articles explaining what a garbage collector does, and none of them will teach you what I learned the first time my own GC collected an object that was still technically reachable and I had to figure out exactly which root I forgot to trace. That kind of lesson only comes from building the real thing and watching it break in your face.&lt;/p&gt;

&lt;p&gt;This started as a toy project, something small just to prove to myself I could get a basic interpreter working at all. It did not stay small for long.&lt;/p&gt;

&lt;p&gt;A Taste of the Syntax&lt;/p&gt;

&lt;h1&gt;
  
  
  pullf io
&lt;/h1&gt;

&lt;p&gt;class Player&lt;br&gt;
{&lt;br&gt;
    make int health = 100;&lt;br&gt;
    make string name = "hero";&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make empty takeDamage(int amount)
{
    health = health - amount;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;}&lt;/p&gt;

&lt;p&gt;make Player p = Player();&lt;br&gt;
p.health = p.health - 10;&lt;br&gt;
println(p.health);&lt;/p&gt;

&lt;p&gt;Static types, classes with real inheritance, closures with upvalue capture, compound assignment operators, arrays, and a small standard library brought in through pullf imports for io, math, time, file access, and string manipulation. All of it running on a virtual machine I wrote from the ground up.&lt;/p&gt;

&lt;p&gt;The Part That Actually Kept Me Up At Night&lt;/p&gt;

&lt;p&gt;Skipping runtime type checks entirely was the single riskiest design decision in the whole project. Since the static type checker is supposed to catch every invalid type combination before a program ever runs, the virtual machine itself does zero runtime type guarding. The IS_INT and IS_STRING checks scattered through the VM exist purely to pick a dispatch path, not to catch a mistake the checker let through. That means the runtime stays lean and fast, but it also means the entire safety of the language rests on the checker being airtight, with absolutely no safety net underneath it. High risk, high reward, and still an open question I would love feedback on.&lt;/p&gt;

&lt;p&gt;See It For Yourself&lt;/p&gt;

&lt;p&gt;The full source, the opcode reference, the architecture writeup, and the design decision notes are all sitting in the repository right now: &lt;a href="https://github.com/NateTheGrappler/OliNat-Programming-Language" rel="noopener noreferrer"&gt;https://github.com/NateTheGrappler/OliNat-Programming-Language&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It builds clean on both Linux and Windows, verified by a continuous integration pipeline running on every single push, because a project that only claims to be cross platform is worth a lot less than one that proves it on every commit.&lt;/p&gt;

&lt;p&gt;What's Next&lt;/p&gt;

&lt;p&gt;Native support for dynamic arrays and hashmaps, the ability to link programs across multiple source files, and possibly a graphics library down the line. This project is not finished, and it is not supposed to be. It is going to keep growing as long as I keep learning from it.&lt;/p&gt;

&lt;p&gt;If you have ever wanted to understand what actually happens between typing source code and watching a program run, or if you have opinions on type systems, garbage collection, or bytecode VM design, I would genuinely love to hear from you in the comments.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>career</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Built a Statically Typed Bytecode VM Language in C — Here's What I Learned</title>
      <dc:creator>Natan Guzinski</dc:creator>
      <pubDate>Sun, 28 Jun 2026 17:40:16 +0000</pubDate>
      <link>https://dev.to/natan_guzinski_120c49e589/i-built-a-statically-typed-bytecode-vm-language-in-c-heres-what-i-learned-1e7e</link>
      <guid>https://dev.to/natan_guzinski_120c49e589/i-built-a-statically-typed-bytecode-vm-language-in-c-heres-what-i-learned-1e7e</guid>
      <description>&lt;p&gt;A couple months ago I finished reading &lt;em&gt;Crafting Interpreters&lt;/em&gt; and got the itch to go further. Instead of just following along with clox, I decided to design my own language from scratch. The result is &lt;strong&gt;Oli-Nat&lt;/strong&gt; — a statically typed, bytecode-compiled language with its own GC, type checker, class system, and standard library, all written in C.&lt;/p&gt;

&lt;p&gt;This post isn't a tutorial. It's about three specific design problems I ran into and how I solved them, because I think they're interesting and I haven't seen them written up clearly anywhere.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pipeline
&lt;/h2&gt;

&lt;p&gt;Before diving in, here's the full pipeline so the rest makes sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source → scanner → Pratt parser → AST → type checker → two-pass bytecode compiler → stack-based VM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick taste of what the language looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hero"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="nf"&gt;takeDamage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getHealth&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;health&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;takeDamage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getHealth&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 70&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Variables and functions are declared with &lt;code&gt;make&lt;/code&gt;. Stdlib is imported with &lt;code&gt;#pullf&lt;/code&gt;. Nothing groundbreaking syntactically, but the internals were a different story.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 1: The Circular Dependency Between the Hashmap and Object System
&lt;/h2&gt;

&lt;p&gt;My object system lives in &lt;code&gt;object.h&lt;/code&gt;. My hashmap lives in &lt;code&gt;hashmap.h&lt;/code&gt;. The problem: &lt;code&gt;ObjClass&lt;/code&gt; needs a &lt;code&gt;Hashmap&lt;/code&gt; to store its methods, and &lt;code&gt;Hashmap&lt;/code&gt; needs &lt;code&gt;ObjString*&lt;/code&gt; as a key type. Classic circular dependency.&lt;/p&gt;

&lt;p&gt;The naive solution — just include one from the other — doesn't work because you end up with a cycle the preprocessor can't resolve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My solution: a types-only header.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I created &lt;code&gt;hashmap_types.h&lt;/code&gt; that contains just the struct definitions for &lt;code&gt;Bucket&lt;/code&gt; and &lt;code&gt;Hashmap&lt;/code&gt;, with a forward declaration of &lt;code&gt;ObjString&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// hashmap_types.h&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;ObjString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// forward declaration only&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&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;ObjString&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="n"&gt;Hashmap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;object.h&lt;/code&gt; includes &lt;code&gt;hashmap_types.h&lt;/code&gt; — gets the &lt;code&gt;Hashmap&lt;/code&gt; struct without pulling in hashmap implementation&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hashmap.h&lt;/code&gt; includes both &lt;code&gt;hashmap_types.h&lt;/code&gt; and &lt;code&gt;object.h&lt;/code&gt; — gets everything it needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No cycles. The key insight is separating &lt;em&gt;struct layout&lt;/em&gt; from &lt;em&gt;function declarations&lt;/em&gt;. You only need the layout to embed a &lt;code&gt;Hashmap&lt;/code&gt; inside &lt;code&gt;ObjClass&lt;/code&gt;; you only need the functions when you're actually calling them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 2: Two-Pass Compilation for Forward References
&lt;/h2&gt;

&lt;p&gt;In most simple interpreters, you can't call a function before you declare it. I wanted Oli-Nat to support forward references — call a function defined later in the file, or have two classes reference each other — without requiring explicit forward declarations from the user.&lt;/p&gt;

&lt;p&gt;The solution is a two-pass compiler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First pass&lt;/strong&gt; (&lt;code&gt;declareFunction&lt;/code&gt;): scan the entire source for function, class, field, and method declarations. Don't parse bodies. Just populate the type checker's symbol table with signatures:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// First pass sees this:&lt;/span&gt;
&lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&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="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// And records: "add" → returns int, takes (int, int)&lt;/span&gt;
&lt;span class="c1"&gt;// Body is skipped entirely&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Second pass&lt;/strong&gt;: full parse, type check, and bytecode emission. By this point the type checker already knows about every function and class in the file, so forward calls type-check correctly and the compiler can emit the right call instructions.&lt;/p&gt;

&lt;p&gt;The tricky part is class declarations. The first pass needs to record not just the class name but all its field types and method signatures, so that the type checker can validate &lt;code&gt;instance.field&lt;/code&gt; and &lt;code&gt;instance.method(...)&lt;/code&gt; expressions in the second pass. That means the first pass has to parse class bodies partially — just enough to extract the metadata, without emitting any bytecode.&lt;/p&gt;

&lt;p&gt;The payoff is that the user never thinks about declaration order. Functions and classes can be used anywhere in the file.&lt;/p&gt;




&lt;h2&gt;
  
  
  Problem 3: GC Safepointing Hazards
&lt;/h2&gt;

&lt;p&gt;This one bit me multiple times and is easy to miss if you're not thinking about it.&lt;/p&gt;

&lt;p&gt;The GC runs during allocation. If you allocate something and it triggers a collection, any object you were holding in a local C variable but hadn't yet anchored to the VM's roots (stack, globals, etc.) will be swept as garbage — even though you're actively using it.&lt;/p&gt;

&lt;p&gt;The classic bad pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;ObjString&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// allocation #1&lt;/span&gt;
&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;makeInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// allocation #2 — might trigger GC&lt;/span&gt;
                                               &lt;span class="c1"&gt;// key is now potentially freed!&lt;/span&gt;
&lt;span class="n"&gt;mapSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fix is to push temporaries onto the VM's value stack before any allocation that might trigger GC, then pop after:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;ObjString&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;copyString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OBJECT_VAL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;    &lt;span class="c1"&gt;// anchor it as a GC root&lt;/span&gt;

&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;makeInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;someClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// GC safe now — key is on the stack&lt;/span&gt;

&lt;span class="n"&gt;mapSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                       &lt;span class="c1"&gt;// done with it&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mental model I use now: &lt;em&gt;any call that allocates is a potential safepoint&lt;/em&gt;. Before crossing a safepoint, anchor everything you care about.&lt;/p&gt;

&lt;p&gt;This shows up in subtle places — string interning during compilation, building the methods hashmap while the class object is being constructed, initializing field default values. Every time I added a new feature that involved multiple allocations in sequence, I had to audit the ordering.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The language is working and I'm happy with where it is. The next big things on the roadmap are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Constructors with parameters&lt;/strong&gt; — right now &lt;code&gt;Player()&lt;/code&gt; creates an instance with default field values; I want &lt;code&gt;Player("Alice", 50)&lt;/code&gt; to work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inheritance&lt;/strong&gt; — &lt;code&gt;ObjClass&lt;/code&gt; already has a &lt;code&gt;superclass&lt;/code&gt; pointer reserved for this&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A 2D game library&lt;/strong&gt; — the whole reason I wanted a class system in the first place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full source is on GitHub: &lt;a href="https://github.com/NateTheGrappler/OliNat-Programming-Language" rel="noopener noreferrer"&gt;https://github.com/NateTheGrappler/OliNat-Programming-Language&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer questions about any of the implementation details in the comments.&lt;/p&gt;

</description>
      <category>c</category>
      <category>computerscience</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
