Five reasons to get excited about Go 1.18

The Go 1.18 update is massive. Generics, Fuzzing, and Workspaces are perhaps the most prominent new features. What else changes with the new release?

1. Type parameters, a.k.a generics

In contrast to almost all other Go updates, this one includes a rather large addition to the language - generics. I will not go into much detail in this post, as there is already a truckload of Generics articles out there—including two from myself where I turned a binary search tree into its generic counterpart and discovered generic interface functions after coming across this proposal that generics made superfluous (or so I would guess—it is still open at the time of this writing).

I am pretty sure that with this single feature, Go will win a lot of new fans.

2. Fuzzing

Some people would certainly want to see this one as #1. Fuzzing adds a new approach to Go unit tests. (To be honest, there have been fuzzing packages available long before, but this is now an integral part of Go.)

What’s the reason for fuzzing, and how does it work?

Well, no matter how busy you collect test cases for your table-driven tests, you can never be sure that you have not overlooked one or more subtle corner cases that might come back to haunt you when the code is deployed to production. Fuzzing cannot close that gap entirely but can help to narrow this gap drastically.

Fuzzing works by receiving some seed test cases from the developer—YOU!—and generating new test cases from these with a good dose of randomness involved. Chances are that one of these generated test cases will run into a subtle bug of your code where you expected it the least!

An interesting consequence of generating the test cases is that neither you nor the Fuzzing code can provide an expected output to test against. Instead, you need to test against more general attributes of the expected result. For example, a function that reverses a string could be tested by running the function twice and verifying that the result is the same as the original input.

3. Workspaces

Consider you have two modules A and B, and A imports B. If module B has already been published, the import path would point to the remote repository. Prior to Go 1.18, if you want to work on module B while testing the changes with module A, you had to add and remove replace directives to module A’s go.mod file as needed. Just don’t forget to remove it before pushing the changes to the remote repository!

With Go 1.18, local multi-module testing becomes significantly easier.

  • Create a workspace directory.

  • Put the first module to modify locally in a subdirectory of the workspace directory.

  • Add a go.work file to the workspace directory, typically by calling go work use.

  • Then you can add more modules to that workspace by calling go work use for each of them. Only the first module needs to reside inside the workspace directory, the others can be where you want them to be.

  • Now you can cd to a module in your workspace and run a go command like go build as usual. If that module imports a module with the same module path as any of the other modules in the workspace, the go command will import the module from the local path instead.

    An example: your main module imports "github.com/yourorg/somemodule", and a module in your workspace has this path in its go.mod file, like module github.com/yourorg/somemodule. Then the go command will use the local version of that module instead of the remote one. You can twist and tweak the code of somemodule, and the main module will pick up the changes immediately.

4. Standard Library additions

Lots of interesting changes happened in the standard library. I’ll list only the changes in the “mainstream” packages, skipping the more specialized ones. For the full list, see the Go 1.18 release notes.

  • The sync package has new TryLock methods that do not block if the mutex is locked. They only return a boolean success indicator. I tested the TryLock method already as a possible strategy for avoiding deadlocks.

  • The new package net/netip introduces a new IP address type Addr that takes less memory, is immutable, and is comparable. Plus two other types, AddrPort and Prefix, as well as new functions to support the new types.

  • The bytes and strings packages have a new Cut function for slicing a byte slice or string around a separator.

  • strings also has a new Clone method for copying a string into a different memory area.

  • In both packages, the Title function is deprecated and superseded by the golang.org/x/cases package.

  • html/template and text/template have new {{break}} and {{continue}} commands for breaking a loop early or continuing the next iteration, respectively.

  • text/template/parse supports these commands for both packages via new constants NodeBreak and NodeContinue and new types BreakNode andContinueNode.

5. Bugfixes and deprecations

  • The compiler now correctly reports an error for variables that are declared inside a function literal but never used.

  • Passing a rune constant expression like '1' << 32 to the built-in functions print or printlnnow correctly reports an overflow.

    • Attention: this can break existing code—but such code is incorrect anyway and should be fixed.
    • go get no longer builds or installs packages in module-aware mode. Use go install and add a version to the package path, e.g. go install github.com/appliedgocode/goman@latest.

Read more

This was only a quick overview. Read more here:

Happy coding!


Categories: Releases