-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Consider this program:
package main
import (
"fmt"
)
type Pointer struct{}
func (d *Pointer) IsNil() bool {
return d == nil
}
type Danger struct {
Pointer
}
func main() {
var d *Danger
fmt.Println(d.IsNil())
}
If a struct type embeds another struct type with pointer methods, the pointer method set of the outer struct (*Danger
in this example) includes the pointer methods of the embedded value.
However, calling these embedded methods is dangerous: the mere act of computing the address of the receiver results in a nil panic (see https://play.golang.org/p/jfrCruVC6l). (You can more clearly see that the panic occurs when computing the receiver address by using a method expression instead of actually calling the method: https://play.golang.org/p/629rZ7rs6l.)
This somewhat limits the usefulness of embedding for composition, as the caller must either know the concrete type in which the struct is embedded (https://play.golang.org/p/3ciUa4kiOQ) or use reflection to check whether the concrete pointer is nil before making the call (https://play.golang.org/p/zGDh6Hk5U9).
This style of embedding could be made significantly more useful by defining pointer methods on embedded structs to receive nil
if the pointer to the struct in which they are embedded is nil
.
Specifically, I propose to add the following sentence to https://golang.org/ref/spec#Struct_types:
- If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T. Evaluating a call or method value of a promoted method with a nil *S receiver evaluates the corresponding *T method with a nil *T.
The spec is currently a bit vague on the exact semantics of calls to methods obtained by embedding. This proposal certainly represents a change to the language as implemented, but it is not obvious to me whether it is a "language change" in the Go 1 compatibility sense or merely a spec clarification.