Go

Do methods carry over with type B A vs type B = A vs embedding? What does this mean for sync.Mutex?

Question 105MediumGo 1.22 to 1.25

These are three different mechanisms:

  • Defined type type B A: B has the same underlying type as A but none of A's declared methods. (If A is an interface type, B has the same method set, because the methods are part of the interface's underlying type.)
  • Alias type B = A: B is just another name for the same type. It has all the methods and is fully interchangeable with A.
  • Embedding type B struct{ A }: B is a new type that promotes A's methods.
type MyMutex sync.Mutex
var m MyMutex
// m.Lock()                 // error: m.Lock undefined (type MyMutex has no field or method Lock)
(*sync.Mutex)(&m).Lock()    // works via conversion (same underlying type)

type AliasMutex = sync.Mutex
var a AliasMutex
a.Lock()                    // OK: identical type

type Guarded struct {
    sync.Mutex              // promotes Lock/Unlock (on *Guarded)
    data map[string]int
}
var g Guarded
g.Lock(); g.data = map[string]int{}; g.Unlock()

Dropping methods is a feature. It is how you break infinite recursion in custom MarshalJSON implementations:

func (u User) MarshalJSON() ([]byte, error) {
    type plain User // no MarshalJSON method -> no recursion
    return json.Marshal(struct {
        plain
        Kind string `json:"kind"`
    }{plain(u), "user"})
}

Caveat: embedding sync.Mutex in an exported struct also exports Lock and Unlock as part of your API. Prefer an unexported field such as mu sync.Mutex.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions