3 ms·
Slices (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 a
by iainmerrick 4y ago
Slices (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).
- morelisp 4y agoGo slices cannot change the structure (len or cap) of their "parent" slice. (Unlike Java, the semantics of every operation are even well-defined.) In some sense this is the root of the problem - the "child" slice can start using spare capacity it 'inherited' with no way to tell the parent it has done so, and the parent may inadvertantly pass some of its length as capacity down to its child.
- iainmerrick 4y agoYou can't insert or remove elements, but you can overrun the buffer?? I have a hard time thinking of a situation when that would be useful at all, let alone useful enough to be the default and widely-used behaviour! If I want to let the callee add stuff to the end of my list, can't I just pass them the whole list and let them modify that?
- morelisp 4y agoYou cannot "overrun the buffer" nor can a callee add stuff to the end of your list; you can give them a memory buffer with unused space and they may use it, and then you can also mistakenly use it later. Honestly, you seem to be too detached to understand this. If you really want to know how it works go through some official Go documentation. It's not fundamentally different than some feature in other languages, it's just that in Go this is the default growable list type and in other languages it's usually a non-default type. As for whether it's ultimately useful - of course we can debate, but everyone still builds lists one element at a time and allocators still allocate by doubling, so there's at least one immediate and obvious use of capacity beyond the used length.