liveBook · Manning

Code generation

As explained in Go in Practice, Second Edition

Code generation is the automated production of program source or implementation code from declarations, schemas, or other inputs.

Code generation writes Go source from inputs such as type names or annotated structs, then compiles that source with the rest of the program. It is useful when repeated declarations would be tedious or when runtime reflection adds latency and allocations. Generics remain an option; generation has a niche when they do not fit the task. section 13.3 section 13.0

To run a generator, place a directive such as `//go:generate ./queue MyInt` in a Go file and run `go generate`. The command is an executable plus arguments: `go generate` finds the directive and runs it. A generator can read those arguments, obtain the package name from `GOPACKAGE`, and write a `.go` file. section 13.3

Listing 13.19 The queue template
package main

import (
     "fmt"
     "os"
     "strings"
     "text/template"
)

var tpl = `package {{.Package}}   #1
type {{.MyType}}Queue struct {    #2
     q []{{.MyType}}
}

func New{{.MyType}}Queue() *{{.MyType}}Queue {
     return &{{.MyType}}Queue{
            q: []{{.MyType}}{},
     }
}

func (o *{{.MyType}}Queue) Insert(v {{.MyType}}) {
     o.q = append(o.q, v)
}

func (o *{{.MyType}}Queue) Remove() {{.MyType}} {
     if len(o.q) == 0 {
            panic("Oops.")
     }
     first := o.q[0]
     o.q = o.q[1:]
     return first
}

The queue template substitutes a package name and type name into a struct, constructor, and methods. section 13.3

Listing 13.20 The main queue generator
func main() {
     tt := template.Must(template.New("queue").Parse(tpl))   #1
     for i := 1; i < len(os.Args); i++ {                 #2
            dest := strings.ToLower(os.Args[i]) + 
            "_queue.go"                                    
            file, err := os.Create(dest)
            if err != nil {
                   fmt.Printf("Could not create %s: %s (skip)\n", 
                   dest, err)
                   continue
            }
            vals := map[string]string{
                   "MyType":  os.Args[i],                   #3
                   "Package": os.Getenv("GOPACKAGE"),   #4
            }
            tt.Execute(file, vals)   #5

            file.Close()            
     }

}

The generator loops over type-name arguments and writes a separate queue source file for each. section 13.3

Generate a typed queue

With `type MyInt int` and `//go:generate ./queue MyInt` in `myint.go`, running `go generate` creates `myint_queue.go`. Compile both files to use `NewMyIntQueue`, `Insert`, and `Remove`; the demonstrated program removes the first inserted value. section 13.3

Generation can also move repeated type inspection out of a hot path. The `codecgen` command reads a tagged `User` struct and produces `CodecEncodeSelf` and `CodecDecodeSelf` methods. The codec package uses those methods when present and otherwise falls back to runtime handling. This can reduce the reflection costs of repeated JSON encoding and decoding. section 12.3.1

Other uses include generating protocol-buffer and gRPC scaffolding from service definitions. That saves hand-written message-handling code, though adopting gRPC can be more involved than building a small REST API. section 11.5

How Go in Practice, Second Edition covers it

How deep it goes
Works through a directive, a template-based generator, generated files, and their use in a program.
Examples
Builds a typed queue generator and demonstrates generated JSON codec methods and gRPC client scaffolding.
What it assumes
Assumes familiarity with Go packages, structs, and commands while introducing generator directives and template substitution through examples.
What you can do after
Build it from scratch with `go generate` and Go templates, or apply it via `codecgen` to tagged structs.
How it connects
Connects code generation to reflection, generics, struct tags, JSON serialization, protocol buffers, and gRPC.

Also explained in

Compare how 17 books explain code generation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.