Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Golang: Why selector to pointers is illegal after comparison?

I'm reading the spec about selectors: https://golang.org/ref/spec#Selectors

enter image description here

Why q.M0() is invalid. While p.M0() is valid and q=p. Very strange for me.

The relevant source code:

type T0 struct {
    x int
}

func (*T0) M0()

type T1 struct {
    y int
}

func (T1) M1()

type T2 struct {
    z int
    T1
    *T0
}

func (*T2) M2()

type Q *T2

var t T2     // with t.T0 != nil
var p *T2    // with p != nil and (*p).T0 != nil
var q Q = p

p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
q.M0()       // (*q).M0 is valid but not a field selector
like image 984
Aminadav Glickshtein Avatar asked Nov 25 '16 11:11

Aminadav Glickshtein


1 Answers

Why q.M0() is invalid. While p.M0() is valid and q=p. Very strange for me.

q is initialized like var q Q = p, but it does not mean they are equal. The assignment is valid because it does not violate the assignability rules, but type of q is different than type of p.

Type of q is Q (where type Q *T2), and type of p is *T2.

In Go, methods belong to a specific type. When you do this:

type Q *T2

It creates a new type named Q (*T2 being its underlying type). The new type will have 0 methods, it does not "inherit" any methods from *T2, hence q.M0() will be a compile-time error:

q.M0 undefined (type Q has no field or method M0)

Note:

You may still think it's strange because M0() is declared like this:

func (*T0) M0()

It has *T0 receiver so it belongs to the type *T0, yet type of p is *T2, so *T2 should not have this M0() method and therefore p.M0() should also be invalid. But T2 is a struct which embeds *T0, and so methods of *T0 are promoted, and they will be in the method set of T2.

Also see this related question: Golang: Why selector to pointers is illegal after comparison?

like image 173
icza Avatar answered Sep 27 '22 19:09

icza