Golang Release 1.21: cmp

- 4 minutes read - 784 words

New package in Go standard library that makes easier to compare ordered types.

As the new release of Go came this summer, many of us started to look for the improvements inside its ecosystem. Many new features were introduced, including updates to the tool command to support backward and forward compatibility. New packages appeared inside the Standard Library, including maps and slices. In this article we are covering improvements introduced with the new cmp package.

The new package offers three new functions. All of them rely on Generics, a feature introduced in Go version 1.18, which has opened up possibilities for many new features. The cmp package introduces new functions for comparing values of Ordered constraint.

Let’s dive into each of them.

Ordered constraint and Compare function

The constraint Ordered encompasses all types that support comparison operators for values, specifically, <, <=, >= and >. This includes all numeric types in Go, as well as strings.

Ordered Constraint

type Ordered interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
		~float32 | ~float64 |
		~string
}

Once we understand what the Ordered constraint includes, we can focus on the first function from the cmp package, which is the Compare function. Below, you can find its signature:

Compare Function

// Compare returns
//
//	-1 if x is less than y,
//	 0 if x equals y,
//	+1 if x is greater than y.
// ...
func Compare[T Ordered](x, y T) int

The signature, along with the function description, makes it much easier to understand. The Compare function expects two arguments of the same type, compares their values, and returns a result that represents the comparison status:

  • -1 if the first argument is less than the second.
  • 0 if the arguments’ values are equal.
  • 1 if the first argument is greater than the second.

Let’s prove such claim:

Compare numerals

fmt.Println(cmp.Compare(1, 2))
// Output:
// -1
fmt.Println(cmp.Compare(1, 1))
// Output:
// 0
fmt.Println(cmp.Compare(2, 1))
// Output:
// 1

Compare strings

fmt.Println(cmp.Compare("abc", "def"))
// Output:
// -1
fmt.Println(cmp.Compare("qwe", "qwe"))
// Output:
// 0
fmt.Println(cmp.Compare("abcde", "abcc"))
// Output:
// 1

Above, we can see practical examples of the Compare function for both numerals and strings. Indeed, the return values can only belong to the set of numbers {-1, 0, 1}, as defined in the description.

Function Less

In addition to the function Compare, we got another, similar function Less. Although it’s rather easy to understand what is used for, let’s check its signature:

Function Less

func Less[T Ordered](x, y T) bool

Again, this method expects two arguments of the same type that must adhere to the Ordered constraint. It returns the boolean value true if the first argument is less than the second one.

Less function with numerals

fmt.Println(cmp.Compare(1, 2))
// Output:
// -1
fmt.Println(cmp.Compare(1, 1))
// Output:
// 0
fmt.Println(cmp.Compare(2, 1))
// Output:
// 1

Less function with strings

fmt.Println(cmp.Less("abc", "def"))
// Output:
// true
fmt.Println(cmp.Less("qwe", "qwe"))
// Output:
// false
fmt.Println(cmp.Less("abcde", "abcc"))
// Output:
// false

Bonus: functions min and max

In addition to the functions mentioned in the cmp package, the new Go release introduced two new built-in functions: min and max. They are also based on Generics and can be used without importing any package, just like other built-in functions. Below, you can find their signatures:

Min function

func min[T cmp.Ordered](x T, y ...T) T

Max function

func max[T cmp.Ordered](x T, y ...T) T

Both min and max functions are variadic functions, and they expect at least one argument. As you can see, only the x argument of type T is required, and the y argument is a trailing argument that can accept many or no values of the same type T. The result of these functions is a single value of the same type T, representing the minimum or maximum of all the values. Let’s check some examples:

Examples with numerals

fmt.Println(min(1, 2, 3))
// Output:
// 1
fmt.Println(max(1, 2, 3))
// Output:
// 3

fmt.Println(min(1))
// Output:
// 1
fmt.Println(max(1))
// Output:
// 1

Examples with strings

fmt.Println(min("abc", "def"))
// Output:
// abc
fmt.Println(max("abc", "def"))
// Output:
// def

fmt.Println(min("qwe", "qwe", "qwe"))
// Output:
// qwe
fmt.Println(max("qwe"))
// Output:
// qwe

In all the examples above, we can see how the new functions behave in various situations. This includes their normal behavior with only one argument, as well as when more than two arguments are provided.

Conclusion

New version of Golang, 1.21, delivered many new updates, affecting standard library as well. In this article we checked how functions from cmp packages work. Those new methods give us now possibility to easily compare any ordered types in Go.

Useful Resources

comments powered by Disqus