Thanks for your reply, Ian.
I've decided on using a []*Foo now. Just to clarify, however: In general, 
copying/assigning from a struct literal as in
a[i] = Foo{}, is that always safe for these sync types? Or generally, is 
copying their "untouched" zero-values always safe?

Antonio

On Sunday, August 27, 2023 at 7:05:15 PM UTC+2 Ian Lance Taylor wrote:

> On Sun, Aug 27, 2023 at 7:54 AM Antonio Caceres Cabrera
> <julioca...@gmail.com> wrote:
> >
> > Go vet complains about this minimal example code
> >
> > type Foo struct {
> > val atomic.Uint64
> > }
> >
> > func main() {
> > var foos = make([]Foo, 0)
> > var bar Foo
> > bar.val.Store(5)
> > foos = append(foos, bar) // call of append copies lock value: 
> example.com/foo.Foo contains sync/atomic.Uint64 contains 
> sync/atomic.noCopy
> >
> > }
> >
> > Because the types of the sync package are not supposed to be copied.
> > This is also true for sync.Map, sync.Mutex, sync.WaitGroup etc.
> >
> > However, if I instead copy in a zero-value Foo and then set that, go vet 
> does not complain, even if later appends are done:
> >
> > func main() {
> > var foos = make([]Foo, 0)
> > foos = append(foos, Foo{})
> > foos[0].val.Store(5)
> > foos = append(foos, Foo{})
> > foos = append(foos, Foo{})
> > // append some more
> > // ...
> > fmt.Println(foos)
> > }
> >
> > However, is this supposed to be safe, or is go vet just not catching it?
> > Even if copying a zero-value of such a type is safe, append() might have 
> to re-allocate the underlying array, which includes copying the existing 
> values, which might already have been used, as foo[0] has been in this 
> case. This would violate the noCopy trait of the type. My question is thus:
> >
> > Is it safe to keep nocopy types from the sync and sync.atomic packages 
> in a slice, given that they might internally be copied when the slice is 
> appended to?
> >
> > Of course, copying these types is not by itself atomic or synchronized 
> with other accesses. So let's assume that I, as the programmer, guarantee 
> that while an append happens, this slice will only be accessed by the one 
> appending goroutine, using other synchronization primitives, such as mutex, 
> channels etc. or by only running these appends in the main before any other 
> go-routine is started.
>
> Doing an append on a slice of types that contain atomic types is in
> general not safe and go vet is not catching it.
>
> If your program can guarantee that while the append is happening there
> is no concurrent access to the atomic types, then I think that is
> safe. It's not safe in general for all nocopy types, but it's safe
> for types like atomic.Uint64. It doesn't seem like a very clear way
> to write a program though. It may be better to use a slice of
> pointers: in your example, []*Foo. Or precount the size of the slice
> to ensure that append won't copy it.
>
> Ian
>

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/6ad297ba-19d4-4eaf-a2c2-252ca9db390cn%40googlegroups.com.

Reply via email to