1. 2
  1. 4

    Never do this, it is too easy to mis-use, leading to things like deadlocks and spaghetti synchronization. Mutexes should always be unexported fields, accessed only by methods.

    Longer discussion here (warning: also Twitter thread).

    1. 2

      This is a good counter point. In this contrived example I’m only accessing the mutex inside the struct’s one add function, but I hadn’t considered that by embedding the mutex it effectively exports it since Lock and Unlock are available at the same level as add itself. Thanks.

      1. 3

        Updated the thread for others to discover this too.

    2. 2

      Seems like a bad idea. It’s an impl detail that callers should not be aware of.

      1. 1

        I don’t recommend doing this most of the time. Here’s why:

        1. Go has value types
        2. When you pass by value you get a shallow copy
        3. It’s an error to copy a sync.Mutex

        So if you embed a mutex in a struct (or make it a member field), you now have a precarious situation.

        1. 2

          go vet will catch that btw:

          $ cat main.go
          package main
          
          import "sync"
          
          type x struct { sync.Mutex }
          
          func main() { f(x{}) }
          
          func f(x) {}
          
          $ go vet main.go
          # command-line-arguments
          ./main.go:13:8: f passes lock by value: command-line-arguments.x
          

          You can embed it as a pointer: type x struct { *sync.Mutex }