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
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.
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{}
Can an instance of a go type change its underlying value? Thanks to a previous question I know I can make my function's receiver a pointer and change struct fields if my type is a struct.
However, I'm interesting in changing the underlying type's value. Consider a small program like this
type Foo string
func (f *Foo) ChangeMe() {
val := Foo("Hello World")
f = &val
//fmt.Println(*f)
}
func main() {
f := Foo("Nope")
f.ChangeMe()
fmt.Println(f)
}
My naive assumption was "OK, I've created a new Foo("Hello World") and then pointed f at it. Since receiver is a pointer (*Foo), this should change the value in main().
However, this does not work. The above program still prints out "Nope"
Interested both in what my incorrect assumption about go are, and any techniques for achieving what I want to do.
You're assigning a new pointer value to f instead of dereferencing it.
Dereference f and assign a new string value:
func (f *Foo) ChangeMe() {
*f = Foo("Hello World")
}
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.
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.