Once generics are finally added the language should basically be a no-brainer for any serious production code.
Once generics are finally added the language should basically be a no-brainer for any serious production code.
a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]
Both seem harder than necessary.Is that code just idiomatic, and Go programmers recognize it instantly? Or maybe they don't deal with slices that often?
a = slices.Delete(a, i, i+1)
That said, in code I write, I rarely need to do an in-place delete from a slice. I think it's rare enough that recognizing the idiom is okay.Compare
strings.ToUpper(strings.Replace(strings.Trim(s), "a", "b")))
Instead of s.Trim().Replace("a, "b").ToUpper()It's "to avoid complicating questions about the interface (in the Go type sense) of basic types". It also allows separating the builtin functions, of which there are very few (they have to be in the core language spec), from the stdlib functions like strings.ToUpper, which there are many many more of and are added to more quickly than the builtins.
I didn't get the last point. builtin functions are there (for a big part) because the language doesn't have generics. Functions on types can be added without affecting the interface, since strings don't implement any interface (at least not on purpose, another problem with golang). Java constantly enriches standard library types with more useful methods.
You can restructure it if you don't need to preserve order:
a[i] = a[len(a)-1]
a = a[:len(a)-1]
In general* Go does not hide complexity from you. It's a blessing and a curse.*: because the Internet is a nitpicky place.
You might like the slices proposal for utility functions like these: https://github.com/golang/go/issues/45955
I'll admit freely that I'm not a proficient Go programmer, so it's easier for me to see the things I don't like than the things that Gophers praise. But even this solution leaves me unsatisfied, in contrast to what I'd reach for in Rust or even C++: it requires that I know that struct{} is zero-sized, and I still have to do the manual legwork of writing a CS101 dedupe function.
Like, if you tell Rust you want 4 million empty tuples in a vector, it will give you a vector with exactly 4 million empty tuples in it and no heap allocation because those empty tuples don't take space, so, 4 million of them also doesn't take up any space.
Because Rust has generics, it is more ergonomic though.
https://doc.rust-lang.org/std/collections/struct.HashSet.htm...
For every complain like that in Go I'll find a hundred in C++, ten in Java / JavaScript / Python.
As to your question, as a full-time Go programmer: this doesn't come up often.
When it does, I google "slice tricks" and copy & paste the formula.
It'll be fixed by next release because generics will enable writing a function that does that and that function will be in standard library.
Why wasn't this fixed before generics? Because the only way to do it would be via a compiler built-in function and Go team is rightfully reluctant to bloat the language / compiler for minor functionality like that.
It seems strange to not provide slice.erase as a primitive operation, and instead to recommend implementing it in terms of append. Usually removing from a vector does not require allocation. Still it may be for the best with upcoming generics, fewer builtins is good.
On the second glance, one can see why probably it was left out: there are two fundamental different ways to implement the deletion. You can copy the last element into the slot of the deleted element, or you can move all elements after the deleted one place to the left. The latter is what you implemented and preserves the ordering, which often is desirable. The former is way more efficient, if you don't need to preserve the order. A default implementation would probably choose to preserve the order and thus introduce a systematic inefficiency which is easy to be avoided.
Fortunately, with the introduction of generics and especially the new slice package, this discussion becomes moot.
For now you just have to accept these quirks as part of the tradeoff of working with the language. I don't find it that big of a deal esp with the solution on the horizon.
Have you ever had to remove elements from a list/slice?