Reputation: 470
This question is not as clear as I wanted to be I will ask a better question. But I do not want to marked duplicate on that. So I have flagged my own question. If you can help it to be deleted to not confuse the community. Please do the needful. Please do not downvote me while you are at it. Sorry to be unclear
I am new to golang and just getting the hang of it.
I am learning by taking Tour of Go and then using it with my own understanding. I was at Interfaces and started to implement with my own understanding. Here is Go PlayGround Link
Step 1 : I made 3 types an int, a struct and an interface
package main
import (
"fmt"
)
type MyInt int
type Pair struct {
n1, n2 int
}
type twoTimeable interface {
result() (int, int)
}
Step 2 : Then I implemeted twoTimeable for pointer receivers because it changes underlying value.
func (p *Pair) result() (int, int) {
p.n1 = 2 * p.n1
p.n2 = 2 * p.n2
return p.n1, p.n2
}
func (m *MyInt) result() (int, int) {
*m = 2 * (*m)
return int(*m), 0
}
Step 3 : Then I declared and assigned MyInt, Pair and their corresponding pointers in main function. I also declared twoTimeable interface
mtemp := MyInt(2)
var m1 MyInt
var m2 *MyInt
var p1 Pair
var p2 *Pair
m1, m2, p1, p2 = MyInt(1), &mtemp, Pair{3, 4}, &Pair{5, 6}
var tt twoTimeable
fmt.Println(" Values : ", m1, *m2, p1, *p2, tt)
Step 4 : The I assigned MyInt,Pair and their pointers , called the implemented method and printed.
tt = m1
fmt.Println(tt.result())
fmt.Printf("Value of m1 %v\n", m1)
tt = m2
fmt.Println(tt.result())
fmt.Printf("Value of m2 %v\n", *m2)
tt = p1
fmt.Println(tt.result())
fmt.Printf("Value of p1 %v\n", p1)
tt = p2
fmt.Println(tt.result())
fmt.Printf("Value of p2 %v\n", *p2)
It shows error :
prog.go:41:5: cannot use m1 (type MyInt) as type twoTimeable in assignment:
MyInt does not implement twoTimeable (result method has pointer receiver)
prog.go:49:5: cannot use p1 (type Pair) as type twoTimeable in assignment:
Pair does not implement twoTimeable (result method has pointer receiver)
I also read this question, I got that m1 and p1 are not addressable, thats why it wont compile.
But method result() will just work fine if I use p1, or m1 p1/m1.result()
(auto dereferencing FTW)
Now in Step 2 when I change the pointer receiver to value receiver, and change *m to m(I am aware of change in Output)
func (p Pair) result() (int, int) {
p.n1 = 2 * p.n1
p.n2 = 2 * p.n2
return p.n1, p.n2
}
func (m MyInt) result() (int, int) {
m = 2 * (m)
return int(m), 0
}
It suddenly does not show compile error. shouldn't it for m2 and p2, because now there is no implementation of result using *MyInt and *Pair
That means if interface method implementation has value receiver tt can hold both pointer and value. But when interface method implemenation has pointer reciever it cant hold non pointers.
Q1 : Why it is fine to use pointers (tt = m2) on value receiver interface methods(p MyInt) result() , but not values (tt = m1) on pointer receiver interface method(p *MyInt) result().
Now lets revert to pointer receivers.
Is there a way that if function accept param (tt twoTimeable) i will be able to invoke tt.result() irrespective tt being a pointer to type or not, given result() is only definded with pointer receiver.
See the code below:
func doSomething(tt twoTimeable) {
temp1, temp2 := tt.result()
fmt.Print("doing something with ", temp1, temp2)
}
Since tt can be any predefined type(pointer or not a pointer), accpting param (tt *twoTimeable, if I can even do that) does not seem like a solution or do I have rely on user of function to provide pointer. If i do not have to change underlying value i.e use value receiver its not a problem as tt can hold either value or pointer to that
I always Accept answer.
Upvotes: 3
Views: 4070
Reputation: 42478
Shouldn't it for m2 and p2, because now there is no implementation of result using *MyInt and *Pair
No. You are conflating different things and misinterpreting the results.
Go lets you omit pointer dereferencing in most situations.
type Pair struct {
n1, n2 int
}
var pp *Pair = ...
fmt.Println(pp.n1)
See the last line? pp
is a pointer to Pair but there is no need to write (*pp).n1
.
This dereferencing is inserted automatically (it is the automatic variant of the ->
operator in C).
Your m2 and p2 are just variables containing a pointer. If needed these pointers will be dereferenced. This has nothing to do with pointer/value-receivers or interfaces.
Upvotes: -1
Reputation: 42478
Is there a way that if function accept param (tt twoTimeable) i will be able to invoke tt.result() irrespective tt being a pointer to type or not, given result() is only definded with pointer receiver.
This seems to be a major missconception here. If if tt
is a variable of the interface type twoTimetable
than is has a result
method and this method can be called. Whytever the underlying type of the tt
is does not matter at all. A interface type completely encapsulates the underlying type from being relevant. An interface type provides a set of methods and these can be called and no other method can be called.
The question of assignability of a concrete type (e.g. you MyInt) to a variable of type twoInterfaces is a different question. If your concrete type (e.g. MyInt) happens to have all methods defined by the interface type (here twoTimetables) then it is assignable, if not, then not.
The question "what methods does my concrete type have" is a third question. This one is the only question which is a bit complicated. Any method defined on receiver T is a method of T. For pointer types *T the methods on *T and the methods on T count.
Upvotes: 0
Reputation: 42478
Q1 : Why it is fine to use pointers on value receiver methods but not vice vers?
Because the language spec say it it fine: https://golang.org/ref/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).
(A possible reason why the spec is like this: Convenience.)
For the rest of the question: I do not have the slightest idea what you are asking. The code of do Something
is totally fine. You invoke result
on tt
which is any type implementing the result() (int, int)
method. Whether this type is a pointer type or not is of no interest. You get two int
s back from this method call and can do whatever you want with these ints.
(Regarding the "pointer to interface" part: Yes. It is technically possible to do ttp *twoTimetable
. But you never need this. Never. (Of course this is a lie but the case you need it is so rare and delicate that you really never need this as a beginner and once you do need it you will know how to use it.) There is one thing to remember here: You never do "pointer to interface".)
Upvotes: 3