You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Append can't concatenate multiple slices. This means you need to jump through hoops to precalculate the capacity and to make a one-liner you end up with awkward things like append(s1, append(s2, s3...)...).
Reacted by DeedleFake, xiaokentrl, zigo101, Leigh and Alex Glukhovtsev
@carlmjohnson I don't think it should use cap as that could greatly overestimate the size requirement. For example, slices.Concat(nil, make([]int, 0, 1000)) should not grow the dest to 1000 elements.
I think at a certain point, if the user is clobbering the slice they are reading from, it's a user error. You can probably make up an example using slices.Insert that is confusing too.
@carlmjohnson It would be all too easy for someone not to realize that the first parameter is special in that regard, especially because it isn't in other languages that have similar APIs. And due to the nature of append/slices.Grow it will sometimes appear to work the way they expect, meaning they might not even notice the problem until it causes some production incident.
What if it were a method instead of a function, to reinforce the fact that the first parameter is actually the output buffer?
The objection to destination slices already applies to several functions in exp/slices: Insert, Delete, the upcoming Replace, and arguably Grow and Clip (although not as confusing as the others). If you think it's causing bugs, you should open an issue to make a v2 of the package before the current slices API gets into the standard library.
Regardless, adding a typedef with methods does not itself necessitate a v2. It just means some (or all) of the existing functions would presumably be deprecated.
I feel like two versions of concatenation could make sense - a minimally complicated, more variadic 'Append'-like concatenation, and a profligately eager, maximally allocating 'Collect'-ing concatenation: https://go.dev/play/p/13N05VZPjwS
If it used make there, the capacity would be exactly the combined size of the slices, but we want it to be rounded up to the next size class, so people don't rely on len(s) == cap(s) being true, and box ourselves into a corner.
Still not quite following, what do we mean by rounded up to the next size class? Do we mean:
@earthboundkid
I also don't quite understand why slices.Grow should be used instead of make in this case. I tested it with Go 1.22 using the link you provided, and contrary to what the post claims, this code does not allocate memory.
Therefore, I believe that this post is no longer valid.
In this case, make seems to be superior in terms of performance, and there doesn't seem to be a significant difference in readability either. Can you explain in more detail why slices.Grow should be used in this scenario please?
This is a closed issue. Your benchmark is invalid because sort.Strings isn't relevant to slices.Concat and the slice is sorted after the first loop. If you can make a change with better performance, submit the change with a benchmark from benchstat.
@OhJuhun
It looks the APIs in the slices package try to round up memory size to the next class size, except strings.Repeat. Honestly, I don't understand the cause of the inconsistency.
The current design of the slices package lacks of custom configurations:
whether or not round up to the next memory class size.
whether or not zero freed-up elements (in Delete, Replace and Compact etc)
whether or not keep element order (such as in Delete)
...
Because of these facts, the slices package doesn't satisfy the needs of all cases.
So sometimes, you might need to write your own implementations.
Activity
rittneje commentedon Oct 20, 2022
What is the value of
c? Depending on the order of events weird things could happen.For example, consider the following (perhaps naive) implementation:
This will result in
cbeing[1 2 4 4]which is probably unexpected.ericlagergren commentedon Oct 20, 2022
Isn't
appendalready generic?earthboundkid commentedon Oct 20, 2022
Append can't concatenate multiple slices. This means you need to jump through hoops to precalculate the capacity and to make a one-liner you end up with awkward things like
append(s1, append(s2, s3...)...).earthboundkid commentedon Oct 20, 2022
I think it's only worth doing Concat if it does one shot preallocation, like
If you run this, you get 1, 2, 4, 3.
rittneje commentedon Oct 20, 2022
@carlmjohnson I don't think it should use
capas that could greatly overestimate the size requirement. For example,slices.Concat(nil, make([]int, 0, 1000))should not grow the dest to 1000 elements.Really it should be
len, but that still causes problems. https://go.dev/play/p/zb1d-MhD6Pjearthboundkid commentedon Oct 21, 2022
😅 You're right!
earthboundkid commentedon Oct 21, 2022
I think at a certain point, if the user is clobbering the slice they are reading from, it's a user error. You can probably make up an example using slices.Insert that is confusing too.
rittneje commentedon Oct 22, 2022
@carlmjohnson It would be all too easy for someone not to realize that the first parameter is special in that regard, especially because it isn't in other languages that have similar APIs. And due to the nature of
append/slices.Growit will sometimes appear to work the way they expect, meaning they might not even notice the problem until it causes some production incident.What if it were a method instead of a function, to reinforce the fact that the first parameter is actually the output buffer?
(This type name is just for example purposes.)
Then it would be
slices.Buffer[int](a).Concat(b, c). For people who don't care to optimize it, they can callslices.Buffer[int](nil).Concat(a, b, c).earthboundkid commentedon Oct 22, 2022
The objection to destination slices already applies to several functions in exp/slices: Insert, Delete, the upcoming Replace, and arguably Grow and Clip (although not as confusing as the others). If you think it's causing bugs, you should open an issue to make a v2 of the package before the current slices API gets into the standard library.
rittneje commentedon Oct 22, 2022
Yes, it is possible to break them, but it is a bit more contrived. https://go.dev/play/p/4lLBHhxrfdN
Regardless, adding a typedef with methods does not itself necessitate a v2. It just means some (or all) of the existing functions would presumably be deprecated.
AndrewHarrisSPU commentedon Oct 23, 2022
I feel like two versions of concatenation could make sense - a minimally complicated, more variadic 'Append'-like concatenation, and a profligately eager, maximally allocating 'Collect'-ing concatenation:
https://go.dev/play/p/13N05VZPjwS
49 remaining items
zigo101 commentedon Sep 1, 2023
It is impossible to write normal benchmarks without hacking the runtime code. Someone ever hacked it.
There is no need to create a new issue.
slices: add Concat
slices: add Concat
slices: add Concat
slices: add Concat
justinhwang commentedon Feb 22, 2024
@ianlancetaylor / @earthboundkid could one of you elaborate on what this comment means and why we shouldn't be using
makehere?https://go-review.googlesource.com/c/go/+/504882/3..6/src/slices/slices.go#b510
earthboundkid commentedon Feb 22, 2024
justinhwang commentedon Feb 23, 2024
Still not quite following, what do we mean by rounded up to the next size class? Do we mean:
earthboundkid commentedon Feb 23, 2024
OhJuhun commentedon Jul 15, 2024
@earthboundkid
I also don't quite understand why slices.Grow should be used instead of make in this case. I tested it with Go 1.22 using the link you provided, and contrary to what the post claims, this code does not allocate memory.
Therefore, I believe that this post is no longer valid.
In this case, make seems to be superior in terms of performance, and there doesn't seem to be a significant difference in readability either. Can you explain in more detail why slices.Grow should be used in this scenario please?
earthboundkid commentedon Jul 15, 2024
This is a closed issue. Your benchmark is invalid because sort.Strings isn't relevant to slices.Concat and the slice is sorted after the first loop. If you can make a change with better performance, submit the change with a benchmark from benchstat.
zigo101 commentedon Jul 16, 2024
@OhJuhun
It looks the APIs in the
slicespackage try to round up memory size to the next class size, exceptstrings.Repeat. Honestly, I don't understand the cause of the inconsistency.The current design of the
slicespackage lacks of custom configurations:Delete,ReplaceandCompactetc)Delete)Because of these facts, the
slicespackage doesn't satisfy the needs of all cases.So sometimes, you might need to write your own implementations.