Private doesn’t mean undiscoverable

When you try to print a structure in Go with the Sprint or Println family of operations it will check to see if it’s a Formatter or Stringer and usually use those methods, otherwise it will use reflection to invent a way to print the structure. You can inspect the conditions for when is uses Formatter or Stringer inside print.go.

This particular code stumped me because I kept looking at Stats{} and thinking there’s no way that is a race. I keep prev private and never reference it. However, with Go, you can use reflection to inspect private variables. This inspection created the read operation that caused a race condition to trigger. This is very reasonable, especially since you can trigger a read of private variables even without reflection by taking the value of a structure

s := Stats{}

q := s // Will read stats to make a copy inside q

Thankfully, we can’t use reflection to set a private variable. See Value.CanSet for a description of when you can and cannot.

The moral of this little trivia is to remember that private variables can cause read -race errors, via copy and reflection, even if looking at the struct itself it appears safe.