ZVM Crosses 600 stars

Tristan Isham
13 Mar 2025, 4:21 pm · edited
Star History Chart

Last week ZVM crossed an important milestone: 600 stars on GitHub! I never thought when I first started working on ZVM that it would become an essential tool for so many Zig developers. I still don’t really know how most people use it. I don’t have any analytics or automatic error reporting built into the program. The only feedback I get is from issues created on GitHub and unsolicited feedback people send me on Twitter. The fact that the feedback has been so kind is incredible.

I really care about ZVM being a reliable tool. I hate when you just want to get something done, and out of nowhere your flow is broken. Or when you have to relearn your favorite tool because of an update. I can’t claim that ZVM has always been 100% reliable. I’ve renamed some commands and downgraded others. Depending on a third party host for downloads sometimes means that Zig’s maintainers introduce bugs or temporarily break ZVM functionality, but I’ve always tried to maintain a high level of quality. I think the fact that we’ve gotten to more than 600 stars through mostly word of mouth speaks to that. In the coming months I’ll continue to work on ZVM, facilitating open source contributions, adding features where necessary, and working to build out infrastructure that removes our dependency on the Zig CDN. I also want to thank everyone who has taken the time to contribute, use, or ever just view the repository. I appreciate the fact that something I’ve started has had such an impact. I hope to replicate my success with future projects, but for the meantime. I’m just happy to have a little piece of me on your machine making your life a bit easier. Thanks.

Please create an account or sign in to leave a comment.

Success Is Self-Defined

Tristan Isham
1 Mar 2025, 8:19 pm · edited

Today I’m traveling to Lisbon, Portugal, for a vacation with my fiancé and her brother. The travel has been going great so far. Usually, traveling can be a bit stressful or chaotic, but today has been as smooth as butter.

I haven’t posted three times this week, but I have written three different posts. This one, my last one about the neatness of reflection in stack-based dynamic languages and PHP, and another about Laravel deleted after a day. It wasn’t work I was proud of.

I’m considering this week a success. By writing more, I’m stretching my writing muscles and building a habit. Once I have enough momentum, I can dive back into the bigger posts I’m excited to write.

Success is self-defined. If you’re creative, the purest form of success is enjoying creating for yourself and not needing to please others or make money. Not to say doing that isn’t nice, but to truly only need to create because you want to is a mindset freer than the wind. I’ve loved writing here these past two weeks because I’m no longer writing for other people. I’m writing for myself, and in these past two weeks, I’ve written more than I have in the past two years. If that isn’t success, I don’t know the definition.

I’ll be writing over this trip about our travels and my experiences. I’m excited to attempt some travel writing. It’s been a few years since I last reflected on a journey.

Please create an account or sign in to leave a comment.

Laravel is a special web framework. A modern, full toolbox packed with goodies like user account management, web sockets, concurrency, an ORM, and a variety of frontends, including a bespoke tempting language and JavaScript framework for PHP.

"Isn’t PHP notoriously 90s?", I hear you ask. Though it’s true PHP originally rocked with Cold Fusion and ASP, the language has continued to innovate and modernize with each release. Especially in its design department. Early PHP was a mess of global functions with no clear naming conventions. In the past decade, PHP has adopted numerous standards that have streamlined how the language looks and performs. Laravel has built on this work and PHP’s exceptional runtime reflection and customizability to rework basic language functionality, such as dependency injection, to create a much cleaner dependency system than vanilla PHP.

Here’s an example of using a Composer dependency from within a nested file. It could be a route, or just some backend code, but the point is that it’s unclean, and required the developer to be aware of the file’s position relative to the vendor directory. This is a huge pain on large projects, especially if you’re using vanilla PHP and file-based routing.

require_once __DIR__ . "/../../vendor/autoload.php";

use SomeNamespace\CoolClass;

$c = new CoolClass();

Compare this to Laravel, which, under the hood, has supplied it’s own dependency injection container, and that file becomes:

use SomeNamespace\CoolClass;

$c = new CoolClass();

It’s all based on namespaces and doesn’t require relative knowledge of file positions. The only requirement is that you have to follow PSR naming conventions for your files and classes. I don't know enough about how dependency injection works in PHP to comment on this further, but frankly it solves one of my biggest gripes with the language.

My favorite aspect of PHP is how customizable it is. You can really make it do anything. From how it loads dependencies, to how protect/private methods work within a class, all because of its incredible reflection capabilities. Reflection, in this context, is a programming language's ability to analyze itself. It's what enables Go to serialize structs into JSON or other formats from struct tags.

type Example struct {
	Name string `json:"name"`
	Age  int    `json:"age,omitempty"`
}

How it works is dependent on the language, but in my experience building Fan and now Osprey, two stack-based dynamic languages, I'd implement it by having the virtual machine work directly with values already on the call stack. Osprey, pictured below, is currently in very early alpha. All of the variables are based around a union type called Value that stores them as either their natural type bool, f64, and null, or as an Object responsible for it's own allocated space that can be cast to store more complex types like strings.

var breakfast = "beignets";

var beverage = "cafe au lait";

breakfast = "beignets with " + beverage;

  

print breakfast;

I plan to change the keywords and statements in a later iteration of Osprey, but the context remains. That little script to print a new string results in the following call stack.

$ zig build -Dtrace run -- run .\lib\var.test.fan

== code ==
   0    0    1 Constant            1 'beignets'
   2    2    | DefineGlobal        0 'breakfast'
   4    4    2 Constant            3 'cafe au lait'
   6    6    | DefineGlobal        2 'beverage'
   8    8    3 Constant            5 'beignets with '
  10   10    | GetGlobal           6 'beverage'
  12   12    | Add
  13   13    | SetGlobal           4 'breakfast'
  15   15    | Pop
  16   16    5 GetGlobal           7 'breakfast'
  18   18    | Print
  19   19    | Return

   0    1 Constant            1 'beignets'
            [ beignets ]
   2    | DefineGlobal        0 'breakfast'

   4    2 Constant            3 'cafe au lait'
            [ cafe au lait ]
   6    | DefineGlobal        2 'beverage'

   8    3 Constant            5 'beignets with '
            [ beignets with  ]
  10    | GetGlobal           6 'beverage'
            [ beignets with  ][ cafe au lait ]
  12    | Add
            [ beignets with cafe au lait ]
  13    | SetGlobal           4 'breakfast'
            [ beignets with cafe au lait ]
  15    | Pop

  16    5 GetGlobal           7 'breakfast'
            [ beignets with cafe au lait ]
  18    | Print
beignets with cafe au lait

  19    | Return

The fourth column contains Osprey's operating codes. These are bytes that represent actions or requests for the VM. Even defining something as simple as a global variable requires multiple codes. You first have to add the actual string to your constants table, then link it to your global variable. That's two separate systems working together to create a simple string. I've never implemented reflection, but I'd imagine this is where the magic happens. The next step for Osprey is a byte-code compiler. Implementing that may change my opinion on this whole matter.

Programming languages are incredibly cool. To create a piece of software that can do anything just by reading text is like creating a whole universe that works to your beat. I have dreams for Osprey, or whatever language I end up writing, where writing something portable, performant, and powerful is as simple as knowing how to code.

Please create an account or sign in to leave a comment.

A Domain is A Home

Tristan Isham
22 Feb 2025, 10:44 pm · edited

I first purchased tristanisham.com nearly ten years ago. In 2016, I was in highschool. A member of the marching band and tech club, the domain was a vehicle for a SquareSpace site self-promoting my limited work making videos for our high school media class. I’ve always been a bit self-promotional. I’ve never sold anything I can’t do, but even I’ll admit I embellished my experience then.

I’ve loved the web for as long as I remember. The first program I wrote was a BAT game inspired by the copy of Zork included with the original Call of Duty: Black Ops on the Xbox 360. From there, I quickly hopped over to websites, creating my first blog nextgamewins.com where I wrote about gaming through the GoDaddy WYSIWYG editor. Before that, back in middle school I had a blog on Blogger called Life Changing Cheese. Unfortunately, I changed the domain to one of those free .co.vu TLDs and now I can no longer access the original site, but my point stands. Since I was a little kid, I’ve always loved creating on the internet.
What people born outside of the late 90’s fail to understand is that we were the only generation to grow up at the right time for the internet. We have a natural proclivity towards it, but had enough time to mature without it. We were the first generation to grow up with smartphones, while still being able to appreciate life without them. I remember where I was when the App Store launched. I saw the rise of smartphones and social media. I was there when tests were on paper and when they transitioned to laptops. I lived through the greatest transformation of society since the mass adoption of electricity with feet in both worlds. No other generation can appreciate that. They were either too early, growing up in the now defunct age of the desktop, or too late, never to know the peace and reward of having to think for yourself on every matter. In that way, I think I am uniquely situated to comment on what it means to own your own name. With this website, I hope to leave a permanent record for anyone to observe, interact with, and experience beyond the control of anyone else. I would like to own my digital identity without falling prey to the manipulative misincentivised platforms that run our lives.

I would like you to make your own website. You should purchase a cheap domain, and find a service that works for you. Hosting your own site is easy too. If you can learn HTML, CSS, and JavaScript, you can find a service like Netlify that’ll host your site for free. Just create something. Draw something; write something; film something; do something. You won’t regret it.

Please create an account or sign in to leave a comment.

This week’s been all about Winter. After a couple weeks respite from snow and bitter cold--we even had a day up into the 50s--Jack Frost came back with a vengeance. The thermometer plunged into the low teens and tens. The wind brought the feels-like down into the negatives. Worst of all, we had three days of Lake Effect Snow.

Lake Effect Snow is a phenomenon here in the Midwest where cool air, usually from Canada, moves across the relatively warm Great Lakes resulting in increased moisture in the lower-bands of the earth's atmosphere. That moisture forms into clouds which can dump 2-3 inches of snow per hour. Here in Northeast Ohio, this snow usually hits the eastern portion of the lakeshore the hardest with counties on the Ohio-Pennsylvania border suffering the most.

Since I live somewhere in the middle of Northeast Ohio, I don’t get the worst of it, but I do get my fair share. My driveway is large, with a light incline narrowly snaking between my house and my neighbor’s. Since I’d rather not hit a house, that means I have to get out there and clear any snow if my fiance or I want to drive anywhere. I’ve been clearing snow most days this week, but after a particularly large snowfall Monday night, Tuesday’s plowing proved to be too mighty for my snowblower. Midway through a stretch of light snow, its auger died.

The next day, my dad came over and he was able to briefly get the auger working again. I remember seeing the blades spinning from my kitchen window thinking I’d wasted his time having him drive out, but after a few minutes of pushing it around, the gearbox imploded.

shattered gearbox

Please create an account or sign in to leave a comment.

My Rules for Blogging

Tristan Isham
20 Feb 2025, 2:08 pm · edited
  1. Take portable notes for everything

    • Need to be searchable
    • Need to be portable
    • Need to be exportable
  2. Minimum of three (3) blog posts a week

    • Writing is a muscle
    • No reposting links
    • Don't worry about always writing like a journalist. Just journal.
    • It's okay not to write if writing feels like a chore
    • Use one website
    • Don't chase trends. Just write for yourself (myself).

Thanks Matt Webb.

Please create an account or sign in to leave a comment.

Single page applications (SPAs) are generally not the first tool I reach for when building a new website. Unless I’m starved for reactivity, I find managing user credentials, securing my API, and shipping a large bundle to the client to process frankly over-stressful and unnecessary. I’d much rather use a server-side multi-page app (MPA) with HTMX or Alpine.JS to achieve dynamic hydration where it counts without having to worry about exposing logic or secrets to the client.

However, recently I started building a realtime multiplayer board game using websockets. I needed a tech stack that could handle regular state changes from the server while updating a dynamic game board. Out of everything I found, Solid JS seemed to be the simplest, most performant framework I could integrate with Go.

Setting up Vite

You can set up a new Solid project easily by running

bunx degit solidjs/templates/ts my-app

Then move 'package.json', 'tsconfig.json', 'vite.config.ts', 'index.html' and 'postcss.config.js' out of your 'my-app' directory into the root of your Go project. This centers your root as the heart of your project and follows Go best practice. Next, modify the index html so the 'script' tag source is accurate to your 'index.tsx'.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <link
      rel="shortcut icon"
      type="image/ico"
      href="/client/assets/favicon.ico"
    />
    <title>My App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>

    <script src="/my-app/index.tsx" type="module"></script>
  </body>
</html>

Finally, update your 'vite.config.ts'’s server.proxy object to support your application’s API route:

proxy: {  
     "/api": {  
       target: "http://localhost:3000",  
       changeOrigin: true,  
     },  
     "/ws": {  
       target: "http://localhost:3000",  
       changeOrigin: true,  
     },  
   },

Now, you can configure your backend to render your app’s development server and static assets depending on your development or production environment.

Using Go Fiber

DEBUG in this example represents any methodology you might use to determine if you're running your app in production.

	if DEBUG {  
		  
		app.Use(func(c *fiber.Ctx) error {  
			// Proxy requests to Vite dev server  
			if c.Path() == "/" || strings.HasPrefix(c.Path(), "/assets/") {  
				return proxy.Do(c, "http://localhost:5173")  
			}  
			return c.Next()  
		})

		app.Get("/*", func(c *fiber.Ctx) error {  
			// Redirect to Vite dev server  
			return c.Redirect("http://localhost:5173")  
		})  
	} else {  
		// Serve built assets in production  
		app.Use("/assets", filesystem.New(filesystem.Config{  
			Root: http.Dir("./dist/assets"),  
		}))  
		app.Get("/*", func(c *fiber.Ctx) error {  
			return c.SendFile("./dist/index.html")  
		})  
	}

Using Gin

if gin.Mode() == gin.DebugMode {  
        // Serve Vite in development  
        router.Use(func(c *gin.Context) {  
            if c.Request.URL.Path == "/" || strings.HasPrefix(c.Request.URL.Path, "/assets/") {  
                proxy := httputil.NewSingleHostReverseProxy(&url.URL{  
                    Scheme: "http",  
                    Host:   "localhost:5173",  
                })  
                proxy.ServeHTTP(c.Writer, c.Request)  
                return  
            }  
            c.Next()  
        })

        // Fallback route should be last  
        router.NoRoute(func(c *gin.Context) {  
            c.Redirect(http.StatusFound, "http://localhost:5173")  
        })  
    } else {  
        router.Use(static.Serve("/assets", static.LocalFile("./dist/assets", false)))  
        router.NoRoute(func(c *gin.Context) {  
            c.File("./dist/index.html")  
        })  
    }

Please create an account or sign in to leave a comment.

AI Won't Replace Writing

Tristan Isham
26 Nov 2024, 6:12 pm · edited

In his most recent essay, Paul Graham, founder of Y-Combinator, misses the forest for the trees in his prediction that writing as a skill will be functionally extinct because of AI. To be specific, Graham thinks that many people won’t be able to write because AI has dissipated almost all pressure to write. And because the gap between being a good writer and not being able to write has disappeared.

I want to presuppose that when he says writing, Graham means communicating effectively and asynchronously through text. Not actually writing by typing keys or scratching pens. I don’t think that skill will ever go away because frankly, using your voice alone to communicate would suck. It is not realistic in any litany of places where it would either be inappropriate, too loud, or impossible to talk.

In his essay, Graham says, “One of the strangest things you learn if you're a writer is how many people have trouble writing. Doctors know how many people have a mole they're worried about; people who are good at setting up computers know how many people aren't; writers know how many people need help writing.”

I’m more than willing to agree with that. When I was in journalism school, I was horrified that even after four years, seniors who had been coached for 1/5th of their lives on how to write could barely string together a succinct essay. I can’t imagine the quality of the average person’s paper today. To these people, writing well was never important, because if it had been, they’d have learned how to do it. They wrote well enough to pass their classes, and well enough to ease their minds. For them, using AI to write is like using spell check and accepting all changes. There was no craft to begin with. Yet, by the very nature of having to communicate with the AI, and that I can’t imagine a world in which not being able to write without using an AI doesn’t get you teased out of the room, I imagine that even these people will retain a poor to okay level of writing skill.

Graham also talks about how “AI has blown this world open. Almost all pressure to write has dissipated. You can have AI [write] for you, both in school and at work.”

In school, if used unethically like when writing a paper, AI scribing is only going to result in more student suffering. No matter how advanced an AI becomes, it will never be able to write an essay by hand in a blue book with a number 2 pencil. I hate to say it, but kids are spoiled by Chromebooks and iPads. If kids are found to be cheating on their essays or on their online tests, there’s nothing stopping teachers from taking a step back from technology on test days and forcing students to write by hand. AI might be the revitalization handwriting needs.

Graham asks, “Isn't it common for skills to disappear when technology makes them obsolete? There aren't many blacksmiths left, and it doesn't seem to be a problem.” Yet only a paragraph later distinguishes writing from other skills by stating, “writing is thinking. In fact there's a kind of thinking that can only be done by writing. You can't make this point better than Leslie Lamport did: If you're thinking without writing, you only think you're thinking.”

People are still taught how to write by hand, and even cursive. The most popular medium for books is still paper, despite e-reader’s many advantages. We don’t operate in a reality where the rational choice is always the one that wins. Instead, emotions often rule our days, and writing is one skill unlike any other--inexplicably tied to our thoughts and feelings. I don’t see a world in which we ever let that skill go.

Please create an account or sign in to leave a comment.

braxton 3 Feb 2025, 4:15 pm

Another change to consider is the style and capabilities that have, and will continue to decline with the influx of AI. There's less self reliance for growth of newer writers who can easily turn to AI to have multiple versions of the works edited and rewritten. Why foster personal growth and knowledge when the option of ease and faster results is available with AI? I anticipate we see writing styles and capabilities decline with the increased use of AI writing tools.

My day starts slowly. A cup of coffee, a quick YouTube video, and I’m off to work. It’s not a long commute to my office in the other room, but by the time I’ve sat down my mind is already buzzing with a long list of tasks. Distractions like unfinished chores leftover from the week and new work for today. I find it hard to lock in on tasks I’m not personally interested in, or to stay focused for long bits of time. I tend to flutter between busywork until I find a single task to focus on, at which point I can stay targeted on that task for hours. I get my work done, but I wish I could still accomplish more.

I scarf down my dinners. Dieting habits aside, I’ve developed a propensity for being a fast eater. My fiancé tells me to slow down, but that never made much sense to me. Why slow down when I can finish it this fast? It never clicked until last night when I was drinking a protein shake. After finishing it in two gulps, she looked at me in loving horror and commented on how I could not have enjoyed that. I was confused. Of course, I enjoyed it. I drank it didn’t I? I thought it tasted great! But on later reflection, I realized what she meant. I hadn’t taken the time to process the drink. Instead of savoring it, remembering its flavor, and enjoying it, I had consumed it. I had missed the broader point of the drink by leaning too hard on what it could do for me functionally—fill me up and taste good.

If you asked me to describe the drink to you, I could say it was chocolaty, but not much more. I can’t remember the texture or viscosity. It is a faded and soon to be forgotten memory because I didn’t take the time to properly catalogue and enjoy it.

I’m going to work on treating more of my life like a chocolate protein shake. To be savored and understood, not to be rushed through. Like with books. I always have trouble remembering the names of characters in books. It doesn’t matter if I’ve just looked from the page. Their names stay down with the ink. Maybe, if I read books a little slower and with more care, I wouldn’t struggle to remember the cast of my stories? Simply, I’m so enamored with the concept of done, that I’ve sacrificed the art of doing.

Please create an account or sign in to leave a comment.

braxton 12 Dec 2024, 1:23 pm

There's beauty in the small things that you come to see with this mindset. Step away from your phone, separate your work and your life, the growth and change you will gain won't be hard to miss. You should check this out: https://improvisedlife.com/2021/10/19/kurt-vonnegut-we-are-here-on-earth-to-fart-around