◀

Blog

  • I guess I kinda get why people hate AI

    Feb 14, 2026

    I’m sitting on a lānai in a hotel in Waikiki beach, writing this article, and wondering if the job I am starting nine days from now will be my last.

    This is a unique situation for me in a few ways—I’ve never been to Hawaii before, I think the five minutes it’s taken me to come up with that opening sentence is the somehow the most time I’ve ever spent on a hotel balcony, and this is the first time I’ve actually followed through on the “I should delay my start date to take a vacation” idea I’ve had every time I’ve switched jobs. There’s one difference, however, that looms larger in my mind. It’s not the “wondering if the new job will be my last” thing. I’ve worked exclusively in startups, and while the primary reason I’ve done so has been because I enjoy the agency and impact you can have at early-stage companies, I’d be lying if the idea of cashing in cheap ISOs into early retirement wasn’t a factor in each job offer I accepted. The difference here is why I’m wondering that. Previously, it was wondering if I would need a job after this one.

    Now, it’s wondering if I’ll be able to acquire a job after this one, or if AI is going to completely take over my profession and ruin my career.

    Read More
  • Writing about Haskell is Hard

    Nov 5, 2021

    If your first thought upon clicking on a blog post entitled “Writing about Haskell is Hard” was “I bet this guy was writing a very different sort of post, got frustrated, and went back to the drawing board,” congradulations, you’re right! Because when I sat down after work and decided to do some blogging about programming, I originally wanted to write an introduction to my new JSON library, jordan. Jordan has a few features that I haven’t seen in other JSON parsers:

    • Jordan directly generates wire-format parsers for your custom types. That is, if you have a data type like:

      data Person 
        = Person 
        { name :: String
        , age :: Int 
        }
      

      And you’re trying to parse this in the obvious way:

      {
        "name": "Bob Smith",
        "age": 55,
        "profession": "writer"
      }
      

      Jordan will not construct any sort of Map<String, JSONValue> in the middle. It also will immediately discard the “profession” key. With a bit of refactoring (which I plan to do soon), it won’t even ever store a string for “writer” in memory. Jordan will instead generate an actual UTF-8 Parser that directly converts from your type to JSON.

    • Jordan directly writes wire-format JSON without any intermediate types, either. You can even write the JSON right to a file handle, which potentially saves on memory consumption in a serious way. Haskell’s default JSON library, aeson, also supports this (and supports it in a way that’s marginally faster than Jordan without compiler flags), but it’s not required for all types, just an option you can (and should) make use of
    • Jordan can generate documentation for your JSON types, using the same definitions as your parsers and serializers. That is, if you write some way to parse or serialize JSON, you can generate OpenAPI types automatically with no intermediate step.
    • Jordan parsers and serializers are in an abstract, user-extendable format. So, if you have some crazy wire protocol for sending JSON, like BSON or whatever, you can probably write a Jordan “interpreter” that will directly serialize to that.

    These features are all, in my opinion, very cool. They’re not only efficient, but they solve the “Documentation about JSON format and actual JSON format are out of sync” problem, which is the bane of my freaking existence on many web-dev projects. I wanted to write a blog post explaining how Jordan works, and how Haskell helped me to write it.

    My first post was a disaster that I discarded. Here’s a second attempt.

    Read More
  • Error Messages in Haskell, and how to Improve them

    May 14, 2020

    I’ve been writing more and more Haskell lately, as part of a side project involving GraphQL. As part of working with the language, I’ve had to work with its compile errors. The Haskell compiler gives you errors that are extremely informative—if you know the language. If you don’t know the language very well, the compiler errors can occasionally be opaque and unhelpful.

    I’ve very much enjoyed using Haskell, and I figure the best way for me to give back to the community is to make this situation a little better. In order to do this, we’re going to take a fun dive into Haskell errors, why they’re confusing, and how they might be improved.

    This is very much not a literate Haskell file, because none of the snippets within will actually compile! You can discuss this post here.

    Read More
  • A Brief History of my Failed Attempt at Making a Video Game

    Nov 13, 2018

    On the internet, it isn’t particularly hard to find technology postmortems. Some of them are from large, venture-funded companies which eventually keeled over and died after the investors ran out of confidence and the bank account ran out of money. Others are from open-source initiatives that failed to find a footing and drifted off into darkness until their creator decided to turn the lights off for good. And others are much more personal, the story of a small, not-well-funded team that couldn’t quite get up to snuff. The term originates in medicine, where it describes a detailed account of all the things that eventually lead to the death of a patient. Such reports aren’t written unless there’s a need to. There’s no knowledge to be gained from an obese man in his late seventies succumbing to heart disease, or a trauma patient simply dying after succumbing to injuries no human can survive. If the cause of death is obvious, a postmortem report is frivolous. All of my previous failures, I believe, fell under this particular category. I’ve never felt a need to write a postmortem for them because it was obvious, even to me, why they did not succeed.

    I graduated college with a Bachelor’s in Computer Science in December of 2017, after studying for five semesters plus two summer classes. Instead of going the typical route and trying to find a job immediately, I decided that I would embark on a project of my own, take another stab at entrepreneurship, and try to pursue a dream I remember having as a child. I was going to make a video game, and a good one at that, and I was going to sell it on steam and turn its moderate success into a fledgling indie studio. Unfortunately, however, I find myself in the morgue, staring down at my game’s corpse and trying to decide if it’s worth the time and effort to investigate exactly how it died.

    In this case I’m not quite sure if I’m even writing a postmortem, or if it’s a sort of obituary. I’ll admit openly that I am partially writing this for emotional closure and not purely as an objective report so that I may discover why and how this project died. Still, I do think there is some value to be gained in organizing my thoughts on the matter. So, without further ado, let us examine my failed attempt at game development, so we can try to pinpoint exactly where things went wrong.

    Read More
  • Dynamic Syntax Highlighting with React.js

    Apr 26, 2018

    Let’s say you’re building a modern web app. You’re using react, you’re set up with webpack code splitting, you render stuff on the server-side, everything is awesome. Even better, your dependencies are really lean-and-mean: you fetch stuff as you go, so the initial bundle is very small!

    You might run into a problem, though, if you need to render user-generated Markdown. You’re already using the excellent react-markdown library, so that’s all working fine, but the recommended way to do syntax highlighting has the rather large problem that you need to manually require the languages you want to use. Worse, they’re all bundled together.

    You don’t want this. You want to be able to deliver no highlighting code, then allow the user to dynamically fetch the required highlighting files, like how the rest of your app works. Ideally, you even want it to render a non-highlighted version first, then switch to the highlighted one when its ready. How might this get done?

    Read More
  • Templates, Index Sequence, and Optimization

    Mar 21, 2018

    Recently, I’ve been working on a 2D game. Full-time, in fact: I recently graduated early, and I figured I might as well take a year and a half to work on this project before getting a “real” job. I initially started creating a game in Unity, however, I quickly realized that I didn’t actually like the engine. I actually disliked it fairly heavily, and it was hurting my productivity. So, naturally, my next thought was to code the game from scratch.

    The natural choice for this was C++. I messed around with making a 2D engine before and enjoyed it, even if I didn’t actually get very far. I took a bit of a different approach this time, intentionally trying to make a game instead of an engine. However, that doesn’t mean that I don’t occasionally encounter engine-dev-related problems. One interesting recent one: optimizing a component of my ECS system.

    Read More
  • Luck and Analysis

    Nov 7, 2017

    Over the last few years, I’ve become progressively more interested in tabletop games. As a result, I’ve been playing more of them—and thus rolling more dice. Now, as with any game of chance, occasionally luck isn’t in my favor and and I’ll consistently do much lower damage than I feel like I should. When you do 5 damage on an attack that averages 16, it feels pretty awful. I, however, wanted to know more. I wanted to know exaclty how unlucky I was getting. Being a programmer, my solution, naturally, was to write some code to do so.

    Read More
  • value_ptr

    Sep 28, 2017

    In today’s blog post, we’re going to discuss the idea of a value_ptr. Basically, the idea is that it’s pointer with value semantics. Why would you want this? Well, polymorphism for one. For another, you could conceivably want to allocate a very large number of some very large objects on the stack (perhaps recursively), and you don’t want to cause an overflow.

    This has been implemented before, but I didn’t actually read the source for that. Instead, I’ll write it myself.

    Read More
  • An alternative way to Memoize in Ruby

    May 8, 2017

    I was screwing around with Ruby Coroutines, and the concept of coroutines in general, when I came across this page. It talks about how you can use coroutines to memoize functions. Ruby has native coroutines. You can guess what happened next.

    Here’s what I came up with:

    class Object
      def self.fiber_memoize(method_name)
        meth = self.instance_method(method_name)
        self.send(:define_method, method_name) do
          f = Fiber.new do |s|
            result = meth.bind(self).call
            loop do
              Fiber.yield(result)
            end
          end
          self.send(:define_singleton_method, method_name) do
            f.resume
          end
          f.resume
        end
      end
    end
    

    This works on an instance-level, which a naive implementation wouldn’t. It also works by re-defining methods on a per-instance basis when you call them, which is just another example of how much Ruby rocks.

    Here’s how to use it:

    class Factorial
      def initialize(num)
        @num = num
      end
    
      def result
        puts "This run is not memoized"
        (1..@num).inject(:*) || 1
      end
    
      fiber_memoize :result
    end
    
    f = Factorial.new(100)
    puts f.result #=> Prints the not memoized message, then the result
    puts f.result #=> Prints the (now memoized) result
    

    Interesting, this is also a way to do memoization in ruby without any conditionals, which is pretty neat.

    Please never use this in any kind of production environment. I’m begging you.

    Read More
  • Some thoughts on Ruby

    Feb 2, 2017

    I’m a well-known Ruby fanboy among my circle of friends. Even people who aren’t into programming will occasionally make a comment about it, which I think is an indication that I talk about how great the language is too often.

    In truth, it’s not surprising that people might know this about me. I really, really like Ruby. I don’t think it’s perfect for all tasks—hell, I think it’s downright terrible in some contexts—but I do think it is a fantastic language, and it’s probably my favorite to write. This blog post is going to serve as a bit of a high-level introduction to Ruby as a language, as well as a justification for my fanboy-ism.

    Read More
  • Writing and Artwork

    Sep 27, 2016

    As I mentioned in my previous post, I’ve been spending the past few months working on a novel. Along the way I’ve hit the general bumps and roadblocks: outline issues, stress about characterization, plot reworks, and so on. Still, I think I’ve been at least mildly productive. Recently, especially, I feel like I’ve hit a flow. I can sit down, and with a relatively small amount of effort, I can get into the story and set to work on expanding it. It’s not perfect, or particularly easy, but it’s productive.

    Writing a novel while working on ImageHex has been a sort of strange experience. Not necessarily because the act of coding and the act of writing are dissimilar—indeed, I’ve always maintained that the opposite was true, and that programming is a lot closer to fiction writing than most people would expect. Instead, it has been strange because of the two types of art I must focus on: visual art, such as drawing or painting, and writing.

    When I work on ImageHex I need to think about the experience of an artist. I need to think about what problems an artist may have and what the solutions to those problems can be. I’ve actually sent messages to a few artists requesting a bit of help on that front, and I’ve been very grateful for the responses I’ve received.

    When working on the novel, however, I am living the experiences of a writer. An amateur writer, sure, and somebody who is likely to never get anywhere with their writing, but still a writer in the technical sense of the word.

    Writing and artwork have a strange, intertwined relationship: similar in some ways, vastly different in others. My current life has given me a lot of time to think about these differences.

    Read More
  • Undertale

    Sep 26, 2016

    undertale logo

    I’m writing this blog post at midnight. As I write it, I am getting over a cold. I need to sleep, not only because I need to beat my sickness, but also because I have a midterm on Tuesday, and I need my sleep schedule to be in whack for it.

    Yet, as I lay awake, staring at my ceiling, I can’t fall asleep. And, stupid as it is, the reason for my wakefulness is (partially) a stupid indie RPG made by a dog.

    Read More
  • mruby, C++, and Template Magic

    May 12, 2016

    For the past few days I’ve been trying my hand at making a simple 2D game engine. It’s a challenge that involves math and programming, two subjects I greatly enjoy.

    I decided early on that I would use Ruby as the engine’s scripting language. Ruby’s pretty much my favorite language, and its ability to create DSLs seems like it would be highly useful in enabling users of the engine to be productive. The normal ruby interpreter, of course, isn’t well suited to embedding—it’s way too big and heavy. Thankfully, there’s another implementation called mruby, which is designed to be used in more resource-constrained contexts. That matches my use case pretty well, so I set it up.

    Now, I needed some way to bind ruby methods to my native code. Ideally, I’d be able to expose C++ classes and their associated methods to ruby natively. I found a library called mrubybind that seemed to do what I wanted, but I soon found it had limitations. The biggest limitation was how it handled parameter types. With mrubybind, your methods can take ints, booleans, strings, floats, and void pointers. That didn’t sit well with me. void * is a horribly unsafe construct. It has its uses, of course, but I’d rather have something with a bit more type information.

    It soon became clear that I would need to bite the bullet and write my own library. Hopefully, I could make use of C++ templates to design something with an interface that isn’t too terrible.

    Read More
  • Feature Suggestion: Website Issues

    Apr 29, 2016

    Recently I’ve been thinking about ways to allow users to give feedback on ImageHex. ImageHex isn’t fully launched and lacks users at the moment, of course, but I think that the ability to provide feedback is going to be crucial. I’m the sole developer of the website at the moment, and it’s going to be difficult (if not impossible) for me to track down any bugs it’s likely to have. This is especially true as I lack any kind of android device to test it on, meaning that there’s almost definitely a lot of minor (or major) visual glitches for android users. I’m working on rectifying that situation, but even when I do some things are bound to slip through the cracks. If companies that make millions of dollars a year can’t keep bugs out of their software, it’s highly unlikely that a college kid with no money will succeed where they have failed.

    Read More
  • Matrixes and C++

    Feb 9, 2016

    This semester, I enrolled in a linear algebra class in college. I was having some trouble learning it, so I figured I might as well expand my knowledge by writing a program. I picked C++ to be the language for this, mostly for speed, but partially because I haven’t written C++ in a while and wanted to try my hand. Of course, my version isn’t going to be nearly as fast as the hyper-optimized libraries the pros write, but that’s fine. This is just a learning project, after all.

    Read More
  • Tables

    Oct 14, 2015

    I’ve been using this web page for my CS192 class at Colorado State University. As part of one of the assignments, I have to use a table. So there’s a table after the break.

    Read More
  • A Canvas Test

    Oct 7, 2015

    Warning: This page may crash your browser

    Read More
  • A Ghost on the Net

    Sep 28, 2015

    Recently, I stumbled upon a defunct website about lost Disney World attractions. It’s obvious from the moment you get to the homepage that this site has been dead for years. If you open the dev tools, you’ll see inline <style> and <script> tags, a <center> tag, and all the other hallmarks of the internet age of old.

    Stumbling upon these websites is always an amusing experience. For me, there’s a certain nostalgic charm to them. They remind me of my first days on the internet, when I was still in elementary school. They’re relics from the days when getting content on the internet involved writing your own HTML and putting it on a server instead of making a Tumblr account and editing your text in their built-in, WYSIWYG editor. Of course, the new model is better in many ways, but the new model makes it harder to do

    Stuff like this.

    Then again, that’s probably a good thing.

    This particular website, however, is different. I don’t get a touch of joyful nostalgia. Instead, I get… a little creeped out.

    You see, this isn’t just “Bob’s Blog (Now with 100% more animated skeleton gifs!)”. This is a website about dead things, abandoned things. In some ways it could be about itself.

    Two posts specifically caught my eye:

    The first post that’s visible is the Webmaster’s petition to save Horizons, a ride in Epcot. The Wikipedia Article for the ride starts off with the words “Horizons was”, so his petition was apparently a failure. To the website, however, Horizons still exists. It’s frozen in time.

    On February 2nd, 1998, the site’s author wrote the second post, titled Disney Ramblings. In it, he outlines what he thinks the future of Disney parks will be. Surprisingly, he seems to mostly get it right. Disney had no reason to be scared of Premier Parks, a rival theme park corporation, even after they bought Six Flags. Nobody takes a trip to California to go to Magic Mountain—they take a trip to go to Disney Land, and then make a stop at Magic Mountain. Even in 1998 that was apparently obvious. Today, Disney parks still absolutely dominate their competition. But it’s not the accurate predictions that give me the creeps. It’s the last two sentences of the post:

    I’ll have to think about this further. I will continue my ramblings later.

    But he never did.

    The Webmaster may be dead at this point. The website certainly is. And yet I can still access it. The corpse is on display, immaculately preserved in just the way it used to be.

    Around it, the age in which it existed decays. Throughout the website, there’s links to dead pages. Banners that no longer display. Ad servers that no longer work. Every 404 is a tiny piece of information lost, the arrow of time moving forward. The internet has slowed the decay of history, both public and private. Wikipedia’s continued existence ensures that any trend of note will exist somewhere in our collective memory, and websites like Facebook ensure that your wedding photos will long outlive you. For a few brief moments, however, the internet let us see the decay of personal history without preventing it. The network this website once existed in is slowly wasting away. Soon, Tripod will probably stop hosting it, and it will be gone forever, just like the thoughts of billions of humans before it.

    For now, though, it exists. A window to the past revealing another window to the past, a memory dedicated to memories.

    Read More
  • Endtroducing...

    Sep 16, 2015

    Most blogs start with an introductory post, something to describe the author and what the blog will be about. I initially sat down to write just such a post. I planned on describing how I was a programmer, the languages and frameworks I used, the projects I was working on, and how this blog would probably be about a wide variety of topics.

    Come to think of it, however, the golden rule of writing is “show, don’t tell.” So it may be more effective for me to simply write on a topic I greatly enjoy. With that in mind, let us discuss one of my favorite albums:

    Read More