1

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.

topenion
  • 390
  • 3
  • 12
  • please take a look at https://play.golang.org/p/fvFvsONstaK for the other case where I use value receiver and it does not show compile error – topenion Dec 10 '18 at 09:40
  • 1
    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 Dec 10 '18 at 09:55
  • 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 Dec 10 '18 at 10:42
  • No. No and again No. You are accessing this problem from the wrong angle. A a variable of type twoTimeable can hold **any** type with the right set of methods. All this pointer receiver, whatnot is **not relevant** here. There is literally nothing more to understand in the relation between a variable of type twoTimetable and the implementing type than: Has all methods of twoTimetable or has not. You must stop thinking about more than "which methods does this thing have" when you think of what a variable of type twoTimestable can hold. – Volker Dec 10 '18 at 11:21
  • The question about why and when a *MyInt or a MyInt has some method is a **different** question and is **unrelated** to the former. If you are interested what MyInt's method set is: That one is simple: Just those method defined like `func (m MyInt) ...` . If you want to know which methods are in the method set of *MyInt: Look for methods of the form `func (pm *MyInt) ...` **and** `func (m MyInt) ...` – Volker Dec 10 '18 at 11:25
  • 1
    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 Dec 10 '18 at 11:27
  • 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 – topenion Dec 10 '18 at 11:44
  • 1
    You might split your questions into 2 or 3 different questions, 1 questions seems to be why does https://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 Dec 10 '18 at 12:12
  • If you want the question to be removed, click the [delete] link. – James Z Dec 11 '18 at 14:06
  • @JamesZ No delete link is visible – topenion Dec 11 '18 at 18:08
  • Now Delete link is Visible but upon deleting it shows "since others have invested time and effort in answering it, it can not be deleted" – topenion Dec 12 '18 at 09:34

3 Answers3

3

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

Volker
  • 40,468
  • 7
  • 81
  • 87
  • But tt twoTimeable can not hold non pointers , it is showing compilation error. – topenion Dec 10 '18 at 09:11
  • No, this statement is wrong. twoTimetables _can_ hold non pointers. The compilation error originates elsewhere. The fact is: twoTimetables can hold only types which implement `result() (int, int)`. – Volker Dec 10 '18 at 09:14
  • Yes. That is the problem. MyInt is _not_ a twoTimetable. only *MyInt is. – Volker Dec 10 '18 at 09:16
  • If I make MyInt twoTimeable and no *MyInt , why does *MyInt becomes twoTimeable automatically – topenion Dec 10 '18 at 09:21
  • "why does *MyInt becomes twoTimeable automatically" It does not. It *MyInt has the right method. MyInt doesn't. These things do not "become" a twoTimetables. They either have or have not the right set of methods. If they do have the right methods: They can be assigned to a twoTimestable. And there are two ways of getting the right methods. See the linkes language spec for details. I _urge_ you to read the linked part of the spec. (And better names like MyInt and twoTimestable would help too). – Volker Dec 10 '18 at 09:30
  • Thank you for being patient but please take a look at https://play.golang.org/p/fvFvsONstaK it looks like it *MyInt became twoTimeable. – topenion Dec 10 '18 at 09:39
  • No, one last time: You *MyInt has the right method to be assignable to a twoTimetables. It has the right method because *MyInt has all methods of MyInt and MyInt has the proper result method. You example code is _not_ helpful: It crams to much different stuff into one example. – Volker Dec 10 '18 at 10:02
  • You have to understand three different and separate concepts. 1. Methods on pointer types and on non-pointer types. Methods on non-pointer types _cannot_ modify their receiver. 2. Method set: What methods does a type T or *T implement. 3. If a type has enough methods it can be assigned to an interface. 4. Sometimes Go takes addresses of variables automatically to go from T to *T. – Volker Dec 10 '18 at 10:02
0

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.

Volker
  • 40,468
  • 7
  • 81
  • 87
-1

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.

Volker
  • 40,468
  • 7
  • 81
  • 87