On Sun, Aug 27, 2023 at 2:28 PM Antonio Caceres Cabrera <juliocacerc...@gmail.com> wrote: > > 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?
Yes, in general it's safe to copy the untouched zero value of these types. Ian > 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. -- 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/CAOyqgcUY9R%2Bm74Dzf4Z_Gp1BQ8eCRBNzrNW4xW1PEbQPfgK7pg%40mail.gmail.com.