Given a method value, get receiver object - go

Is there a way in Go, to get the receiver object from a method value?
For example, is there any such MagicFunc that would make the following program output the string my info from the underlying Foo instance.
package main
import "fmt"
type Foo struct {
A string
}
func (foo *Foo) Bar() string {
return "bar"
}
func MyFunc(val interface{}) {
i := MagicFunc(val)
f := i.(Foo)
fmt.Println(f.A)
}
func main() {
f := Foo{A: "my info"}
MyFunc(f.Bar)
}

No, it is not possible to get the method's receiver instance.
The most you can get is the receiver's type if you use a method expression instead of method value but that won't help you get the my info string.

I wanted to deep-dive into this a bit and soon found this document: https://golang.org/s/go11func
As describe there, when MyFunc is entered val doesn't contain a reference to f.Bar but rather to a special function with the signature func() string. That function knows that it can retrieve the orignal f pointer by checking the well-known R0 register (in the example. On amd64 it appears to be dx, but that's an implementation detail obviously).
Thus there's no way to do this without using implementation specific assembly code, which would be very fragile.

Related

Get method receiver with reflect [duplicate]

Is there a way in Go, to get the receiver object from a method value?
For example, is there any such MagicFunc that would make the following program output the string my info from the underlying Foo instance.
package main
import "fmt"
type Foo struct {
A string
}
func (foo *Foo) Bar() string {
return "bar"
}
func MyFunc(val interface{}) {
i := MagicFunc(val)
f := i.(Foo)
fmt.Println(f.A)
}
func main() {
f := Foo{A: "my info"}
MyFunc(f.Bar)
}
No, it is not possible to get the method's receiver instance.
The most you can get is the receiver's type if you use a method expression instead of method value but that won't help you get the my info string.
I wanted to deep-dive into this a bit and soon found this document: https://golang.org/s/go11func
As describe there, when MyFunc is entered val doesn't contain a reference to f.Bar but rather to a special function with the signature func() string. That function knows that it can retrieve the orignal f pointer by checking the well-known R0 register (in the example. On amd64 it appears to be dx, but that's an implementation detail obviously).
Thus there's no way to do this without using implementation specific assembly code, which would be very fragile.

Difference between method signatures of structs

As a programmer coming from other languages like C++, I find it rather strange that go allows to specify methods for structs that allow either a pointer or an instance as a parameter. According to go by example once could use either of them if we didn't want to modify the origin:
Go automatically handles conversion between values and pointers for method calls. You may want to use a pointer receiver type to avoid copying on method calls or to allow the method to mutate the receiving struct.
Consider the following code:
package main
import (
"fmt"
)
type Foo struct {}
type Bar struct {}
func (this Foo) String() string {
return "Foo"
}
func (this *Bar) String() string {
return "Bar"
}
func main() {
fmt.Println(Foo{}) // "Foo"
fmt.Println(Bar{}) // "{}"
}
Why can't I use both signature versions to modify the stringify (I don't know how it is actually called in go) behavior of the structs?
Just to be clear: I don't really care about the stringify, but want to understand how the language behaves.
Just add & to the Bar{} and make it pointer receiver, like this:
fmt.Println(&Bar{}) // "Bar"
Here a little adjustment to your code that outputs:
Foo
Bar
see:
package main
import "fmt"
type Foo struct{}
func (Foo) String() string {
return "Foo"
}
type Bar struct{}
func (*Bar) String() string {
return "Bar"
}
func main() {
fmt.Println(Foo{}) // "Foo"
pb := &Bar{}
fmt.Println(pb) // "Bar"
}
Notes:
Receiver name should be a reflection of its identity; don't use
generic names such as "this" or "self"
And you don't need names here for your example.
And nice to read Golang methods receivers:
Value receivers operate on a copy of the original type value. This
means that there is a cost involved, especially if the struct is very
large, and pointer received are more efficient.
Because Bar does not implement stringer *Bar does.
If you remove implementation of stringer from Foo, you will get "{}".
Similarly, When you write fmt.Println(Bar{}) it means it will look for something like func (Bar) String() and not func (*Bar) String()
Additioanlly , story is different when you write fmt.Println(&Foo{}), you might think it will print "{}" because there is no func (*Foo) String() but it will print "Foo".
For that, you will have to understand Interfaces. These are my experiences so please do your own research too. The fmt.Print function calls String() on passed arguments. So actually the String() is not called on your struct but rather than an variable of type stringer.
interface type can hold a type(which implemented it) or pointer to it,
if it was implemented with value receiver. That is why Foo{} and
&Foo{} both work.
interface type can hold a type's pointer (which implemented it)only,
if it was implemented with pointer receiver. Why? Because when you
implement an interface with pointer receiver, it needs an address
which can only be provided with a pointer. That is why only &Bar{}
works and not Bar{}

The argument in golang RPC call

In the RPC handler function, I omit the first argument like:
func (self Handler) GetName(int, reply *StructObj) {
}
and in the calling side
var reply StructObj
client.Call("Handler.GetName", 0, &reply)
Because I do not need the first argument in the GetName Method, I omit its name,
HOWEVER, I got:
gob: type mismatch in decoder: want struct type
I changed the GetName method to GetName(id int, reply *StructObj) and it works.
I want to know why this happened?
You hit a tricky aspect of function definition syntax in Go. You can't have an unnamed argument, and you can name an argument int, and func f(x, y, z Type) is a shortcut to declare all three variables to be of type Type. For example, func f(int, x string) counterintuitively declares an f that accepts two strings, one of which happens to be named int.
package main
import "fmt"
func f(int, x string) {
fmt.Println("int is:", int)
fmt.Println("x is:", x)
}
func main() {
f("foo", "bar")
}
When you run it, the output is
int is: foo
x is: bar
Yes, that's a little mind-bending. I've never heard the specific thinking explained, but maybe they kept builtin type names un-reserved so they could later introduce new builtin types without breaking code that's already out there.
Anyway, it means your first function definition doesn't actually accept an int and a *StructObj but a *StructObj named int and another named reply. So the error message from net/rpc actually means that the client passed a 0 when it expected a *StructObj. Pretty fun.

Why isn't my Stringer interface method getting invoked? When using fmt.Println

Suppose I have the following code:
package main
import "fmt"
type Car struct{
year int
make string
}
func (c *Car)String() string{
return fmt.Sprintf("{make:%s, year:%d}", c.make, c.year)
}
func main() {
myCar := Car{year:1996, make:"Toyota"}
fmt.Println(myCar)
}
When I call fmt.Println(myCar) and the object in question is a pointer, my String() method gets called properly. If, however the object is a value, my output is formatted using the default formatting built into Go and my code to format the said object is not called.
The interesting thing is in either case if I call myCar.String() manually it works properly whether my object is either a pointer or value.
How can I get my object formatted the way I want no matter if the object is value-based or pointer-based when used with Println?
I don't want to use a value method for String because then that means every time it's invoked the object is copied which seams unreasonable. And I don't want to have to always manually called .String() either because I'm trying to let the duck-typing system do it's work.
When calling fmt.Println, myCar is implicitly converted to a value of type interface{} as you can see from the function signature. The code from the fmt package then does a type switch to figure out how to print this value, looking something like this:
switch v := v.(type) {
case string:
os.Stdout.WriteString(v)
case fmt.Stringer:
os.Stdout.WriteString(v.String())
// ...
}
However, the fmt.Stringer case fails because Car doesn't implement String (as it is defined on *Car). Calling String manually works because the compiler sees that String needs a *Car and thus automatically converts myCar.String() to (&myCar).String(). For anything regarding interfaces, you have to do it manually. So you either have to implement String on Car or always pass a pointer to fmt.Println:
fmt.Println(&myCar)
Methods
Pointers vs. Values
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 is because pointer methods can modify the
receiver; invoking them on a copy of the value would cause those
modifications to be discarded.
Therefore, for your String method to work when invoked on both pointers and values, use a value receiver. For example,
package main
import "fmt"
type Car struct {
year int
make string
}
func (c Car) String() string {
return fmt.Sprintf("{make:%s, year:%d}", c.make, c.year)
}
func main() {
myCar := Car{year: 1996, make: "Toyota"}
fmt.Println(myCar)
fmt.Println(&myCar)
}
Output:
{make:Toyota, year:1996}
{make:Toyota, year:1996}
Define your fmt.Stringer on a pointer receiver:
package main
import "fmt"
type Car struct {
year int
make string
}
func (c *Car) String() string {
return fmt.Sprintf("{maker:%s, produced:%d}", c.make, c.year)
}
func main() {
myCar := Car{year: 1996, make: "Toyota"}
myOtherCar := &Car{year: 2013, make: "Honda"}
fmt.Println(&myCar)
fmt.Println(myOtherCar)
}
Playground
Output:
{maker:Toyota, produced:1996}
{maker:Honda, produced:2013}
Then, always pass a pointer to instances of Car to fmt.Println. This way a potentially expensive value copy is avoided under your control.
The OP further asked:
OP: [when a value receiver is used] "Does this basically mean that if I have a large struct, then every time it goes through Println it will be copied?"
The following experiment is evidence that the answer is "yes" (when a value receiver is used). Note that the String() method increments the year in this experiment, and check how this affects the printed output.
type Car struct {
year int
make string
}
func (c Car) String() string {
s := fmt.Sprintf("{ptr:%p, make:%s, year:%d}", c, c.make, c.year)
// increment the year to prove: is c a copy or a reference?
c.year += 1
return s
}
func main() {
myCar := Car{year: 1996, make: "Toyota"}
fmt.Println(&myCar)
fmt.Println(&myCar)
fmt.Println(myCar)
fmt.Println(myCar)
}
With a value receiver (c Car), the following printed output shows that Go makes value copies of the Car struct, because the year increment is not reflected in subsequent calls to Println:
{ptr:%!p(main.Car={1996 Toyota}), make:Toyota, year:1996}
{ptr:%!p(main.Car={1996 Toyota}), make:Toyota, year:1996}
{ptr:%!p(main.Car={1996 Toyota}), make:Toyota, year:1996}
{ptr:%!p(main.Car={1996 Toyota}), make:Toyota, year:1996}
Changing the receiver to a pointer (c *Car) but changing nothing else, the printed output becomes:
{ptr:0xc420094020, make:Toyota, year:1996}
{ptr:0xc420094020, make:Toyota, year:1997}
{1998 Toyota}
{1998 Toyota}
Even when a pointer is provided as argument in a call to Println, i.e. fmt.Println(&myCar), Go still makes a value copy of the Car struct when a value receiver is used. The OP wants to avoid value copies being made, and my conclusion is that only pointer receivers satisfy that requirement.
It's only related to implementation of fmt instead of Go however.
String() with pointer receiver would be invoked by https://github.com/davecgh/go-spew since spew print things in this way:
v = reflect.ValueOf(arg)
...
switch iface := v.Interface().(type) {
case fmt.Stringer:
defer catchPanic(w, v)
if cs.ContinueOnMethod {
w.Write(openParenBytes)
w.Write([]byte(iface.String()))
w.Write(closeParenBytes)
w.Write(spaceBytes)
return false
}
w.Write([]byte(iface.String()))
return true
}
Generally speaking, it's best to avoid assigning values to variables via static initializers, i.e.
f := Foo{bar:1,baz:"2"}
This is because it can create exactly the complaint you're talking about, if you forget to pass foo as a pointer via &foo or you decide to use value receivers you end up making a lot of clones of your values.
Instead, try to assign pointers to static initializers by default, i.e.
f := &Foo{bar:1,baz:"2"}
This way f will always be a pointer and the only time you'll get a value copy is if you explicitly use value receivers.
(There are of course times when you want to store the value from a static initializer, but those should be edge cases)

Adding a func never called improves behavior?

The code below produces undesirable
[20010101 20010102].
When uncommenting the String func it produces better (but not my implementation):
[{20010101 1.5} {20010102 2.5}]
However that String func is never called.
I see that Date in DateValue is anonymous and therefore func (Date) String is being used by DateValue.
So my questions are:
1) Is this a language issue, a fmt.Println implementation issue, or
something else? Note: if I switch from:
func (*DateValue) String() string
to
func (DateValue) String() string
my function is at least called and panic ensues. So if I really want my method called I could do that, but assume DateValue is really a very large object which I only want to pass by reference.
2) What is a good strategy for mixing anonymous fields with
functionality like Stringer and json encoding that use reflection
under the covers? For example adding a String or MarshalJSON method
for a type that happens to be used as an anonymous field can cause
strange behavior (like you only print or encode part of the whole).
package main
import (
"fmt"
"time"
)
type Date int64
func (d Date) String() string {
t := time.Unix(int64(d),0).UTC()
return fmt.Sprintf("%04d%02d%02d", t.Year(), int(t.Month()), t.Day())
}
type DateValue struct {
Date
Value float64
}
type OrderedValues []DateValue
/*
// ADD THIS BACK and note that this is never called but both pieces of
// DateValue are printed, whereas, without this only the date is printed
func (dv *DateValue) String() string {
panic("Oops")
return fmt.Sprintf("DV(%s,%f)", dv.Date, dv.Value )
}
*/
func main() {
d1, d2 := Date(978307200),Date(978307200+24*60*60)
ov1 := OrderedValues{{ d1, 1.5 }, { d2, 2.5 }}
fmt.Println(ov1)
}
It's because you've passed in a slice of DateValues and not DateValue pointers. Since you've defined the String method for *DataValue, *DateValue is what fulfills the Stringer interface. This also prevents DateValue from fulfilling the Stringer interface via its anonymous Date member, because only one of either the value type (DateValue) or the pointer type (*DateValue) can be used to fulfill an interface. So, when fmt.Println is printing the contents of the slice, it sees that the elements are not Stringers, and uses the default struct formatting instead of the method you defined, giving [{20010101 1.5} {20010102 2.5}].
You can either make OrderedValues a []*DateValue or define func (dv DateValue) String() string instead of the pointer version.
Based on what #SteveM said, I distilled it to a simpler test case:
package main
import "fmt"
type Fooable interface {
Foo()
}
type A int
func (a A) Foo() { }
type B struct {
A
}
// Uncomment the following method and it will print false
//func (b *B) Foo() { }
func main() {
var x interface{} = B{}
_, ok := x.(Fooable)
fmt.Println(ok) // prints true
}
In other words, the Foo method is not part of the method set of B when the Foo method for *B is defined.
From reading the spec, I don't see a clear explanation of what is happening. The closest part seems to be in the section on selectors:
For a value x of type T or *T where T is not an interface type, x.f
denotes the field or method at the shallowest depth in T where there
is such an f.
The only way I can see this explaining what is going on is if when it is looking for a method Foo at shallowest depth in B, it takes into consideration the methods for *B too, for some reason (even though we are considering type B not *B); and the Foo in *B is indeed shallower than the Foo in A, so it takes that one as the candidate; and then it sees that that Foo doesn't work, since it's in *B and not B, so it gets rid of Foo altogether (even though there is a valid one inherited from A).
If this is indeed what is going on, then I agree with the OP in that this is very counter-intuitive that adding a method to *B would have the reverse consequence of removing a method from B.
Maybe someone more familiar with Go can clarify this.

Resources