Frontier Software

Go

Wiki

Go’s commands and subcommands:

go
├── bug         start a bug report
├── build       compile packages and dependencies
├── clean       remove object files and cached files
├── doc         show documentation for package or symbol
├── env         print Go environment information
├── fix          update packages to use new APIs
├── fmt         gofmt (reformat) package sources
├── generate    generate Go files by processing source
├── get         add dependencies to current module and install them
├── help
├── install     compile and install packages and dependencies
├── list        list packages or modules
├── mod         module maintenance
│   ├── download    download modules to local cache
│   ├── edit        edit go.mod from tools or scripts
│   ├── graph       print module requirement graph
│   ├── init        initialize new module in current directory
│   ├── tidy        add missing and remove unused modules
│   ├── vendor      make vendored copy of dependencies
│   ├── verify      verify dependencies have expected content
│   └── why         explain why packages or modules are needed
├── work        workspace maintenance
│   ├── edit        edit go.work from tools or scripts
│   ├── init        initialize workspace file
│   ├── sync        sync workspace build list to modules
│   ├── use         add modules to workspace file
│   └── vendor      make vendored copy of dependencies
├── run         compile and run Go program
├── test        test packages
├── tool        run specified go tool
├── version     print Go version
└── vet         report likely mistakes in packages

I started these notes teaching myself Go by working through Brian Kernighan & Dennis Ritchie’s classic The C Programming Language (K&R to its friends) and translating the examples from C to Go before discovering this was all readily available since Kernighan co-authored The Go Programming Language with Alan Donovan (gopl to its friends).

It turned out lots of things I’d painstakingly figured out were explained nicely in the preface of this Go book.

Hello Word

This is the big hurdle; to leap over it you have to to be able to create the program text somewhere, compile it successfuly, load it, run it, and find out where your output went. With these mechanical details mastered, everything else is comparitively easy. — K&R

Example 1 in K&R looks like this:

#include <stdio.h>

main()
{
	printf("hello, world\n");
}

The first example from A Tour of Go uses the fmt package’s Println function.

In my initial attempt to translate the above into Go, I created a file called hello_world.go which worked find with go run hello_world.go, but it turns out in Go, rather create a subdirectory hello-world with a file called main.go containing func main() {...}.

For this simple introductory example, my directory tree looks like this:

hello-world
├── go.mod
├── hello_test.go
└── main.go

main.go

/*
The only way to learn a new programming language is by writing programs in it.
The first program to write is the same for all languages.
*/
package main

import "fmt"

func main() {
	fmt.Printf("Hello, world\n")
}

hello_test.go

package main

func ExampleHello() {
	main()
	// Output:
	// Hello, world
}

main.go

module hello-world

go 1.22.2

go test

go test scans the *_test.go files for functions which start with Test, Benchmark or Example. Here I’m using an Example type test.

A gripe I have with many programing books is they leave a given language’s testing and documentation tools to the end, if they cover them at all. In Kernighan’s Go book, testing is only introduced in Chapter 11.

$ go test
PASS
ok  	hello-world	0.006s

My favourite introduction to programing, How to Design Programs, a prequel to Structure and Interpretation of Computer Programs, encourages programers from day 1 to practice test-driven development and to write in “natural language” what they are trying to achieve before diving into how by coding.

go mod init hello-world

My initial attempts to get go test to work failed because a go.mod file is required in the project directory, which was easily created by go mod init hello-world

Given a go.mod file with the name of the module, go build created an executable binary hello-world.

godoc

“Doc comments” are comments that appear immediately before top-level package, const, func, type, and var declarations with no intervening newlines. Every exported (capitalized) name should have a doc comment. — Go’s structured comment rules

Extensive doc comments are often placed in a file of their own, conventionally called doc.go. — gopl

While go doc extracts structured comments, to get a local webserver etc requires godoc which needs to be installed:

go install golang.org/x/tools/cmd/godoc@latest

The above command put it into %HOME/go/bin from where I moved it to /usr/bin.

Then by running godoc -http=localhost:6060 and pointing my browser to http://localhost:6060/pkg/hello-world/ showed the following:

Pointing to http://localhost:6060/pkg/ brings up documentation of all the Go packages installed on your computer.

A reason I like hugo is I prefer code embedded in documentation to “structured comments”. But to stick to the 6 step recipe from How to Design Programs:

  1. From Problem Analysis to Data Definitions
  2. Signature, Purpose Statement, Header
  3. Functional Examples
  4. Function Template
  5. Function Definition
  6. Testing

What’s in step 2, “Signature, Purpose Statement, Header” along with a few functional examples are important too.

Good Comments Explain WhyHow To Write Comments in Go

main

In this simple example, we have package main and func main() {...} in a file called main.go.

Normally you are at liberty to give functions whatever names you like, but “main” is special — your program begins executing the beginning of main. This means that every program must have a main somewhere. — K&R

Linter staticcheck gives no complaints about the above code.

Package main is special. It defines a standalone executable program, not a library. Within package main the function main is also special — it’s where the execution of the program begins. — gopl

The next step is to modularize a larger, more complex program into separate files which go install will then combine into one executabale file.

Packages

Tutorials

packages

Successful design is based on a principle known since the days of Julius Caesar: Divide and conquer. — Structured Design, Edward Yourdon and Larry L. Constantine

Go programs are organized into packages. A package is a collection of source files in the same directory that are compiled together. Functions, types, variables, and constants defined in one source file are visible to all other source files within the same package. — How to Write Go Code

pgx

github

https://github.com/jackc/pgx/wiki/Getting-started-with-pgx

https://donchev.is/post/working-with-postgresql-in-go-using-pgx/

error-handling

Handling errors in concurrent programs involves a completely different way of thinking than handling errors in sequential programs… Error handling in concurrent Erlang programs is based on the idea of remote detection and handling of errors. Instead of handling an error in the process where the error occurs, we let the process die and correct the error in some other process. — Joe Armstrong in Programming Erlang.

5 Error Handling strategies

  1. Propogate the error (ie Erlang-style).
  2. Retry if error is due to a transient problem, possibly with a delay and limit on number of attempts.
  3. Print error and stop program (usually reserved for main package).
  4. Log error and continue.
  5. Ignore error entirely.

Error handling in Go has a particular rhythm. After checking an error, failure is usually dealt with before success. If failure causes the function to return, the logic for success is not indented within an else block but follows at the outer level. — gopl

types

  • basic
    • number
      • int octal begin with 0, hexadecimal 0x
        • int8
        • int16
        • int32
        • int64
      • rune (int32) single quoted unicode character eg ‘a’
      • uint
        • uint8
        • uint16
        • uint32
        • uint64
        • uintptr
      • byte (uint8)
      • float32
      • float64
      • complex64
      • complex128 0.867 + 0.5i
    • string
      • []byte
    • bool
  • aggregate (composite, fixed size)
    • arrays [3]int{1,2,3}
    • structs ages.alice = 31
  • reference
    • pointers
    • slices
    • maps ages["alice"] = 31
    • functions
    • channels
  • interface

concurrency-oriented-programming

Here I’m going to switch from translating examples in K&R to translating examples from another classic, Joe Armstrong’s Programming Erlang: Software for a Concurrent World.

I put some notes on Erlang at github:

Erlang has no mutexes, no synchronized methods, and none of the paraphernalia of shared memory programming. — Joe Armstrong

input_output

K&R’s introductory examples using the C stdio.h library’s getchar function can’t be directly translated to Go easily.

A search brought up Create a WC clone with Golang which I’ll use as my template. It’s also a nice example of test-driven development which is lacking in the classic K&R tutorial.