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.

Reply via email to