What are the options? • The Applied Go Weekly Newsletter 2025-03-23
Your weekly source of Go news, tips, and projects
What are the options?
Hi ,
Fascinating articles grabbed my attention this week: A dead-simple virtual machine that runs no bytecode, a Go-based intro to systems programming, and (in the Unrelated section) an article about the evils of the null
value in programming languages. I took the latter as an occasion for inspecting the usefulness of option types in Go—see the Spotlight section.
Happy spring coding! (Where "spring" is the season, not that Java thing. Everyone on the southern half of the globe, please substitute "autumn" or "fall".)
–Christoph
Featured articles
Faster interpreters in Go: Catching up with C++ — PlanetScale
Typical virtual machines have drawbacks: Usually, they're slow, and if they are co-developed along with a compiler, the two projects need to be kept in sync.
PlanetScale didn't want to go down that route, so they made the virtual machine a dead-simple caller of functions picked from a slice. As a consequence, the compiler also became simple as it doesn't need to emit any bytecode. (Sounds strange, but the article explains it much better as I can do it here in a few words.)
Starting Systems Programming, Pt 1: Programmers Write Programs
Can you implement a grep
tool during an interview? Efron Licht has seen too many candidates fail at this seemingly simple task, so he started an article series about systems programming. The second part has also been released already.
Someone copied our GitHub project, made it look more trustworthy by adding stars from many fake users, and then injected malicious code at runtime for potential users.
Attention, (potential) Atlas users! Malicious actors try to sneak malware onto your machines, so be careful about the exact URL you're importing from.
The attack scheme is simple: Fork a well-known repo, make it look legit, and add malware to it.
As far as Go repos are concerned, even if GitHub removes the malicious repo, the Go proxy server may already hold a copy of the repo.
So if you come across such an attack, immediately inform not only GitHub but also the Go team so that they can remove the malicious code from the Go proxy as well.
Podcast corner
Fallthrough: Choosing, Expanding, & Evolving Communities
Kelsey Hightower ("Bash is the reason people leave IT!") joins Kris and the Fallthrough panel to discuss the ins and outs of communities in tech (and outside tech).
go podcast() 055: Zog, a Go validation pkg with Tristan Mayo
Tristan Mayo, author of Zog, talks to Dominic about his journey from starting into programming as a 12-year-old to his current project, a validation library for Go. (Zog, that is.)
Spotlight: Optional Types
Language enthusiasts, particularly those of other languages, tend to scold Go for having a nil
value and happily cite Tony Hoare (see also the Completely Unrelated article about "marker values"), even though they often miss the point that Go's nil
is a typed value and therefore better than the untyped null
value of other languages.
Still, the desire of having "something safer" than nil
exists. Everyone who accidentally dereferenced a nil
pointer without checking knows what I mean. Option types to the rescue! An option type is a wrapper around a value that allows checking the value for absence before accessing it.
Are option types useful in Go? Let's check it out.
Here is an example of a very simple option type:
The type is basically just a struct with a value and an absence marker. A "constructor", often named Some()
, wraps a given value into an option type. Likewise, a None()
constructor returns an option type with no value.
type Option[T any] struct {
val T
none bool
}
func Some[T any](v T) Option[T] {
return Option[T]{
val: v,
}
}
func None[T any]() Option[T] {
return Option[T]{
none: true,
}
}
A Wrap()
method allows constructing an option type including the absence marker. This comes handy if, for example, a library function wants to wrap a pointer (that could be nil
) into an option type.
func Wrap[T any](v T, null bool) Option[T] {
return Option[T]{
val: v,
none: null,
}
}
When working with an instance of this option type, the IsSome()
method reveals whether the instance contains a valid value.
func (opt *Option[T]) IsSome() bool {
return !opt.none
}
Note that the above implementation is just sufficient for this example. What if the value passed to the Some()
constructor is a nil
value? Real-life option type libraries would check for nil
values, too, as in this example.
The Or()
method conveniently allows accessing an option type instance or use a fallback value in case the option type instance contains no value.
func (opt *Option[T]) Or(fallback T) T {
if !opt.none {
return opt.val
} else {
return fallback
}
}
Likewise, this Value()
method provides a fallback mechanism through the "comma, ok" idiom. Value()
returns the inner value and a boolean that is true
if the value is valid, else false
.
func (opt *Option[T]) Value() (T, bool) {
if opt.none {
var zero T // the zero value of T
return zero, false
}
return opt.val, true
}
Here is this little option type in action:
func main() {
var null *int
absent := -1
// wrap the pointer
optPtr := Wrap(null, true)
fmt.Println(optPtr.IsSome())
// comma, ok idiom:
if msg, ok := optPtr.Value(); ok {
fmt.Println(msg)
}
// dereferencing with fallback:
fmt.Println(*optPtr.Or(&absent))
}
Run this to see how the option value can be safely accessed through the comma, ok idiom or through the Or()
fallback mechanism.
What did we win?
Arguably, even an option type requires to either test the validity of the encapsulated value or take measures to deal with absent values.
Especially, for pointer types, we could as well use the classic nil
check to avoid dereferencing a nil pointer:
if ptr != nil {
fmt.Println(*ptr)
}
An option type, though, makes it impossible to forget the check for nil
. The user must go through the "getter" methods Or()
or Value()
to access a wrapped pointer, and thus cannot forget to check the ok
value or provide a fallback value.
A small win only, you might argue, and I wouldn't oppose your standpoint. Especially, as linters like golangci-lint
can detect possible nil dereferencing.
Yet, depending on the situation, the elevated safety may be worth using an option type.
Quote of the Week: A greppable language
Programming thought: there's an underappreciated aspect to Go's syntax that I miss in almost all other languages, and might be the single biggest reason I still use Go so frequently even though there are plenty of other languages that I prefer that might be just as good (otherwise) for a specific task. And that's the consistency and grep-ability of the language.
More articles, videos, talks
Building Cross-Platform SDKs: From FFI to WebAssembly | Flipt Blog
TL;DR: Go and wazero are a great combo for building cross-platform SDKs without going through all the CGO and glibc vs musl dramas.
Go import cycles: three strategies for how to deal with them, and a plea for a fourth
Zach Musgrave's biggest gripe with Go is the strict rejection of import cycles. I beg to disagree, for these reasons. Anyway, it can happen that unwanted circular dependencies evolve in a large codebase, and then they're difficult to resolve. Zach shares three approaches to deal with import cycles, from good to ugly.
My 6 months with the GoTH stack: building front-ends with Go, HTML and a little duct tape
Tom Elliott shares some lessons learned from building apps with Go, Templ, Tailwind, and HTML.
Session-Based Authentication in Go
Mohamed Said continues his series about writing an app server in Go with an article on letting users log in and out, tracking the status inside the session.
Go Structs and Interfaces Made Simple
Structs for the implementation, interfaces for the behavior: An introduction to Go's non-OOP approach to program design, from the ground up.
Timeout Middleware in Go: Simple in Theory, Complex in Practice - Viktor Nikolaiev's blog
What if you need different timeouts for different endpoints? Viktor Nikolaiev found that what looks straightforward can become quite a challenge.
Projects
Libraries
GitHub - DBarbosaDev/supermuxer: Super useful and dependency-free Go package to configure your HTTP routes using only the standard library. Define routes, middlewares, groups, and subgroups effortlessly! This package acts like a Swiss Army Knife: It is tiny and compact, providing everything you need in just one file with less than 200 lines of code.
A tiny package with some usability enhancements for net/http
.
GitHub - minio/minlz: MinLZ is a LZ77 compressor, focused on realtime data compression
MinLZ was just released but already has about two years of work behind it. It provides Block (up to 8MB) and Stream compression. Both compression and decompression include amd64 assembly to achieve multiple GB/s of throughput.
The Bappa Framework | Bappa
A game framework based on the Ebiten 2D game engine.
OpenRouter
For anyone working or experimenting with LLMs a lot, the sheer number of available models and providers can become overwhelming. OpenRouter.ai channels 100+ different models through a single API, (for a small extra fee on top of the cost per token). This repo is an unofficial client SDK, so that you can create LLM-powered apps without worrying about APIs and endpoints and vendor peculiarities.
GitHub - robbyt/go-supervisor: Handle OS signals, graceful shutdown, hot reloading
An all-in-one package for monitoring and managing Go server states inside the app.
Tools and applications
GitHub - owulveryck/gomcptest: A proof-of-concept demonstrating a custom-built host implementing an OpenAI-compatible API with Google Vertex AI, function calling, and interaction with MCP servers.
Typically, you would use LLM clients like Claude Desktop to connect LLMs to MCP servers (that is, tools that can do work for the LLM such as working with local files or searching the Web). This project aims to be a replacement for Claude Desktop (but just as a proof of concept). It uses VertexAI but the author says it should be easy to connect to Ollama instead.
GitHub - nubskr/nubmq: A high performant nosql engine engineered from first principles
If you look for a Redis replacement or simply a K/V store, nubmq
does not only have interesting performance promises but also has no external dependencies.
Go is DOOMed
DOOM, the 1st-person shooter from the last millenium, has been ported to the wildest places: to terminal UIs, watches, Lego bricks, inside a PDF file, the Apple Lightning-to-HDMI adapter, a Honeywell thermostat, a Husqvarna Robotic Lawnmower, inside the Doom Eternal game, and many more.
A port to Go would therefore seem a bit "meh", but still: It's CGO-free and a nice proof of concept, even though it runs only on Linux/X11 targets and has no sound.
GitHub - go2hx/go2hx: Go to Haxe source-to-source compiler
Want to transpile your Go code to C++, Java, Javascript, Lua, C#, and other languages? Then compile it to Haxe and move on from there. (Alpha status)
Completely unrelated to Go
Use marker values instead of null or whatever your language calls a it!
null
values are Tony Hoare's "billion dollar mistake". Jarrod Roberson seeks to replace null
s by ... no, not option types, but marker values.

Happy coding! ʕ◔ϖ◔ʔ
Questions or feedback? Drop me a line. I'd love to hear from you.
Best from Munich, Christoph
Not a subscriber yet?
If you read this newsletter issue online, or if someone forwarded the newsletter to you, subscribe for regular updates to get every new issue earlier than the online version, and more reliable than an occasional forwarding.
Find the subscription form at the end of this page.
How I can help
If you're looking for more useful content around Go, here are some ways I can help you become a better Gopher (or a Gopher at all):
On AppliedGo.net, I blog about Go projects, algorithms and data structures in Go, and other fun stuff.
Or visit the AppliedGo.com blog and learn about language specifics, Go updates, and programming-related stuff.
My AppliedGo YouTube channel hosts quick tip and crash course videos that help you get more productive and creative with Go.
Enroll in my Go course for developers that stands out for its intense use of animated graphics for explaining abstract concepts in an intuitive way. Numerous short and concise lectures allow you to schedule your learning flow as you like.
Christoph Berger IT Products and Services
Dachauer Straße 29
Bergkirchen
Germany