Spec says:
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.
So, to verify the point, below is the code:
package main
import "fmt"
// I interf
type I interface {
hello()
goodbye()
}
// T type
type T struct {
name string
}
func (t T) hello() {
fmt.Println("Hello", t.name)
}
func (t *T) goodbye() {
fmt.Println("Goodbye", t.name)
}
func main() {
var t1 T = T{"James"}
t1.hello()
t1.goodbye()
}
t1.goodbye() works despite goodbye() method is not part of method set of type T. Because, t1.goodbye() works internally as (&t1).goodbye() that satisfies below rule:
If you have a T and it isn't addressable, you can only call methods that have a receiver type of T, not *T.
But, specs says, method calling follows below rule:
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.
Does invocation of t1.goodbye() as (&t1).goodbye() break method calling rule?
From Calls in the spec...
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
t1 is addressable.
&t1's method set contains goodbye().
t1.goodbye() is shorthand for (&t1).goodbye().
Related
The following is the source code to try the embed type.
Modify function is defined as func (f *F) Modify(f2 F). Could anyone explain why the Modify function is not shown in the first reflection loop? But in the second reflection loop, both Modify and Validate can be got from *s.
package main
import "fmt"
import "reflect"
type F func(int) bool
func (f F) Validate(n int) bool {
return f(n)
}
func (f *F) Modify(f2 F) {
*f = f2
}
type B bool
func (b B) IsTrue() bool {
return bool(b)
}
func (pb *B) Invert() {
*pb = !*pb
}
type I interface {
Load()
Save()
}
func PrintTypeMethods(t reflect.Type) {
fmt.Println(t, "has", t.NumMethod(), "methods:")
for i := 0; i < t.NumMethod(); i++ {
fmt.Print(" method#", i, ": ",
t.Method(i).Name, "\n")
}
}
func main() {
var s struct {
F
*B
I
}
PrintTypeMethods(reflect.TypeOf(s))
fmt.Println()
PrintTypeMethods(reflect.TypeOf(&s))
}
output:
struct { main.F; *main.B; main.I } has 5 methods:
method#0: Invert
method#1: IsTrue
method#2: Load
method#3: Save
method#4: Validate
*struct { main.F; *main.B; main.I } has 6 methods:
method#0: Invert
method#1: IsTrue
method#2: Load
method#3: Modify
method#4: Save
method#5: Validate
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 embedded 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.
Struct types
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
...
Given a struct type S and a defined type T, promoted methods are
included in the method set of the struct as follows:
If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
If a method m is defined for a type T, that method is available for both T and *T:
type T struct {}
func (t T) m() {}
func main() {
t:=T{}
tp:=&T{}
t.m() // valid: m defined for T
tp.m() // valid: m defined for *T
}
If a method is defined with a pointer receiver, it is only defined for *T and not for T':
func (t *T) n() {}
func main() {
t:=T{}
tp:=&TP{
t.n() // Valid: &t is passed to n
tp.b // valid
mp:=map[int]T{1:t}
mp[1].n() // not valid. mp[1] is not addressable
pp:=map[int]*T{1:&t}
pp[1].n() // valid: pp[1] is *T
}
The reason for this is simple: it prevents unintentionally modifying the copy instead of the indented object. If a method with pointer receiver was available for the value type as well, with the following code:
mp[1].n()
n, taking a pointer receiver, would have modified a copy of the value of mp[1], and not the value stored at mp[1]. The fact that methods with pointer receivers are not available for value types prevents that, and this becomes a compile error, because n is not defined for T, and mp[1] is not addressable, preventing the value to be converted to a pointer by the compiler.
Here is the link to the code and description I was looking at: https://tour.golang.org/methods/11
I change method M of type *T to T, that is changing from a pointer receiver to a value receiver as below.
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
However, the change above gave me the same result as it was still a pointer receiver.
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
I am not sure I got this concept right. From my understanding since interface variable i got assign a pointer to an instance of struct T, the type of that interface variable should be a pointer to struct T, and since pointer to struct T does not implement method M, it will cause a panic.
Spec: 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).
[...] 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.
So all methods you declare with value receiver will also belong to the method set of the corresponding pointer type, and thus all interfaces a non-pointer type implements will also be implemented by the pointer type too (and possibly more).
Go has some shortcuts. For example:
a.Method()
a.Field
is the same as
(*a).Method()
(*a).Field
is similar to the concept here https://tour.golang.org/moretypes/4
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.
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).
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).
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.
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.
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.
Go interface by Lance Taylor
Go interface by Russ Cox
-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.
The address of a composite literal is evaluated as the literal itself when used as an interface. Can somebody please point to the part of the ref spec which deals with this ?
package main
import "fmt"
type ntfc interface {
rx() int
}
type cncrt struct {
x int
}
func (c cncrt) rx() int{
return c.x
}
func rtrnsNtfca() ntfc {
return &cncrt{3}
}
func rtrnsNtfc() ntfc {
return cncrt{3}
}
func rtrnsCncrt() *cncrt {
return &cncrt{3}
}
func main() {
fmt.Println(rtrnsNtfca().rx())
fmt.Println(rtrnsNtfc().rx())
fmt.Println(rtrnsCncrt().rx())
}
Also here. For future ref., is it acceptable to just link to the playground without including the code here?
Spec: 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).
So the method set of *cncrt includes the methods set of cncrt. Since rx() is an element of cncrt's method set, it will also be in *cncrt's method set. Which means both cncrt and *cncrt types implement the ntfc interface.
If you have a pointer value (*cncrt) and you call rx() on it, the pointer will automatically be dereferenced which will be the receiver of the rx() method.
In your rtnsNtfca() and rtnsNtfc() functions an interface value of ntfc will automatically be created and returned. Interface values in Go are represented as (type;value) pairs (for more details: The Laws of Reflection #The representation of an interface). So both rtnsNtfca() and rtnsNtfc() return an interface value, but the first one holds a dynamic value of type *cncrt and the latter one holds a dynamic value of type cncrt.
And your 3rd method rtrnsCncrt() returns a concrete type (*cncrt), there is no interface wrapping involved there.
Note: "The other way around"
Spec: Calls:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m().
This means if you would have declared rx() to have a pointer receiver, and you have a variable of type cncrt (note: not pointer), you could still call the rx() method on it if it is addressable, and the address would be taken automatically and used as the receiver.
Why don't I have to define PrintValue() as a pointer receiver (*One) to be able to print "hello"?
package main
import "fmt"
type One struct{
a string
}
func (o *One)AssignValue(){
o.a = "hello"
}
func (o One)PrintValue(){
fmt.Println(o.a)
}
func main() {
one := One{}
one.AssignValue()
one.PrintValue()
}
Because one is already of type One. The instantiation syntax
t := One{}
creates a value of type One while the form
p := &One{}
creates a pointer to a value of type One.
This means that nothing is to be done when calling t.PrintValue as the receiver type (One) is already the same as the type of t (One as well).
When calling p.PrintValue the compiler automatically converts an addressable variable to its pointer form because the receiver type (One) is not equal to the type of p (*One). So the expression
p.PrintValue()
is converted to
(*p).PrintValue()
There is also a conversion necessary when calling t.AssignValue as this method has a pointer receiver but we're supplying a value. This is also done automatically by the compiler where possible.
From the spec on calls:
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
This means the expression
t.AssignValue()
is converted to
(&t).AssignValue()
Note that this is not always possible. For example when returning a value from a function:
func NewOne(s string) One { return One{s} }
NewOne("foo").AssignValue() // Not possible
x := NewOne("foo")
x.AssignValue() // Possible, automatically converted