|
In my testing [1] that doesn't eliminate bound checks. Instead, it avoids a computation of otherwise unused `cap(a[i:i+4]) = len(a) - i` value if my reading is correct. [1] https://go.godbolt.org/z/63n6hTGGq (original) vs. https://go.godbolt.org/z/YYPrzjxP5 (capacity not limited) > Well I had never seen that "full slice" expression syntax before. Go's notion of capacity is somewhat pragmatic but at the same time confusing as well. I learned the hard way that the excess capacity is always available for the sake of optimization: a := []int{1, 2, 3, 4, 5}
lo, hi := a[:2], a[2:]
lo = append(lo, 6, 7, 8) // Oops, it tries to reuse `lo[2:5]`!
fmt.Printf("%v %v\n", lo, hi) // Prints `[1 2 6 7 8] [6 7 8]`
While I do understand the rationale, it is too unintuitive because there is no indication of the excess capacity in this code. I would prefer `a[x:y]` to be a shorthand for `a[x:y:y]` instead. The `a[x:y:len(a)]` case is of course useful though, so maybe a different shorthand like `a[x:y:$]` can be added. |
Slices encapsulate an ubiquitous C pattern, where you pass to a function: a pointer (to an initial array element), and a length or capacity (sometimes both). This pattern is directly encapsulated by Go's slices, which can be thought of as something like:
I love Go's slice syntax. It's the right piece of syntactic sugar. It removes tedium and room-for-mistakes from this prevalent C pattern. It lets me work as precisely with memory as I do in C, yet everything is simpler, lighter, and breezier.For example, I'm making a game in Go. I don't want to be allocating memory throughout the game (which can cause frame drops), so instead I allocate giant arrays of memory on launch. Then I use slices to partition this memory as needed.
Some of these arrays get their elements re-accumulated at some interval (every level, or every frame, etc.). And so it works nicely to first set them to zero length:
Notice that the myMem slice now has zero length, but still points to its same underlying array. Then I perform the accumulation: Again, I don't want to be allocating in general, so I care very much that append continues to use myMem's preexisting capacity.All this is to say, I don't see slices as being the way they are for the "sake of optimization." Rather I see them as an ideal tool for working with, referring to, and partitioning memory.