- Golang Nugget
- Posts
- What to expect from Go 1.24 - Part 1
What to expect from Go 1.24 - Part 1
A deep dive into the new toolchain features and the full support for generic type aliases coming in Go 1.24.
Go 1.24 is set to be released in February 2025, and it is bringing some amazing features that I couldn’t wait to get my hands on. In this post, I’ll cover Generic Type Aliases and the new tool directive. This post kicks off the first in a series of Go 1.24 editions, where I’ll explore the new features in detail.
Generic Type Aliases
Generics were introduced in Go 1.18, making it simpler to work with different types without sacrificing type safety. Aliases were introduced in Go 1.19, but without support for generics. Now, Go 1.24 is bringing the complete package with Generic Type Aliases.
Let me explain the difference between a type definition and a type alias before getting into generic type aliases.
Type Definition
Type definitions are useful when you want to create a completely distinct type based on an existing one. With this, we can add custom methods and behaviors to the new types and ensure we’re not accidentally mixing them.
type Celsius float64
type Fahrenheit float64
Here, Celsius
and Fahrenheit
are distinct types, even though they both share the underlying type float64
. We can define different methods for each type, preventing unintended operations between them.
It improves type safety by preventing us from accidentally passing Celsius
to a function expecting Fahrenheit
. It also makes the code more readable.
It’s worth mentioning when you create a type definition, it gets the underlying data type's fields but not its methods. For example, in the following code, Manager
has access to age
and name
fields from Employee
, but it doesn’t get the Title
method.
type Employee struct {
name string
age int
}
func (e Employee) Title() string {
return "Employee"
}
type Manager Employee
func (m Manager) DescribeRole() {
title := m.Title() // Does NOT compile
fmt.Printf("%s is %d years old and they are a(n) %s!\n", m.name, m.age, title)
}
Type Alias
Type aliases provide an alternative name for an existing type without creating a new, distinct type.
type Manager = Employee
func (m Manager) DescribeRole() {
title := m.Title() // It compiles
fmt.Printf("%s is %d years old and they are a(n) %s!\n", m.name, m.age, title)
}
Here, Manager
is simply another name for Employee
. The compiler treats Manager
and Employee
as interchangeable. Type aliases are handy for code refactoring and improving readability, especially when dealing with long or complex type names.
Until now, we couldn’t use type aliases with generic types, but Go 1.24 introduces this feature. Let’s look at an example to make sense of it.
Suppose we have a generic type Pair
in a package called oldpkg
:
package oldpkg
type Pair[T any] struct {
First T
Second T
}
Assume we want to deprecate oldpkg
and move Pair
to a new package newpkg
while maintaining full compatibility. Type aliases become incredibly useful when moving types and guiding users toward the new package.
Before Go 1.24, you couldn’t directly create a type alias for Pair[T any]
because type aliases didn’t support type parameters. But now, we can define the following alias:
package newpkg
import "path/to/oldpkg"
type Pair[T any] = oldpkg.Pair[T]
With this alias, newpkg.Pair
and oldpkg.Pair
are treated as the same type, ensuring complete compatibility. The [T any]
part ensures that the alias also captures the generic type parameter.
New “tool” directive
Go 1.24 introduces a new tool
directive in go.mod
to track executable dependencies. Let’s break down what problem it solves and why it’s so useful.
If you’ve looked at the Kubernetes codebase, you might have seen files called tools.go. Here’s an example of one. These files import tools using _
and don’t actually do anything with them:
// Package tools is used to track binary dependencies with go modules
// https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
package tools
import (
// linting tools
_ "github.com/aojea/sloppy-netparser"
_ "github.com/client9/misspell/cmd/misspell"
// ...
// Some more imports
// for publishing bot
_ "golang.org/x/mod/modfile"
_ "k8s.io/publishing-bot/cmd/publishing-bot/config"
)
When working on a project, we often need tools for tasks like linting, testing, or code generation—tools like stringer
, protoc
, or golangci-lint
.
Managing these tools in a team can be tricky because people might have different versions installed. This can cause inconsistent outcomes and unexpected issues.
So, why not just add them to go.mod
? Well, as these tools aren’t directly used in your code, go mod
doesn’t recognise them as dependencies. When you run go mod tidy
, it removes them.
The Old Workaround: tools.go
Pattern
To deal with this, the hack was using a file called tools.go
. This file imports all tool dependencies using _
so that go.mod
treats them as dependencies.
install-tools: download
@echo Installing tools from tools.go
# Not a proper one as it doesn't install specific versions
@cat tools.go | grep _ | awk -F'"' '{print $$2}' | xargs -tI % go install %
|
The Go 1.24 Solution: tool
Directive
Go 1.24 introduces the tool
directive, which removes the need for the tools.go
hack. Now, you can directly define your tool dependencies in go.mod
.
Let’s say I want to install go.uber.org/mock/mockgen@latest to generate mock implementation of some interfaces.
🚀 1. Add and Manage Tool Dependencies
We can add mockgen tool dependency to our module using:
go1.24rc1 get -tool go.uber.org/mock/mockgen@latest
🛠️ 2. Run Tools Easily
Once a tool dependency is added, we can run it directly using the go tool
command:
go1.24rc1 tool mockgen
📋 3. List Available Tools
To see all tools currently available in our module, run: go tool
(base) ➜ go-124 go1.24rc1 tool
addr2line
asm
buildid
cgo
compile
covdata
cover
doc
fix
link
nm
objdump
pack
pprof
preprofile
test2json
trace
vet
go.uber.org/mock/mockgen
🔄 4. Update All Tools
You can update all tools in go.mod
with:
go1.24rc1 get -u tool
📦 5. Install All Tools
Install all tools to $GOBIN
directory using:
go install tool
This is just the tip of the iceberg when it comes to Go 1.24. There’s a lot more to explore, including a new map implementation using Swiss Table, the mlkem package for post-quantum cryptography, and the synctest package for testing concurrent code. I’ll be covering the rest in the upcoming posts.
If you don’t want to miss them, make sure to subscribe and get them straight to your inbox!
Reply