Today at work, I needed a function in Go to remove duplicates from a slice, and thus wrote something like this using the generic-based slices package:
func removeDuplicates(s []mytype) []mytype {
slices.SortFunc(s, less)
slices.CompactFunc(s, eq)
return s
}
Can you spot the bug? Here are the prototypes of the two functions:
func SortFunc[E any](x []E, less func(a, b E) bool)
func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S
The first has no return value, while the second does, unused in our case, hence the bug. It's interesting to note that the go compiler is perfectly happy with this, and doesn't issue any warning: it was extraordinarily fun to pinpoint.
I reached out to Ian Lance Taylor who
implemented
those functions in 2021 and he pointed me to Go Slices: usage and internals
. Things indeed do become obvious once
looking at the implementation of
slice:
type slice struct {
array unsafe.Pointer
len int
cap int
}
Both slices.SortFunc and slices.CompactFunc are taking a slice as
parameter, and not a pointer to a slice, meaning that any changes to len and
cap will be local to the function.
Anyway, There is a proposal to require
return values to be explicitly used or ignored open since 2017, but it didn't
go anywhere for now. There is also another proposal
to make go vet better at highlighting error mishandling, as well as errcheck,
but those wouldn't really help in this case.