Exploring the New Unique Package in Go 1.23
The Go programming language continues to improve, bringing new features aimed at enhancing performance and developer productivity. One of the notable additions in Go 1.23 is the introduction of the unique
package, which provides a facility for interning values—a technique with a long history in computer science. Let’s explore what interning is and why it might be beneficial.
If you want to learn more about Go 1.23, you can find the release notes here and our free video course on important changes here.
What is Interning?
Interning is a technique that originated in the Lisp programming language. It involves storing only one copy of a value in memory and sharing references to that single copy. This approach can reduce memory usage by avoiding the allocation of multiple identical values. In practical terms, this means that if you have several instances of the same string or other comparable values, they will all point to the same memory location.
For example, consider the following Go code snippet:
str1 := "bytesizego.com"
str2 := "bytesizego.com"
In this case, both str1
and str2
store the same string. With interning, Go ensures that these two variables reference the same memory address, thereby conserving memory. The Go compiler already performs interning on string constants at compile time, but the unique
package extends this capability to runtime values.
Context & Implementation
Before Go 1.23, developers relied on third-party packages or built their own solutions for interning runtime values. The unique
package in Go 1.23 provides a standardized and optimized approach. At its core, the unique
package introduces the Make
type, which guarantees a globally unique identity for any comparable value. Two Make
instances compare as equal if the values used to create them are equal. Internally, the Make
type is backed by a concurrent-safe map, ensuring thread-safe operations.
Using the Unique Package
The following example is adapted from Joseph Woodward’s blog post on the unique
package.
package main
import (
"unique"
)
type addrDetail struct {
isV6 bool
zoneV6 string
}
func main() {
h1 := unique.Make(addrDetail{isV6: true, zoneV6: "2001:0db8:0001:0000:0000:0ab9:C0A8:0102"})
// This addrDetail won't be allocated as it already exists in the underlying map
h2 := unique.Make(addrDetail{isV6: true, zoneV6: "2001:0db8:0001:0000:0000:0ab9:C0A8:0102"})
if h1 == h2 {
println("addresses are equal")
}
// Value() returns a copy of the underlying value (i.e., different memory address)
println(h1.Value().zoneV6)
}
In this example, h1
and h2
are created using the Make
function. When h1 == h2
is evaluated, it returns true
, indicating that both handles reference the same interned value.
Does This Have a Performance Impact?
The benefits of interning are especially noticeable in memory allocation and comparison speed. By reducing memory allocation and enabling faster comparisons, interning can lead to significant performance improvements. Benchmarks show that the time complexity of operations remains consistently low, regardless of the size of the interned values, making the unique
package an attractive option for memory-intensive applications.
When Should I Use the Unique Package?
While the unique
package offers advantages, it is essential to use it judiciously. For most applications, interning may not be necessary. However, in scenarios where memory is a critical resource, or where ensuring identical instances is important, the unique
package can be highly beneficial. It’s best used as an optimization tool rather than a default approach.
Wrapping Up
The unique
package in Go 1.23 is a valuable addition to the language, providing a standardized mechanism for interning runtime values and enhancing memory efficiency and performance. Although this feature may not be essential for all applications, it’s a helpful optimization tool for memory-intensive use cases.
Special thanks to Joseph Woodward for his insightful blog post on this topic, which offers a clear explanation of the unique
package and its practical applications.
If you found this helpful, consider following Joseph for more in-depth content on Go and its evolving features.