Difference between a method receiver as pointer or not - methods

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

Related

Why can I assign struct functions to members of other structs?

I was just messing around and wrote the below piece of code,
package main
import (
"fmt"
)
type Person struct {
name string
}
func (p Person) printName() {
fmt.Println(p.name)
}
type Man struct {
name string
f func()
}
func main() {
p := Person{name: "John"}
m := Man{name: "Adam"}
m.f = p.printName
p.printName()
m.f()
}
The above code results in the following output. This works across packages too.
John
John
So, here are my questions.
Why does this work?
Struct methods require receivers of the same type. How is the function still able to access members of the Person struct?
What happens when m.f = p.printName is executed in the above example?
This question deals mostly with receivers and may extend a bit to embedding.
From the relevant section of the spec:
A method is a function with a receiver. A method declaration binds an
identifier, the method name, to a method, and associates the method
with the receiver's base type.
MethodDecl = "func" Receiver MethodName Signature [ FunctionBody ] .
Receiver = Parameters .
The receiver is specified via an extra parameter section preceding the
method name. That parameter section must declare a single non-variadic
parameter, the receiver. Its type must be of the form T or *T
(possibly using parentheses) where T is a type name. The type denoted
by T is called the receiver base type; it must not be a pointer or
interface type and it must be defined in the same package as the
method. The method is said to be bound to the base type and the method
name is visible only within selectors for type T or *T.
A non-blank receiver identifier must be unique in the method
signature. If the receiver's value is not referenced inside the body
of the method, its identifier may be omitted in the declaration. The
same applies in general to parameters of functions and methods.
For a base type, the non-blank names of methods bound to it must be
unique. If the base type is a struct type, the non-blank method and
field names must be distinct.
Given type Point, the declarations
func (p *Point) Length() float64 {
return math.Sqrt(p.x * p.x + p.y *p.y)
}
func (p *Point) Scale(factor float64) {
p.x *= factor
p.y *= factor
}
bind the methods Length and Scale, with receiver type *Point, to the
base type Point.
The type of a method is the type of a function with the receiver as
first argument.
For instance, the method Scale has type
func(p *Point, factor float64)
However, a function declared this way is not a method.
Man has a field named f that is a function that takes no arguments and returns nothing.
As we saw above golang internally treats
func (p Person) printName()
as
func printName(p Person)
and this can be considered as a function of no arguments when it acts on a Person struct (and it does because p is a Person and p.printName acts on p). Therefore it is allowed to be assigned to Man.f
So the moment you assigned the f field on the Man struct to a function that has captured the Person instance with name "John" and reads the name from that, therefore you get effect of the second "John" being printed.
The Man.name field has never come into play on that one.
I suspect that what you would expect as normal behaviour can be achieved with struct embedding of Person into a Man.
here is a playground link to demonstrate that
A method, in Go, is basically a function with a receiver. That receiver is wraped by the compiler, and beyond that, there is nothing more different from a normal function. That means, at anywhere, the method always gets the receiver which it is bound to, no matter how you call it, assign it to another variable or anythiing else.
In your code, f is not a method of type Man. It is merely a field of type func(). You can set to anything that match the signature, and the function will know nothing about Man or its instance. That means, m.f has no knowledge of m and no access to m.name or any other field of m.
And a note, you can call methods like: Person.PrintName(p) where p is of type Person.
function in Golang is also a value, it can be passed as parameter or assigned by other function too, method in Golang is also a function, with one different, it has receiver in it's value, so when use assign a method to a function (which have same signature) it's refer to the receiver and executing code in that method to destination function

converting a method to a function with a pointer to the struct in Golang

I read some strange codes which convert a method to a function whose first argument is a pointer to this method's struct.
I write an example to demonstrate it:
package main
import "fmt"
type fooS struct{}
func (s *fooS) fooF(fooArg interface{}) {
fmt.Println("fooF: ", fooArg)
}
type wowS struct {
callback func(s *fooS, fooArg interface{})
}
func main() {
wow := new(wowS)
wow.callback = (*fooS).fooF // strange
wow.callback(nil, 123)
}
Golang Playground Link
The example's syntax is strange but has no error.
Can any one tell me how these codes work or give me an official document about them?
Thanks:)
Method expressions:
If M is in the method set of type T, T.M is a function that is
callable as a regular function with the same arguments as M prefixed
by an additional argument that is the receiver of the method.
MethodExpr = ReceiverType "." MethodName .
ReceiverType = TypeName | "(" "*" TypeName ")" | "(" ReceiverType ")" .
Consider a struct type T with two methods, Mv, whose receiver is of
type T, and Mp, whose receiver is of type *T.
type T struct {
a int
}
func (tv T) Mv(a int) int { return 0 } // value receiver
func (tp *T) Mp(f float32) float32 { return 1 } // pointer receiver
var t T
The expression
T.Mv
yields a function equivalent to Mv but with an explicit receiver as
its first argument; it has signature
func(tv T, a int) int
That function may be called normally with an explicit receiver, so
these five invocations are equivalent:
t.Mv(7)
T.Mv(t, 7)
(T).Mv(t, 7)
f1 := T.Mv; f1(t, 7)
f2 := (T).Mv; f2(t, 7)
Similarly, the expression
(*T).Mp
yields a function value representing Mp with signature
func(tp *T, f float32) float32
For a method with a value receiver, one can derive a function with an
explicit pointer receiver, so
(*T).Mv
yields a function value representing Mv with signature
func(tv *T, a int) int
Such a function indirects through the receiver to create a value to
pass as the receiver to the underlying method; the method does not
overwrite the value whose address is passed in the function call.
The final case, a value-receiver function for a pointer-receiver
method, is illegal because pointer-receiver methods are not in the
method set of the value type.
Function values derived from methods are called with function call
syntax; the receiver is provided as the first argument to the call.
That is, given f := T.Mv, f is invoked as f(t, 7) not t.f(7). To
construct a function that binds the receiver, use a function literal
or method value.
It is legal to derive a function value from a method of an interface
type. The resulting function takes an explicit receiver of that
interface type.
And see:
Go - difference between parameter and receiver
Is there a performance penalty for passing "this" by value in Go methods?
differences between pointer and value slice in for-range loop

Strange behaviour of int inside a struct

Let's say we have this kind of a struct (one of the simplest ever):
type some struct{
I uint32
}
And we want to have a variable of that type and to atomically increment in for loop (possibly in another goroutine but now the story is different). I do the following:
q := some{0}
for i := 0; i < 10; i++ {
atomic.AddUint32(&q.I,1) // increment [1]
fmt.Println(q.I)
}
We're getting what we'd expect, so far so good, but if we declare a function for that type as follows:
func (sm some) Add1(){
atomic.AddUint32(&sm.I,1)
}
and call this function in the above sample (line [1]) the value isn't incremented and we just get zeros. The question is obvious - why?
This has to be something basic but since I am new to go I don't realize it.
The Go Programming Language Specification
Calls
In a function call, the function value and arguments are evaluated in
the usual order. After they are evaluated, the parameters of the call
are passed by value to the function and the called function begins
execution. The return parameters of the function are passed by value
back to the calling function when the function returns.
The receiver sm some is passed by value to the method and the copy is discarded when you return from the method. Use a pointer receiver.
For example,
package main
import (
"fmt"
"sync/atomic"
)
type some struct {
I uint32
}
func (sm *some) Add1() {
atomic.AddUint32(&sm.I, 1)
}
func main() {
var s some
s.Add1()
fmt.Println(s)
}
Output:
{1}
Go Frequently Asked Questions (FAQ)
When are function parameters passed by value?
As in all languages in the C family, everything in Go is passed by
value. That is, a function always gets a copy of the thing being
passed, as if there were an assignment statement assigning the value
to the parameter. For instance, passing an int value to a function
makes a copy of the int, and passing a pointer value makes a copy of
the pointer, but not the data it points to.
Should I define methods on values or pointers?
func (s *MyStruct) pointerMethod() { } // method on pointer
func (s MyStruct) valueMethod() { } // method on value
For programmers unaccustomed to pointers, the distinction between
these two examples can be confusing, but the situation is actually
very simple. When defining a method on a type, the receiver (s in the
above examples) behaves exactly as if it were an argument to the
method. Whether to define the receiver as a value or as a pointer is
the same question, then, as whether a function argument should be a
value or a pointer. There are several considerations.
First, and most important, does the method need to modify the
receiver? If it does, the receiver must be a pointer. (Slices and maps
act as references, so their story is a little more subtle, but for
instance to change the length of a slice in a method the receiver must
still be a pointer.) In the examples above, if pointerMethod modifies
the fields of s, the caller will see those changes, but valueMethod is
called with a copy of the caller's argument (that's the definition of
passing a value), so changes it makes will be invisible to the caller.
By the way, pointer receivers are identical to the situation in Java,
although in Java the pointers are hidden under the covers; it's Go's
value receivers that are unusual.
Second is the consideration of efficiency. If the receiver is large, a
big struct for instance, it will be much cheaper to use a pointer
receiver.
Next is consistency. If some of the methods of the type must have
pointer receivers, the rest should too, so the method set is
consistent regardless of how the type is used. See the section on
method sets for details.
For types such as basic types, slices, and small structs, a value
receiver is very cheap so unless the semantics of the method requires
a pointer, a value receiver is efficient and clear.
Your function need to receive a pointer for the value to be incremented, that way you are not passing a copy of the struct and on next iteration the I can be incremented.
package main
import (
"sync/atomic"
"fmt"
)
type some struct{
I uint32
}
func main() {
q := &some{0}
for i := 0; i < 10; i++ {
q.Add1()
fmt.Println(q.I)
}
}
func (sm *some) Add1(){
atomic.AddUint32(&sm.I,1)
}

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.

multiple-value in single-value context (go)

The code below returns the error multiple-value in single-value context. I fail to understand why because it can't be more clear that the function has one argument ( I pass an empty string ""), and returns a string and an error (I assign it to r and err).
package main
import "fmt"
type Some struct{}
func main() {
cl := Some{}
r, err := &cl.Start("")
fmt.Println(r)
}
func (cs *Some) Start(sg string) (string, error) {
return sg, nil
}
It's an operator precedence thing. &cl.Start() is the same as &(cl.Start()), which isn't what you want.
Use parentheses to clarify that what you want is (&cl).Start().
Or you could just use a pointer variable.
func main() {
cl := &Some{}
r, err := cl.Start("")
fmt.Println(r)
}
As already stated in the comment, remove the & from &cl.Start("") and it will work - though you'l then get an error about err being declared and not used.
Or you can write it as (&cl).Start("") and that too will work.
The explanation is here:
The rule about pointers vs. values for receivers is that value methods can be invoked on pointers and values, but pointer methods can only be invoked on pointers.
This rule arises because pointer methods can modify the receiver;
invoking them on a value would cause the method to receive a copy of
the value, so any modifications would be discarded. The language
therefore disallows this mistake. There is a handy exception, though.
When the value is addressable, the language takes care of the common
case of invoking a pointer method on a value by inserting the address
operator automatically.
and also here:
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()

Resources