So, I don't want to tear too much into someone's side project, but a lot of this is exactly what people are worried about.
As an example, let's take the `Chunk` function, since that's something I know I have three implementations that differ only in type in one project, pre-generics:
result := make([][]T, 0, len(collection)/2+1)
length := len(collection)
len(collection)/2? If you're splitting a list of size M into N chunks, you know exactly how many chunks you need a priori, and it's not M/2+1.
for i := 0; i < length; i++ {
chunk := i / size
if i%size == 0 {
result = append(result, make([]T, 0, size))
}
But worse: You allocated a whole new slice to store the chunk! What a waste.
But, you know, the real frustrating thing in the end is that it allocated anything at all. Chunking can also happen iteratively on the source slice:
func [T any]([]T, int) (chunk []T, remaining []T)
And then it will be zero-alloc.
But, once you see this, you see we could write something that works on indices:
func (len int, size int) (split int)
And get nearly the same effect, without any generics.
Go < 1.18 forces you to factor down to the last one if you're pursing highly abstract code (or you write it inline if you're not, and it's as fast). It's not pretty, and you need one more line of boilerplate to slice the slice, but it is fast. Go 1.18 has a nicer option that gets rid of the line of boilerplate, but it's no longer the easiest solution to reach for.
(See also my comments at https://news.ycombinator.com/item?id=29905908#29926708 - just because you have a generic type doesn't mean you should use it as much as possible, even if you do need to use it once.)
I'm happy to see generics in golang. It will simplify a ton of my higher-level code like REST endpoints, and be a minor boon to low-level code. But this library, as useful as some parts may be, is also a great example of why they're a dangerous tool.