For a function, it makes sense to just write two functions, the easiest to use, and the one with maximum flaxibility.<p><pre><code> func SortOrdered[T constraints.Ordered](s []T) {
// …
}
func Sort[T any](s []T, less func(T, T) bool) {
// …
}
</code></pre>
For a data structure, I recommend using<p><pre><code> type SearchTree[T any] struct {
Less func(T, T) bool
// …
}
</code></pre>
and then writing two constructors<p><pre><code> func NewSearchTree(less func(T, T) bool) *SearchTree[T] {
// …
return &SearchTree[T]{
Less: less,
// …
}
}
func NewOrderedSearchTree[T constraints.Ordered]() *SearchTree[T] {
// …
return &SearchTree[T]{
Less: func(x, y T) bool {return x < y},
// …
}
}</code></pre>
Hrmm. How do float32 and float64 satisfy constraints.Ordered? The Go spec (which is almost uselessly vague and will some day contain 1000 pages of caveats) just says that floats are "comparable and ordered, as defined by the IEEE-754 standard" but of course that standard doesn't really say that, it specifically says that NaN are unordered. I just checked quickly with Compiler Explorer and float32<float32 emits UCOMISS on x86, which makes sense, resulting in 42.0<NaN and NaN<42.0 both being false, as expected. So how does it handle the constraint for float?
Nice write-up and summary. The emoji chart would be easier to visually parse with more traditional symbols e.g. [I realize these Unicode symbols could also be considered emoji but are less emotional.]
I don't program in Go. But I could imagine that I might at some point want to sort a list of a custom struct by one of its members. And that's probably as advanced as it would get for my purposes.
Imagine looking at a Garbage Collected language that isn't even a complete language (You just got generics, FFS) and thinking, "Yeah, this is a great idea!"