Go

Why would you embed an interface inside a struct? What is the danger?

Question 91HardGo 1.22 to 1.25

Embedding an interface in a struct makes the struct satisfy the interface automatically. You then override only the methods you care about, and all the others delegate to the wrapped value. This is the standard decorator pattern in Go:

// Capture the status code of an http.ResponseWriter
type statusRecorder struct {
    http.ResponseWriter // all methods promoted
    status int
}

func (r *statusRecorder) WriteHeader(code int) {
    r.status = code
    r.ResponseWriter.WriteHeader(code)
}

// stdlib example: sort.Reverse
type reverse struct{ sort.Interface }
func (r reverse) Less(i, j int) bool { return r.Interface.Less(j, i) }

// Test fake implementing only what the test needs
type fakeStore struct {
    Store // nil; any un-overridden call panics
}
func (fakeStore) Get(id string) (string, error) { return "x", nil }

The dangers:

  1. If the embedded interface is nil, calling any method you did not override panics with a nil pointer dereference at runtime. The compiler cannot catch it. That is fine for a deliberately partial test fake and dangerous in production.
  2. The wrapper hides optional interfaces of the inner value. statusRecorder no longer satisfies http.Flusher or http.Hijacker, even when the underlying writer did. Go 1.20's http.ResponseController works around this when the wrapper has an Unwrap() http.ResponseWriter method.

More on Interfaces, Methods & Embedding

All 35 Interfaces, Methods & Embedding questions