Update: Want to listen to a podcast about Go 1.19 instead of reading a blog post? Check out Go Time episode 240. Go 1.18 was a big release with huge features like generics, fuzzing, and workspaces. There was plenty of excitement around [its minor](/post/2021/golang-118-minor-features/) or [even ultra-minor](/post/2022/golang-118-even-more-minor-features/) features. [Go 1.19](https://tip.golang.org/doc/go1.19) is not a release on that scale. But it does pack in a lot of small improvements that can help the average Go developer. Let's take a look at what some of them are. - - - - ## Stuff I worked on It's my blog, so of course I'm going to start with the features that I helped work on. 😊 I can't actually take full credit for any of the features I helped get into 1.19, but I did get my name listed for the commits in git, so it counts. ### New `url.JoinPath` `url.JoinPath` is a new function and method pair in the url package that [does what it says on the tin](https://pkg.go.dev/net/url@go1.19beta1#JoinPath). A user called [wanglong001](https://github.com/wanglong001) on Github suggested the feature, and we batted around the implementation details in the issues. I was particularly interested in it because I had just worked on a URL path joining feature for [my HTTP requests library](/post/2021/requests-golang-http-client/). ### New `time.Duration.Abs()` This feature was born out of a bug that [bit me in production](https://github.com/spotlightpa/almanack/pull/143/commits/cba4d5f0055bf9aafa31e28d415a84c8edec48cc#diff-be96de0d62daf80f89f3ab830a5925c44b924ec35ad37ae587d5b926b158dd8b). 😊 If you have two `time.Time`s and want to know if they're within N minutes of each other, you might try to subtract them, convert the difference to a positive number if it's negative, then see if that duration is less than N minutes. That doesn't work because `time.Duration` can represent [one more nanosecond in negative numbers than in positive numbers](https://en.wikipedia.org/wiki/Two%27s_complement), since it's just an ordinary signed `int64` under the covers. This will come up anytime one of the two `time.Times` is zero because the zero time is longer ago than can fit into a `time.Duration`. In Go 1.19, [the new method `time.Duration.Abs()`](https://pkg.go.dev/time@go1.19beta1#Duration.Abs) fixes the problem by just rounding down in the case of saturation. Russ Cox, as always, was extremely helpful in pointing me in the direction of a better solution after I opened [the issue](https://github.com/golang/go/issues/51414). ### New `http.MaxByteError` The [underlying issue](https://github.com/golang/go/issues/30715) for this dated back to 2019. [As with `http.MaxBytesHandler`](/post/2021/golang-118-minor-features/#2-new-httpmaxbyteshandler-middleware), what pushed me to work on this was reading the great [Let's Go Further](https://lets-go-further.alexedwards.net) by [Alex Edwards](https://www.alexedwards.net/blog/chronological). The problem is that if you use [a `http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader) and want to return a proper error message to your faulty clients, there wasn't a reliable way to detect the errors from `http.MaxBytesReader` until now. You had to just look at the error string and see if it was exactly `"http: request body too large"`. If the Go team ever changed this error string, the check would break. [The new `http.MaxBytesError`](https://pkg.go.dev/net/http@go1.19beta1#MaxBytesError) lets you [use `errors.As`](/post/2020/working-with-errors-as/) to check for the error reliably and send a proper response. It also lets you see what the limit was that the client exceeded. - - - - ## Stuff I'm just a fan of ### First use of generics in the standard library We've all been waiting for years for Go to get generics, but the Go team have [deliberately chosen](https://github.com/golang/go/issues/48918) to keep the roll out of generics to the standard library slow for now. Well, blink and you'll miss it, but [here is](https://pkg.go.dev/sync/atomic@go1.19beta1#Pointer) the first new API in the standard library to use generics: `atomic.Pointer[T]`. In prior versions of Go, you could [use `atomic.StorePointer`](https://pkg.go.dev/sync/atomic#StorePointer) and friends to achieve this same functionality, so it's not really a new capability, but it is a much more convenient way to use the feature. These new features flowed out of [Russ Cox's work](https://research.swtch.com/mm) on revising [Go's memory model](https://tip.golang.org/ref/mem). As before, the memory model warns, "If you must read the rest of this document to understand the behavior of your program, you are being too clever." For most programmers, the long and short of the changes are that Go is now documenting that its memory model guarantees are more or less similar to other languages, but nothing should change in code that the average programmer writes. ### Go doc improvements One of the nice features of Go has always been how the parts of the go tool work together: it formats code with `go fmt`, runs tests with `go test`, and provides documentation with `go doc`. However, the exact formatting that `go doc` expects was a bit cryptic. It supports headings, lists, and blockquotes, but you had to know to [read the right Github repo](https://pkg.go.dev/github.com/fluhus/godoc-tricks) to figure out how to do it. Fortunately, for Go 1.19, the formatting expected by `go doc` has [been clarified](https://tip.golang.org/doc/comment) and now `go fmt` will even clean up certain formatting issues with doc comments. You can also include links in your doc comments, and it should display properly on [pkg.go.dev](https://pkg.go.dev). ### Soft memory limit Go deliberately restricted the number of "knobs" that could be used to tune garbage collection to try to keep things working simply for the large majority of users. [Setting `GOGC`](https://pkg.go.dev/runtime/debug#SetGCPercent) lets you tell Go when to trigger the next round of garbage collection based on the percentage of new memory allocated versus old memory remaining. This lead to strange tricks like [Twitch's "memory ballast" optimization](https://blog.twitch.tv/en/2019/04/10/go-memory-ballast-how-i-learnt-to-stop-worrying-and-love-the-heap/), in which they tried to smooth out garbage collection by just allocating a big slab of memory that they didn't actually need. Go 1.19 adds a soft memory limit that can be controlled by the environment variable `GOMEMLIMIT` or `runtime/debug.SetMemoryLimit`. Michael Knyszek wrote [the proposal](https://github.com/golang/proposal/blob/150687b78c1d11cdb41572e75484c84280d5a963/design/48409/soft-memory-limit.src.md) for this issue, which should make "memory ballast" obsolete and make it easier to use Go in devices like phones and tablets with a lot of RAM but a hard ceiling. It essentially sets a target and triggers increasingly aggressive garbage collection (within a CPU limit) as the amount of memory used gets closer to that target. ### More AppendX functions Go 1.18 [added `bufio.Writer.AvailableBuffer()`](/post/2022/golang-118-even-more-minor-features/#3-bufiowriteravailablebuffer) to make the low level append-to-preallocated-byte-slice pattern a little easier to use. Go 1.19 expands this pattern greatly by adding [`fmt.Append`, `fmt.Appendf`, and `fmt.Appendln`](https://pkg.go.dev/fmt@go1.19beta1#Append). These functions work like `fmt.Print` etc. but instead of printing to standard out or an `io.Writer` or a string, they append to a byte slice, which allows for very precise control of memory allocation. ### New `flag.TextVar` I am [a big fan of the flag package](/post/2020/add-func/), so I'm always happy to see improvements to it. [The `flag.TextVar` function and method](https://pkg.go.dev/flag@go1.19beta1#TextVar) let you use any type which [implements `encoding.TextUnmarshaler`](https://pkg.go.dev/encoding#TextUnmarshaler) directly as a flag without needing to write an adapter. Some example types that already implement TextUnmarshaler are `big.Int`, `net.IP`, and `time.Time`. ### New `sort.Find` and new sort algorithm While we're [waiting for `slices.Sort`](https://pkg.go.dev/golang.org/x/exp@v0.0.0-20220613132600-b0d781184e0d/slices#Sort) to be added to the standard library (with [its promised speed up](https://twitter.com/carlmjohnson/status/1441086498464403463)), the good old sort package is making some improvements of its own. Rob Pike [proposed](https://github.com/golang/go/issues/50340) `sort.Find`, which is [a new way](https://pkg.go.dev/sort@go1.19beta1#Find) to search for an item in a presorted sequence. Also, the algorithm for `sort.Sort` has been slightly tweaked to use the [pattern defeating quicksort](https://arxiv.org/pdf/2106.05123.pdf) variation. It is still O(n log n) on average and in the worst case, but it has a best case time of O(n) that it can achieve in some cases, such as when the sequence is already sorted. - - - - Wrapping up, Go 1.19 won't be remembered as the kind of paradigm shattering release that 1.18 was, but it brings a steady accumulation of small improvements in the lives of Gophers. You can [download the release candidate](https://groups.google.com/g/golang-announce/c/Lu8ODY19HhA) now and the final version should be released soon. Enjoy and see if you can find some issues to contribute to for Go 1.20 and beyond.