2016-11-26 21:24:32 8 Comments
There are already several Q&As on this "X does not implement Y (... method has a pointer receiver)" thing, but to me, they seems to be talking about different things, and not applying to my specific case.
So, instead of making the question very specific, I'm making it broad and abstract -- Seems like there are several different cases that can make this error happen, can someone summary it up please?
I.e., how to avoid the problem, and if it occurs, what are the possibilities? Thx.
Related Questions
Sponsored Content
35 Answered Questions
31 Answered Questions
[SOLVED] What does it mean to "program to an interface"?
- 2008-12-21 00:48:59
- Damien
- 148342 View
- 746 Score
- 31 Answer
- Tags: language-agnostic oop interface
14 Answered Questions
[SOLVED] What is a smart pointer and when should I use one?
- 2008-09-20 00:09:24
- Alex Reynolds
- 478163 View
- 1557 Score
- 14 Answer
- Tags: c++ pointers c++11 smart-pointers c++-faq
31 Answered Questions
[SOLVED] What's the difference between a method and a function?
- 2008-09-30 23:45:10
- willc2
- 600768 View
- 1546 Score
- 31 Answer
- Tags: function oop methods language-agnostic terminology
33 Answered Questions
[SOLVED] Interface vs Abstract Class (general OO)
- 2009-04-17 16:42:38
- Houman
- 651949 View
- 1286 Score
- 33 Answer
- Tags: oop interface abstract-class
2 Answered Questions
19 Answered Questions
[SOLVED] Does Java support default parameter values?
- 2009-06-15 18:04:28
- gnavi
- 972016 View
- 1419 Score
- 19 Answer
- Tags: java methods parameters default-value overloading
6 Answered Questions
[SOLVED] What does "dereferencing" a pointer mean?
- 2011-02-10 09:16:22
- asir
- 457803 View
- 438 Score
- 6 Answer
- Tags: c++ c pointers dereference
3 comments
@Saman Shafigh 2018-06-21 07:51:47
To keep it short, let say you have this code and you have a Loader interface and a WebLoader that implements this interface.
So this code will give you this compile time error
So what you only need to do is to change
webLoader := WebLoader{}
to following:So why it will fix because you define this function
func (w *WebLoader) Load
to accept a pointer receiver. For more explanation please read @icza and @karora answers@karora 2018-02-13 18:52:00
Another case when I have seen this kind of thing happening is if I want to create an interface where some methods will modify an internal value and others will not.
Something that then implements this interface could be like:
So the implementing type will likely have some methods which are pointer receivers and some which are not and since I have quite a variety of these various things that are GetterSetters I'd like to check in my tests that they are all doing the expected.
If I were to do something like this:
Then I won't get the aforementioned "X does not implement Y (Z method has pointer receiver)" error (since it is a compile-time error) but I will have a bad day chasing down exactly why my test is failing...
Instead I have to make sure I do the type check using a pointer, such as:
Or:
Then all is happy with the tests!
But wait! In my code, perhaps I have methods which accept a GetterSetter somewhere:
If I call these methods from inside another type method, this will generate the error:
Either of the following calls will work:
@icza 2016-11-26 23:03:08
This compile-time error arises when you try to assign or pass (or convert) a concrete type to an interface type; and the type itself does not implement the interface, only a pointer to the type.
Let's see an example:
The
Stringer
interface type has one method only:String()
. Any value that is stored in an interface valueStringer
must have this method. We also created aMyType
, and we created a methodMyType.String()
with pointer receiver. This means theString()
method is in the method set of the*MyType
type, but not in that ofMyType
.When we attempt to assign a value of
MyType
to a variable of typeStringer
, we get the error in question:But everything is ok if we try to assign a value of type
*MyType
toStringer
:And we get the expected outcome (try it on the Go Playground):
So the requirements to get this compile-time error:
Possibilities to resolve the issue:
Structs and embedding
When using structs and embedding, often it's not "you" that implement an interface (provide a method implementation), but a type you embed in your
struct
. Like in this example:Again, compile-time error, because the method set of
MyType2
does not contain theString()
method of the embeddedMyType
, only the method set of*MyType2
, so the following works (try it on the Go Playground):We can also make it work, if we embed
*MyType
and using only a non-pointerMyType2
(try it on the Go Playground):Also, whatever we embed (either
MyType
or*MyType
), if we use a pointer*MyType2
, it will always work (try it on the Go Playground):Relevant section from the spec (from section Struct types):
So in other words: if we embed a non-pointer type, the method set of the non-pointer embedder only gets the methods with non-pointer receivers (from the embedded type).
If we embed a pointer type, the method set of the non-pointer embedder gets methods with both pointer and non-pointer receivers (from the embedded type).
If we use a pointer value to the embedder, regardless of whether the embedded type is pointer or not, the method set of the pointer to the embedder always gets methods with both the pointer and non-pointer receivers (from the embedded type).
Note:
There is a very similar case, namely when you have an interface value which wraps a value of
MyType
, and you try to type assert another interface value from it,Stringer
. In this case the assertion will not hold for the reasons described above, but we get a slightly different runtime-error:Runtime panic (try it on the Go Playground):
Attempting to convert instead of type assert, we get the compile-time error we're talking about:
@xpt 2016-11-30 17:33:46
Thanks for the extremely comprehensive answer. Sorry for responding late as strangely I didn't get the SO notification. One case that I searched, the answer was that the "member functions" should either be all pointer types, e.g., "
func (m *MyType)
", or none. Is it so? Can I mix different types of "member functions", e.g.,func (m *MyType)
&func (m MyType)
?@icza 2016-11-30 20:28:06
@xpt You can mix pointer and non-pointer receivers, it's not a requirement to make all the same. It's just weird if you have 19 methods with pointer receiver and you make one with non-pointer receiver. It also makes it harder to track which methods are part of which types' method sets if you start mixing them. More details in this answer: Value receiver vs. Pointer receiver in Golang?
@Joel Edström 2017-07-16 18:10:32
How do you actually solve the issue mentioned at the end in "Note:" with an interface{} wrapping a value of
MyType
, if you can't changeMyType
to use value methods. I tried something like this(&i).(*Stringer)
but its not working. Is it even possible?@icza 2017-07-18 09:02:07
@JoelEdström Yes, it's possible, but it makes little sense. For example you may type-assert the value of the non-pointer type and store it in a variable, e.g.
x := i.(MyType)
, and then you can call methods with pointer receiver on it, e.g.i.String()
, which is a shorthand for(&i).String()
which succeeds because variables are addressable. But the pointer method changing the value (the pointed value) will not be reflected in the value wrapped in the interface value, that's why it makes little sense.@Joel Edström 2017-07-19 20:27:08
@icza But what if you don't know its concrete type or if the same code should work for multiple types that implement
Stringer
using pointer methods? For example say you got theinterface{}
from reflection.@icza 2017-07-19 21:06:23
@JoelEdström You could create a new pointer value using reflection, set the pointed value to the original, and use reflection to type assert the interface that contains the method you want to call, and call it. So yes, it's possible with reflection. It won't be a "fast" solution, but that's the price of being general on the cost of using reflection.
@Tarik 2017-09-19 22:57:07
Moral of the story: Pointer types and non-pointers types are not the same things even if they use the same underlying type. So, treat them accordingly. That's why which one implements a method to satisfy an interface matters!
@DeepNightTwo 2017-09-22 04:25:56
@icza Thanks for a detail explaination of this. After I practiced this, I wonder why it is designed so. Take the struct S and T for example. Why promoted methods with receiver *T is not included in method sets of S? I suppose it is doable (just use &S as the reciever when calll the method). Why Golang decided NOT to support this? Will it bring some potential issue or makes users make mistakes?
@icza 2017-09-22 07:47:34
@DeepNightTwo Methods of
*T
are not included in method set ofS
becauseS
might not be addressable (e.g. function return value or result of map indexing), and also because often only a copy is present / received, and if taking its address is allowed, the method with pointer receiver could only modify the copy (confusion as you would assume the original is modified). See this answer for an example: Using reflection SetString.