26

I am having a hard time understanding as to why are these rules associated with method set of pointer type .vs. value type

Can someone please explain the reason (from the interface table perspective)

(Snippet from William Kennedy's blog)

Values          Methods Receivers
-----------------------------------------------
T               (t T)
*T              (t T) and (t *T)

Methods Receivers    Values
-----------------------------------------------
(t T)                 T and *T
(t *T)                *T

Snippet from specification

Method sets

A type may have a method set associated with it. The method set of an interface type is its interface. The method set of any other type T consists of all methods declared with receiver type T. The method set of the corresponding pointer type *T is the set of all methods declared with receiver *T or T (that is, it also contains the method set of T). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name.

The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
user2780187
  • 677
  • 7
  • 16
  • 3
    Related: http://stackoverflow.com/questions/19433050/go-methods-sets-calling-method-for-pointer-type-t-with-receiver-t?rq=1 – hobbs Nov 08 '15 at 06:30

3 Answers3

49
  1. If you have a *T you can call methods that have a receiver type of *T as well as methods that have a receiver type of T (the passage you quoted, Method Sets).
  2. If you have a T and it is addressable you can call methods that have a receiver type of *T as well as methods that have a receiver type of T, because the method call t.Meth() will be equivalent to (&t).Meth() (Calls).
  3. If you have a T and it isn't addressable (for instance, the result of a function call, or the result of indexing into a map), Go can't get a pointer to it, so you can only call methods that have a receiver type of T, not *T.
  4. If you have an interface I, and some or all of the methods in I's method set are provided by methods with a receiver of *T (with the remainder being provided by methods with a receiver of T), then *T satisfies the interface I, but T doesn't. That is because *T's method set includes T's, but not the other way around (back to the first point again).

In short, you can mix and match methods with value receivers and methods with pointer receivers, and use them with variables containing values and pointers, without worrying about which is which. Both will work, and the syntax is the same. However, if methods with pointer receivers are needed to satisfy an interface, then only a pointer will be assignable to the interface — a value won't be valid.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • 3
    Thanks for the crystal clear explanation. Wish the documentation carried this amount of clarity – user2780187 Nov 08 '15 at 18:00
  • I agree with @user2780187. I have a question @hobbs, on point#3 from your answer. What could be an example of `T` that is not "addressable", and because of that we cannot call its methods with pointer receiver `*T`. From your reference link to another stackoverflow question I found one example, ie return value. But wondering if there are any other examples. – srini Dec 22 '16 at 12:50
  • 1
    @srini calculateArea(42) is not addressable – Tallboy Aug 17 '19 at 19:57
  • @srini Most anonymous values. There's a good description of that here: https://utcc.utoronto.ca/~cks/space/blog/programming/GoUnaddressableSlice – itsbruce Sep 09 '21 at 01:19
  • Great answer. Just one point: in 4, *"back to the first point again"* is not right, because 1 and 2 have nothing to do with 4. Actually, 1 and 2 are just for programmer's convenience, like a syntactic sugar. In contrast, the feature described in 4 is not related to convenience. – starriet Apr 14 '22 at 17:30
  • @starriet not true. Point 1 is about method sets. Method sets are 100% what defines whether an interface is implemented or not. Point 2 is a pure bit of sugar, but #1 is at the heart of the language. – hobbs Oct 10 '22 at 23:58
7

From Golang FAQ:

As the Go specification says, the method set of a type T consists of all methods with receiver type T, while that of the corresponding pointer type *T consists of all methods with receiver *T or T. That means the method set of *T includes that of T, but not the reverse.

This distinction arises because if an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, there is no safe way for a method call to obtain a pointer. (Doing so would allow a method to modify the contents of the value inside the interface, which is not permitted by the language specification.)

Even in cases where the compiler could take the address of a value to pass to the method, if the method modifies the value the changes will be lost in the caller. As an example, if the Write method of bytes.Buffer used a value receiver rather than a pointer, this code:

var buf bytes.Buffer
io.Copy(buf, os.Stdin)

would copy standard input into a copy of buf, not into buf itself. This is almost never the desired behavior.

About Golang interface under the hood.

meefer
  • 43
  • 2
  • 4
Dan Super
  • 83
  • 1
  • 4
  • I find this reference great, because it gives one level deeper explanation than standard one about Method Sets. Key to the real question about why method sets are designed in this way is "Doing so would allow a method to modify the contents of the value inside the interface, which is not permitted by the language specification". But I can't find this particular prohibition in the language specification. Can one point it? – agronskiy Mar 31 '21 at 20:18
  • yeah, this FAQ is great since it mentions *"why"* it's like that. But, the author seems to have made a mistake and expressed his/her thoughts a little wrong. For instance, the description of the last `io.Copy` example does not correspond to the context (it is supposed to be "pointer receiver", to match the preceding context). But anyways the readers can get the idea. – starriet Apr 15 '22 at 07:46
0

-In go when we have a type we can attach methods on it, those methods attached to type are known as its method set.

  • Depending on Pointer or not pointer value , it will determine which method attach to it.

Case:1 Receiver (t T) Value T => https://go.dev/play/p/_agcEVFaySx

type square struct { 
    length int
}

type shape interface { shape as an interface
    area() int
}
// receiver(t T)
func (sq square) area() int { 
    return sq.length * sq.length
}

func describe(s shape) {
    fmt.Println("area", s.area())
}

func main() {
    sq := square{
        length: 5,
    }
    describe(sq)// value `sq` (T)
}

Case 2: Receiver (t T) Value T

// receiver(t *T)
func (sq *square) area() int { 
    return sq.length * sq.length
}

func main() {
    describe(sq)// value sq (T)
}

Case 4: Receiver (t *T) Value T

// receiver(t *T)
func (sq *square) area() int { 
    return sq.length * sq.length
}

func main() {
    describe(&sq)// value sq (*T)
}

Case 4: Receiver (t *T) Value T this case fails

// receiver(t *T)
func (sq *square) area() int { 
    return sq.length * sq.length
}

func main() {
    describe(&sq)// value sq (T)
}

we input normal value rather than pointer , but method receiver takes pointer value,it will not accept ,fails.

But we call area method like this sq.area()//rather than using interface to access it.

AHL
  • 493
  • 5
  • 8