What does Go's cmp.Compare return, and which types can you call it on?
answer
- a three-way answer, not a bool
- minus one, zero, plus one
- the constraint lists ints, floats, string
- tilde means your named types count too
- structs and time.Time are outside it
basics
~10 scmp.Compare returns -1 if the first argument is less, 0 if they are equal, and +1 if it is greater. It accepts any cmp.Ordered type: integers, floats, strings, and named types built on them.
solid answer
~40 sThe signature is `func Compare[T cmp.Ordered](x, y T) int`, and it returns exactly one of three values: `-1`, `0`, `+1`. It is a generic function, so the comparison is the built-in `<` operator applied to the concrete type — no method, no interface, no boxing. `cmp.Ordered` is a constraint whose type set is every integer kind, `float32`, `float64` and `string`, each written with a `~` so a defined type such as `type Score float64` satisfies it too. `cmp.Less` is the same idea returning a `bool`. You reach for `cmp.Compare` when you need a single integer that expresses less/equal/greater — for example to chain tie-breaks through `cmp.Or`. Types whose order lives in a method, such as `time.Time`, are not in the set; those carry their own `Compare` method instead.
code
go · 4 linesfmt.Println(cmp.Compare(2, 10)) // -1
fmt.Println(cmp.Compare("b", "a")) // 1
fmt.Println(cmp.Compare(3.5, 3.5)) // 0
fmt.Println(cmp.Less(2, 10)) // truego deeper
Be ready to state the three possible results and name the kinds of types cmp.Ordered covers: integers, floats and string. Knowing cmp.Less is the bool-shaped twin is enough at this level.
Explain why the constraint is written with the tilde approximation, so your own named types work, and why a struct such as time.Time is excluded and carries its own Compare method instead.
Show you know when the three-way int actually earns its keep over a plain comparison operator: when the result has to be combined across keys, and when floating-point edge cases must be defined rather than left false.
Own the API consequence: constraining to cmp.Ordered gives the cheapest call site but closes the door on element types whose order lives in a method, and that door cannot be reopened without changing an exported signature.
## What the function is `cmp` is a very small standard-library package. It contains exactly four exported names: the constraint `cmp.Ordered`, and the functions `cmp.Compare`, `cmp.Less` and `cmp.Or`. The first three are about ordering; the fourth is about picking a first non-zero value. `cmp.Compare` has this shape: ```go func Compare[T cmp.Ordered](x, y T) int ``` It returns: - `-1` when `x` is less than `y` - `0` when `x` equals `y` - `+1` when `x` is greater than `y` Those are the only three values it can produce. It is not a C-style `strcmp` that returns "some negative number" such as the arithmetic difference — the documented result is exactly `-1`, `0` or `+1`, so it is safe to compare the result against those constants directly, though idiomatic Go tests `< 0`, `== 0`, `> 0`. ## What cmp.Ordered admits `cmp.Ordered` is a **constraint**, not an ordinary interface. Its type set is: - every signed integer kind: `int`, `int8`, `int16`, `int32`, `int64` - every unsigned integer kind: `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `uintptr` - both floating-point kinds: `float32`, `float64` - `string` Each element is written with the `~` approximation, so the set contains not only those predeclared types but every defined type whose *underlying* type is one of them. That means your own `type Score float64` or `type UserID int64` can be passed to `cmp.Compare` with no extra work. What is **not** in the set is just as important: `bool`, complex numbers, pointers, channels, arrays, structs, slices and maps. `time.Time` is a struct, so `cmp.Compare(t1, t2)` does not compile — `time.Time` supplies its own `Compare` method (and `Before`/`After`) for that job. A type that wants to be ordered by a helper constrained to `cmp.Ordered` has to *be* a number or a string underneath; it cannot opt in by declaring a method. Because `cmp.Ordered` contains type-set elements rather than methods, it can only be used as a type constraint. Writing `var x cmp.Ordered` is a compile error — there is no such interface value at run time. ## Why a constraint and not an interface The reason the ordering helpers in the standard library are generic over `cmp.Ordered` rather than taking a `Comparable` interface is that you cannot add a method to `int`. Methods can only be declared on types defined in your own package, so an interface-based ordering API would force every caller to wrap `int`, `string` and `float64` in a named type before it could sort them. A constraint sidesteps that entirely: the compiler instantiates the function for the concrete type and emits the machine comparison directly, with no interface value to allocate and no dynamic dispatch on the hot path. The price is that the set is closed. If your element ordering needs more than `<` — a struct sorted by two fields, a case-insensitive string order, a locale-aware collation — a constraint cannot express it, and the API has to accept a comparison function instead. ## cmp.Compare versus cmp.Less versus the < operator `cmp.Less[T cmp.Ordered](x, y T) bool` answers the same question as `x < y` for a bool-shaped caller. `cmp.Compare` answers it in one integer, which is what you want when the result must be *combined* — for example folding several keys into a single decision with `cmp.Or`, where a `0` from the first key means "undecided, look at the next key". For integers and strings, `cmp.Compare(x, y)` and the raw operators agree completely. For floating-point values they do not: `cmp.Compare` defines an order for NaN and for negative zero, while the bare `<` and `==` operators report false for every comparison involving a NaN. That difference is the whole reason the function exists rather than each caller writing three lines of `if`. ## A small example ```go cmp.Compare(2, 10) // -1 cmp.Compare("b", "a") // +1 cmp.Compare(3.5, 3.5) // 0 cmp.Less(2, 10) // true ``` Type inference picks `T` from the arguments, so you almost never write the type argument explicitly. Both arguments must have the same type: `cmp.Compare(1, "a")` does not compile, and neither does `cmp.Compare(int32(1), int64(1))` without a conversion.
- What does cmp.Less give you that cmp.Compare does not?`cmp.Less` returns a `bool`, which reads better inside an `if`. `cmp.Compare` returns an `int` so the answer can be combined — a `0` means "these keys are tied, consult the next one", which a `bool` cannot express. Both apply the same floating-point rules, so they never disagree.
- Why can't you call cmp.Compare on two time.Time values?`cmp.Ordered`'s type set is the integer kinds, `float32`, `float64` and `string`. `time.Time` is a struct, so it is not in the set and the call does not compile. Its ordering lives in methods instead: `time.Time.Compare` returns the same -1/0/+1, and `Before`/`After` return bools.
- Does cmp.Ordered accept a defined type such as type Score float64?Yes. Every element of the type set is written with the `~` approximation, which matches any type whose underlying type is that basic kind. So `Score`, `type UserID int64` and `type Name string` all satisfy `cmp.Ordered` without any declaration on your side.
- Can you declare a variable of type cmp.Ordered?No. `cmp.Ordered` is an interface that contains type-set elements rather than methods, and such interfaces may only be used as constraints. `var x cmp.Ordered` is a compile error; the type only exists to bound a type parameter, never to hold a value at run time.
saying these in an interview costs you the question
- Says cmp.Compare returns a bool
- Thinks it returns the arithmetic difference of the two values
- Believes cmp.Ordered includes structs such as time.Time
- Thinks the element type must declare a Compare method
- Assumes it works on numbers only, not on strings