Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proposal: slices: add Push #64090

Open
mitioshi opened this issue Nov 13, 2023 · 1 comment
Open

proposal: slices: add Push #64090

mitioshi opened this issue Nov 13, 2023 · 1 comment
Labels
Milestone

Comments

@mitioshi
Copy link

Motivation:
Appending a new element to a slice is probably the most common slice operation.
The semantics of the append operator might lead to unwanted bugs due to the return parameter.
Consider the following code:

anotherSlice := append(existingSlice, ...entries)

When assigning to a variable different from the source slice, anotherSlice might or might not end up pointing to the same array as in existingSlice.
Since append is such a common operation in Go, it's very easy to miss this nuance and run into a strange bug with some elements "disappearing" from the slice due to another slice holding a pointer to the same array. This issue is very hard to debug.
While there is a linter in gocritic that tackles the exact same problem, it'd be more efficient to exclude this problem on the language level

Solution:
We can improve the situation by introducing a new function for "just appending" to the slice

func Push[S ~[]E, E any](src *S, newElements ...E) {
	*src = append(*src, newElements...)
}

Then, you can use it like this:

Push(&existingSlice, entries)

This solution has the following benefits:

  • With this API one cannot accidentally have two slices owning the same backing array(i.e. The user would have to explicitly declare a new slice, copy the content of existingSlice and only then append what they intended to)
  • works for any slice including nil slices
  • this doesn't break any backward compatibility since append is still available as an operator
  • Slice grow is hidden from the developer. Hence, one does not need to think about resource ownership with this API
@adonovan
Copy link
Member

Since append is such a common operation in Go, it's very easy to miss this nuance and run into a strange bug with some elements "disappearing" from the slice due to another slice holding a pointer to the same array. This issue is very hard to debug.

The compiler won't let you call append and discard the result, and the nature of append really is fundamental knowledge that every Go programmer must posses, so I wonder: how often is this a problem in practice? And if Push existed, how would anyone know to call it unless they were already aware of the problem it supposedly solves?

With this API one cannot accidentally have two slices owning the same backing array(i.e. The user would have to explicitly declare a new slice, copy the content of existingSlice and only then append what they intended to)

It doesn't really solve the general slice aliasing problem. y = x; Push(y, elem) still leaves x and y referring to (possibly) the same array.

Slice grow is hidden from the developer. Hence, one does not need to think about resource ownership with this API

How is that not also true for append?

@seankhliao seankhliao changed the title proposal: slices: Add Push proposal: slices: add Push Jan 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

3 participants