4 ms·
So in other words, appending to a slice may overwrite data in the middle of a different slice?
by DougBTX 4y ago
So in other words, appending to a slice may overwrite data in the middle of a different slice?
- Groxx 4y agoYep. Depending on how the slice was constructed, not how it is used. Slices (largely) behave like this in most languages, Go's contribution is mostly that slices and append are ubiquitous, so pretty much every Go coder is exposed to it. Prior to generics, literally any alternative was so much more work they essentially haven't been used. That may change in the future now that we do have (very simplistic) generics, but only time will tell.
- iainmerrick 4y agoSlices (largely) behave like this in most languages Is that really the case? I can’t think of many languages that let you construct a view into the middle of array, pass that view as an argument to a function call, and allow that function to add new values into your array via the view. In Python or JS, for example, the “slice” would just be a brand new array, right?
- Groxx 4y agoIf the slice syntax creates a copy, I would argue that it's simply syntactic sugar for array copying, not actually producing a slice (i.e. there is no slice type). But yes, `somefunc(ary[1:])` in Python produces a copy, not a reference to the underlying value. You could build a more "true" slice class, but the builtin stuff doesn't do that. JavaScript is similar. Java however has `List<>.sublist` which largely behaves like Go: https://docs.oracle.com/javase/8/docs/api/java/util/List.html#subList-int-int- https://docs.oracle.com/javase/8/docs/api/java/util/List.htm... . Sometimes these kinds of things are also referred to as "views". Go calls them slices though, and this is a Go article. edit: C# apparently has "spans": https://learn.microsoft.com/en-us/archive/msdn-magazine/2018/january/csharp-all-about-span-exploring-a-new-net-mainstay https://learn.microsoft.com/en-us/archive/msdn-magazine/2018...
- klodolph 4y agoAnother example is typed arrays in JavaScript, which have both .slice() and .subarray(). One creates a copy, and one creates a new view into the same underlying memory.
- iainmerrick 4y agoYou can’t change the length of a JS ArrayBuffer, or write past the end of your view.
- morelisp 4y agoArrayBuffers have a byteLength and a maxByteLength and this is similar to Go's len and cap, with the `resize()` being equivalent to a reslice or append on the subview.
- iainmerrick 4y agoThe difference is that those operations are on the root ArrayBuffer in JS, not the TypedArray views on that buffer. In Go, the underlying array is fixed, and each slice independently has resize/reallocate operations. The JS approach seems better and more comprehensible to me. (I note also that MDN lists “resizable” and “maxByteLength” as new experimental features.)
- iainmerrick 4y agoIt doesn’t look like any of those allow you to arbitrarily add and remove elements from the parent list in the same way Go does (if I understand Go slices correctly). Java does let you make modifications, but only under very tight restrictions: The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.) I take that to mean the parent list can’t be modified at the same time, nor can multiple views be modified. So, I think Go’s ability to do those structural modifications on slices is rather unusual (as well as error-prone and not obviously useful).
- masklinn 4y ago> Slices (largely) behave like this in most languages Only on assignment, not in appending. > Go's contribution is mostly that slices and append are ubiquitous Go's contribution is the conflation of slices and vectors, which in most languages are separate (or really most languages only have the latter and don't provide access to backing arrays, thus precluding this specific confusion).
- klodolph 4y agoIn C++, until C++20’s std::span, you would just use std::vector for stuff you can modify and const std::vector for stuff you can’t. I think the real problem is that Go’s type system doesn’t catch the common error of keeping a reference to something you don’t own, or similar errors. C# catches some of these errors by letting you return a IReadOnlyList<T> or some other restricted type. Golang has ways to narrow certain types, but the slice type is primitive and has no narrowed read-only variation. C# instead forces you to pay a higher runtime cost, because you’re paying a lot more for indirection with IReadOnlyList<T>. People fret about the difference between T[] and List<T> in C#, and they do come with different performance characteristics… Go’s choice to use slices everywhere does have a certain advantage that you’re getting the fast path everywhere, and you’re spending less time thinking about which one to use. Not trying to say that Go is “right” here, it’s just my viewpoint that these language design decisions are rational.
- or10nx 4y ago> People fret about the difference between T[] and List<T> in C# That doesn't align with my experience. I've worker for small (4 programmers) and large (100s of programmers) C# shops, and I don't recall people "fretting" about T[] and List<T>. People see T[] as a non-growable, less useful version of List<T>. HashSet<T> vs List<T> seems to cause much more trouble for novice (and sometimes experienced) C# programmers.
- klodolph 4y agoI'm thinking more about the places where people care about performance, since accessing a T[] is faster than accessing a List<T> (less indirection).