Skip to content

cmp: new package with Ordered, Compare, Less; min, max as builtins #59488

Closed
@ianlancetaylor

Description

@ianlancetaylor

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions