NoRaincheck

In Appreciation of Go Generate

In Appreciation of Go Generate

September 2025

Go is a rather minimal language. It does away with macros and (direct) metaprogramming, but it does offer code generation as a first-class citizen via go:generate . On multiple counts, it is rather unassuming and underwhelming, after all the code generation needs to be directly committed for it to be used; there’s no generators or run time generation, but rather it forms part of the distribution.

In a sense, this ends up being a feature of Go, specifically how it implicitly does imports compared with other languages like Python. For example, if a source file defines a method, then that method is exposed everywhere within the scope of that package. More specifically it does not need to be explicitly imported. This facet of Go compliments and perhaps even encourages the use of code generation.

For example, if you want to extend sqlc to use a code generator, you can then naively extend the Querier interface in a separate file. For example, your file tree could look like:

├─ querier.go
├─ querier_custom.go

Where your source code in querier_custom.go in its totality would just look like

 1package sqlc
 2
 3import (
 4    "context"
 5)
 6
 7type CustomQuerier interface {
 8    Querier
 9    
10    MyCustomMethod(ctx context.Context, ...) (...)
11}
12
13var _ CustomQuerier = (*Queries)(nil)

The interface will automatically compose itself, which is different to how Python might do it in OOP way

1from querier import Querier
2
3class CustomQuerier(Querier):
4    ...

I think this implicit namespace inclusion in Go is what makes code generation work so well. At the same time there are draw-backs with regards to codebase navigation. It leads to the lots of (automated) code that is directly in the codebase, rather than having it hidden away in a macro. This affects the readability of a codebase and ability to navigate it without an IDE. In my exposure to Go code, I find the code very difficult to navigate using the web interface. It is difficult to ‘guess’ where a method may be defined (it can literally be anywhere!). In comparison in languages like Python/Rust, imports are explicitly stated, meaning that one can navigate the codebase without relying on IDE/LSP functionality.

Overall this kind of setup in many ways make Go code approachable, in the sense that there’s no ‘knowledge’ one needs to have when tackling a new codebase. Everything is laid bare for you to follow. From a personal perspective, I believe it is something to acknowledge and appreciate. It is this simplicity that allows one to walk away from a Go codebase and come back to it years down the track and just pick it up again.

<< Previous Post

|

Next Post >>

🎲 Random post

|

All posts

#Python #Go #Code-Generation