If S contains an anonymous field T, does the method sets of S include promoted methods with receiver *T? - go

The title of the question is almost quoted from the golang specification:
Given a struct type S and a type named T, promoted methods are
included in the method set of the struct as follows:
If S contains an anonymous 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.
This is a go playground shows that The method inc() is promoted.
package main
import (
"fmt"
)
// just an int wrapper
type integer struct {
i int
}
func (self *integer) inc() {
self.i++
}
type counter struct {
integer
}
func main() {
c := counter{}
c.inc()
fmt.Println(c)
}

No the methods of *T would not be promoted. The specification doesn't explicitly allow it so it isn't allowed. However, there is a reason behind this.
At times you may call a *T method on T. However, there is an implicit reference taken. Methods of *T are not considered part of T's method set.
From the calls section of the Go specification:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
From the address operator section of the Go specification:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
If a S contains a *T, you don't even need to take its address so the methods can be called. If *S contains a T, you know T is addressable because T is a field selector of a pointer indirected struct. For S containing T, this cannot be guaranteed.
UPDATE: why does that code work?
Remember that *S contains the method set of *T. Also, as I quoted before:
If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
Put the two together and you have your answer. Counter is addressable and &counter contains the method set of *T. Therefore, counter.Inc() is shorthand for (&counter).Inc().

Related

Anonymous/explicitly embedded a interface in struct

type A interface {
f()
}
type B struct {
A
}
type C struct {
Imp A
}
func main() {
b := B{}
c := C{}
//b can be directly assigned to the A interface, but c prompts that it cannot be assigned
var ab A = b
//Cannot use 'c' (type C) as type A in assignment Type does not implement 'A' as some methods are missing: f()
var ac A = c
}
what's the different between in the B struct and C struct?
in Go sheet
A field declared with a type but no explicit field name is called an embedded field. An embedded field must be specified as a type name T or as a pointer to a non-interface type name *T, and T itself may not be a pointer type. The unqualified type name acts as the field name.
If you continue reading the same section of the spec of the spec, you will notice the following:
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.
Your struct B has no methods explicitly defined on it, but B's method set implicitly includes the promoted methods from the embedded field. In this case, the embedded field is an interface with method f(). You can use any object that satisfies that interface and its f() method will automatically be part of the method set for B.
On the other hand, your C struct has a named field. The methods on Imp do not get automatically added to C's method set. Instead, to access the f() method from Imp, you would need to specifically call C.Imp.f().
Finally: the fact that you're using an interface as the (embedded or not) field does not matter, it could easily be another struct that has a f() method. The important part is whether f() becomes part of the parent struct's method set or not, which will allow it to implement A or not.

When a receiver method T cannot take *T?

The official Go site writes as follows:
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.
My question is, when can't the compiler take a value to a pointer receiver value?
Addressable is defined in the https://golang.org/ref/spec#Address_operators:
For an operand x of type T, the address operation &x generates a pointer of type *T to x. The operand must be addressable, that is, either a variable, pointer indirection, or slice indexing operation; or a field selector of an addressable struct operand; or an array indexing operation of an addressable array. As an exception to the addressability requirement, x may also be a (possibly parenthesized) composite literal.
A counter examples include map values and functions:
func f() {}
func main() {
var m map[string]string
p1 := &m["foo"] // cannot take the address of m["foo"]
p2 := &f // cannot take the address of f
}

Selector of pointer for method from base type in go

It's obvious that the following code will work fine:
package main
import "fmt"
type T struct {
a int
}
func (t T) M() {
fmt.Println("M method")
}
func main() {
var t = &T{1}
t.M() // it's interesting
}
But as I can see from specification:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.
But in example M is not from *T, it's from T. I know that *T includes method set of T but as I can see specification doesn't tell us about method set of *T. Do I understand the specification wrong or correctness of the line with comment is based on some other specification rule?
You quoted:
x.f denotes the field or method at the shallowest depth in T
The quote refers to depth. "Definition" of depth is:
A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T. The number of embedded fields traversed to reach f is called its depth in T. The depth of a field or method f declared in T is zero. The depth of a field or method f declared in an embedded field A in T is the depth of f in A plus one.
The key is embedding. Your struct does not embed a single type. So by definition, the depth of your T.M is zero.
Your t variable is of type *T (that is the type of the &T{} expression, which is taking the address of a struct composite literal: it generates a pointer to a unique variable initialized with the literal's value).
And quoting from Spec: Method values:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
t.M is a reference to the non-interface method T.M, and since t is a pointer, it will be automatically dereferenced: (*t).M().
Now let's see an example where the "at the shallowest depth" does matter.
type T struct{}
func (t T) M() { fmt.Println("T.M()") }
type T2 struct {
T // Embed T
}
func (t T2) M() { fmt.Println("T2.M()") }
func main() {
var t T = T{}
var t2 T2 = T2{T: t}
t2.M()
}
In main() we call t2.M(). Since T2 embeds T, this could refer to T2.T.M and T2.M. But since depth of T2.T.M is one and depth of T2.M is zero, T2.M being at the shallowest depth in T2, therefore t2.M will denote T2.M and not T2.T.M, so the above example prints (try it on the Go Playground):
T2.M()
From 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).

Address of composite literal used as interface

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.

Difference between a method receiver as pointer or not

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

Resources