Go Commentary #23: Draft Release Notes for Go 1.24 and weak pointers in Go
Draft Release Notes Go 1.24
Go 1.24 is not yet released. These are work-in-progress release notes. Go 1.24 is expected to be released in February 2025.
- Fully supports generic type aliases: a type alias may be parameterized like a defined type
type (
nodeList = []*Node // nodeList and []*Node are identical types
Polar = polar // Polar and polar denote identical types
)
=> Specs:
type set[P comparable] = map[P]bool
type A[P any] = P // illegal: P is a type parameter
=> the feature can be disabled by setting GOEXPERIMENT=noaliastypeparams
; but the aliastypeparams
setting will be removed for Go 1.25.
Some updates for tools
go tool
or-tool
flag, newtests
analyzer forgo vet
Some updates for Cgo, Runtime, Compiler, Linker, Bootstrap
Some updates for stdlibs:
The new
os.Root
type provides the ability to perform filesystem operations within a specific directory.The
os.OpenRoot
function opens a directory and returns anos.Root
. Methods onos.Root
operate within the directory and do not permit paths that refer to locations outside the directory, including ones that follow symbolic links out of the directory.os.Root.Open
opens a file for reading.os.Root.Create
creates a file.os.Root.OpenFile
is the generalized open call.os.Root.Mkdir
creates a directory.Some updates for
crypto
,hash
packageSome updates for
net/http
including support for HTTP/2 protocol settings inTransport
andServer
New implementation for
sync.Map
that will improve overall performance and resolve some long-standing issues
Weak Pointers in Go: Why They Matter Now
Definition:
A type of reference to an object that does not prevent the object from being garbage collected
=> weak
package:
type Pointer[T any] struct {
u unsafe.Pointer
}
// Make creates a weak pointer from a strong pointer to some value of type T.
func Make[T any](ptr *T) Pointer[T] {
//...
}
- If the memory they’re pointing to gets cleaned up, the weak pointer automatically becomes
nil
— so there’s no risk of accidentally pointing to freed memory => they are safe
type T struct {
a int
b int
}
func main() {
a := new(string)
println("original:", a)
// make a weak pointer
weakA := weak.Make(a)
runtime.GC()
// use weakA
strongA := weakA.Strong()
println("strong:", strongA, a)
runtime.GC()
// use weakA again
strongA = weakA.Strong()
println("strong:", strongA)
}
// Output:
// original: 0x1400010c670
// strong: 0x1400010c670 0x1400010c670
// strong: 0x0
- After the first garbage collection
runtime.GC()
, the weak pointer weakA still points to the memory because we’re still using the variable a in theprintln("strong:", strongA, a)
line. The memory can’t be cleaned up yet since it’s in use. - But when the second garbage collection runs, the strong reference (a) isn’t used anymore. That means the garbage collector can safely clean up the memory, leaving
weakA.Strong()
to returnnil
.
Use case
- Canonicalization maps, where you only want to keep one copy of a piece of data around
- Initial purpose is in internal packages, e.g:
unique
func main() {
h1 := unique.Make("Hello")
h2 := unique.Make("Hello")
w1 := unique.Make("World")
fmt.Println("h1:", h1)
fmt.Println("h2:", h2)
fmt.Println("w1:", w1)
fmt.Println("h1 == h2:", h1 == h2)
fmt.Println("h1 == w1:", h1 == w1)
}
// Output:
// h1: {0x14000090270}
// h2: {0x14000090270}
// w1: {0x14000090280}
// h1 == h2: true
// h1 == w1: false
How does it work
- Having a in-between tiny object (8bytes)
- This setup lets the garbage collector clean up weak pointers to a specific object all at once, efficiently:
- the collector only needs to set the pointer in the indirection object to nil (or 0x0). No need to go around updating each weak pointer individually.