Description
Update, May 17 2023: Current proposal at #59488 (comment).
(Edited to change the package from sort to cmp).
I propose adding a new package cmp, which will initially define the following:
// Ordered is a constraint that permits any ordered type: any type
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
type Ordered interface { ... }
// Min returns the smallest of a and b. If a and b are equal, Min returns a.
func Min[T Ordered](a, b T) T
// Max returns the largest of a and b., If a and b are equal, Max returns a.
func Max[T Ordered](a, b T) T
The Min
and Max
functions are trivial but are widely used. The standard library contains 14 versions of Min
and 7 versions of Max
(not counting math.Min
and math.Max
). With such wide usage it's worth providing versions in the standard library.
The Ordered
constraint is useful for Min
and Max
and also for sorting functions such as those in the x/exp/slices package. This would replace constraints.Ordered
in the x/exp/constraints package. GitHub code search reports that constraints.Ordered
appears in 2300 files in GitHub, so people do find it useful.
If we adopt this proposal, we would not add a constraints package to the standard library.
Ordered
, Min
, and Max
are related to comparing values. Therefore, a package cmp is a reasonable location for them. We could also add them to the existing package sort.
Possible other additions to a cmp package would be names for the values returned by bytes.Compare
and similar functions, such as cmp.Less
(-1
), cmp.Eq
(0
), and cmp.Greater
(1
). We could also add a function wrappers that reverses the sense of a less-than comparator, and one that reverses the sense of a byte.Compare
style comparator.
We should define how Min
and Max
treat NaN values when instantiated with a floating-point type. I propose that if the first argument is a NaN then it will be returned, otherwise if the second argument is a NaN then it will be returned, otherwise compare with <
. When comparing a negative zero and a positive zero, I propose that the first argument will be returned, as with equal values; that is both Min(0.0, math.Copysign(0.0, -1))
and Min(math.Copysign(0.0, -1), 0.0)
will return 0
.
Other languages
C++ puts std::min
and std::max
in <algorithm>
. Go's standard library doesn't have anything comparable. The C++ <algorithm>
header is a bit of a catch-all, including functions that Go has in sort
and container/heap
, and functions that Go might put into a possible iter
package in the future.
Java has Math.min
and Math.max
, which are overloaded functions that take double
, float
, int
, or long
arguments. Go already has math.Min
and math.Max
, but since Go doesn't have overloading they only take float64
arguments. Most functions in Go's match package are most naturally defined for floating-point values, so even generic versions of them might not take all ordered values. And math.Ordered
doesn't seem right.
Python has min
and max
builtin functions. There's no particular reasons to make these functions predeclared in Go, since we can write them directly in Go.
Rust has std::cmp::min
and std::cmp::max
. std::cmp
also has the Rust equivalents of comparable
and Ordered
, and some support for comparator functions. This offers some support for using a cmp package in Go. On the other hand Rust's standard library has slice/vector sorting, and has various sorted container types, but as far as I know (which isn't far) doesn't have a general purpose sorting algorithm like the one in Go's sort package.