1
votes

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.

3
please take a look at play.golang.org/p/fvFvsONstaK for the other case where I use value receiver and it does not show compile error - topenion
You playground code shows a common missconception for value receivers (here on Pair): The method Pair.result is invoked on a copy of the underlying Pair. This copy is modified in lines 19 and 20. After the method is done the modified copy ceases to exist. This has _nothing to do with interfaces. - Volker
The Question is being Misunderstood, I will be more clear in future questions. But now If interface twoTimeable is implemented with (m *MyInt) , a variable of type twoTimeable can be assigned with a variable of type *MyInt. But if you change the implementation such that receiver become (m MyInt), a variable of type twoTimeable can hold MyInt as well as *MyInt. Why? - topenion
If you are really interested: Come up with small example, with sensible and short names which shows all the behaviour in one example. This "if you change the implementation" just makes the discussion complicated. - Volker
You might split your questions into 2 or 3 different questions, 1 questions seems to be why does play.golang.org/p/rIQnPjrhLPL (simplified part of your code) result in an error. While 1 other question might be why changing the result() method to take a non-pointer func (m MyInt) result() (int, int) { does not change the value of the MyInt. Another question is likely "how to create only 1 result method, that works on both pointer and non-pointer versions when assigned to a twoTimeable interface. Keep your questions short and distinct. - nos

3 Answers

1
votes

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 ints 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".)

0
votes

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.

-1
votes

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.