0

Can anyone explain why the calling of a.Abs() works? In my opinion, 'a' is a variable of type *Vertex, but the type *Vertex doesn't implement the method Abs.

package main

import (
    "fmt"
    "math"
)

type Abser interface {
    Abs() float64
}

func main() {
    var a Abser

    v := Vertex{3, 4}
    a = &v // a *Vertex implements Abser
    // In the following line, v is a *Vertex (not Vertex)
    // and does NOT implement Abser, but why does this calling work?
    fmt.Println(a.Abs())

}

type Vertex struct {
    X, Y float64
}

func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

1 Answers1

5

From the fine specification:

Method sets
[...] 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). [...]

Your Abs function is in the method sets of both Vertex and *Vertex so *Vertex is an Abser just like Vertex is.

Other related sections:

In general, pointers are automatically dereferenced when possible so you can say x.M() and x.V without worrying about whether or not x is a pointer and there is no need for C's -> or manual dereferencing (i.e. (*x).M() or (*x).V).

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • Yes, I know the compiler would automatically dereference a pointer when calling a method that accepts a value receiver. But, what I'm talking about is the interface. See this [tutorial example]( https://tour.golang.org/methods/9) – Pei Hsiang Hung May 10 '18 at 05:17
  • I'm just trying to say that the automatic dereferencing is more general than just during method calls and property accesses, it also applies to the type's method set. – mu is too short May 10 '18 at 05:18
  • If *Vertex implements Abser just like Vertex, why the [tutorial example](https://tour.golang.org/methods/9) emphasizes that v (of type Vertex) does NOT implement Abser. – Pei Hsiang Hung May 10 '18 at 05:29
  • 1
    Look carefully at the tour example. It has `func (v *Vertex) Abs() float64` whereas you have `func (v Vertex) Abs() float64`. There is automatic dereferencing but it doesn't go the other way. – mu is too short May 10 '18 at 06:16
  • see this [example](https://tour.golang.org/methods/7).Abs has a value receiver (Vertex), and using a variable of type *Vertex to call abs is fine. – Pei Hsiang Hung May 10 '18 at 08:10
  • And that's exactly what you're doing in your question and that's what the specification says. What am I missing? – mu is too short May 10 '18 at 17:33
  • In the [example](https://tour.golang.org/methods/9), if assigning 'v' of type Vertex to the interface 'a' is illegal, why assigning v of type Vertex* in my question is legal since Vertex* doesn't implement the interface. – Pei Hsiang Hung May 10 '18 at 23:28
  • The tour example defines an `Abs` method specifically on `*Vertex`, your question defines it on `Vertex`. Dereferencing is (more or less) automatic, addressing is not. If a method is defined on `T` then it is automatically defined on `*T`; if a method is defined on `*T` then it is not automatically defined on `T`. – mu is too short May 11 '18 at 00:30
  • " if a method is defined on *T then it is not automatically defined on T." I doubt if it's true. Please see the [example](https://tour.golang.org/methods/6). "while methods with pointer receivers take either a value or a pointer as the receiver when they are called:" Does it mean if a method is defined on *T, then it is automatically defined on T? – Pei Hsiang Hung May 11 '18 at 01:50
  • Thanks for discussing with me. I found a thread relating to my question. https://stackoverflow.com/questions/40823315/go-x-does-not-implement-y-method-has-a-pointer-receiver – Pei Hsiang Hung May 11 '18 at 05:09