Question regarding Golang interfaces and Composite struct [duplicate] - go

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.

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.
Short summary: An assignment to a variable of interface type is valid if the value being assigned implements the interface it is assigned to. It implements it if its method set is a superset of the interface. The method set of pointer types includes methods with both pointer and non-pointer receiver. The method set of non-pointer types only includes methods with non-pointer receiver.
Let's see an example:
type Stringer interface {
String() string
}
type MyType struct {
value string
}
func (m *MyType) String() string { return m.value }
The Stringer interface type has one method only: String(). Any value that is stored in an interface value Stringer must have this method. We also created a MyType, and we created a method MyType.String() with pointer receiver. This means the String() method is in the method set of the *MyType type, but not in that of MyType.
When we attempt to assign a value of MyType to a variable of type Stringer, we get the error in question:
m := MyType{value: "something"}
var s Stringer
s = m // cannot use m (type MyType) as type Stringer in assignment:
// MyType does not implement Stringer (String method has pointer receiver)
But everything is ok if we try to assign a value of type *MyType to Stringer:
s = &m
fmt.Println(s)
And we get the expected outcome (try it on the Go Playground):
something
So the requirements to get this compile-time error:
A value of non-pointer concrete type being assigned (or passed or converted)
An interface type being assigned to (or passed to, or converted to)
The concrete type has the required method of the interface, but with a pointer receiver
Possibilities to resolve the issue:
A pointer to the value must be used, whose method set will include the method with the pointer receiver
Or the receiver type must be changed to non-pointer, so the method set of the non-pointer concrete type will also contain the method (and thus satisfy the interface). This may or may not be viable, as if the method has to modify the value, a non-pointer receiver is not an option.
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:
type MyType2 struct {
MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: m}
var s Stringer
s = m2 // Compile-time error again
Again, compile-time error, because the method set of MyType2 does not contain the String() method of the embedded MyType, only the method set of *MyType2, so the following works (try it on the Go Playground):
var s Stringer
s = &m2
We can also make it work, if we embed *MyType and using only a non-pointer MyType2 (try it on the Go Playground):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = m2
Also, whatever we embed (either MyType or *MyType), if we use a pointer *MyType2, it will always work (try it on the Go Playground):
type MyType2 struct {
*MyType
}
m := MyType{value: "something"}
m2 := MyType2{MyType: &m}
var s Stringer
s = &m2
Relevant section from the spec (from section Struct types):
Given a struct type S and a type named T, promoted methods are included in the method set of the struct as follows:
If S contains an anonymous field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
If S contains an anonymous field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
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:
m := MyType{value: "something"}
var i interface{} = m
fmt.Println(i.(Stringer))
Runtime panic (try it on the Go Playground):
panic: interface conversion: main.MyType is not main.Stringer:
missing method String
Attempting to convert instead of type assert, we get the compile-time error we're talking about:
m := MyType{value: "something"}
fmt.Println(Stringer(m))

To keep it short and simple, let say you have a Loader interface and a WebLoader that implements this interface.
package main
import "fmt"
// Loader defines a content loader
type Loader interface {
load(src string) string
}
// WebLoader is a web content loader
type WebLoader struct{}
// load loads the content of a page
func (w *WebLoader) load(src string) string {
return fmt.Sprintf("I loaded this page %s", src)
}
func main() {
webLoader := WebLoader{}
loadContent(webLoader)
}
func loadContent(loader Loader) {
loader.load("google.com")
}
The above code will give you this compile time error
./main.go:20:13: cannot use webLoader (type WebLoader) as type Loader
in argument to loadContent:
WebLoader does not implement Loader (Load method has pointer receiver)
To fix it you only need to change webLoader := WebLoader{} to following:
webLoader := &WebLoader{}
Why this will fix the issue? Because you defined this function func (w *WebLoader) Load to accept a pointer receiver. For more explanation please read #icza and #karora answers

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.
type GetterSetter interface {
GetVal() int
SetVal(x int) int
}
Something that then implements this interface could be like:
type MyTypeA struct {
a int
}
func (m MyTypeA) GetVal() int {
return a
}
func (m *MyTypeA) SetVal(newVal int) int {
int oldVal = m.a
m.a = newVal
return oldVal
}
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:
myTypeInstance := MyType{ 7 }
... maybe some code doing other stuff ...
var f interface{} = myTypeInstance
_, ok := f.(GetterSetter)
if !ok {
t.Fail()
}
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:
var f interface{} = new(&MyTypeA)
...
Or:
myTypeInstance := MyType{ 7 }
var f interface{} = &myTypeInstance
...
Then all is happy with the tests!
But wait! In my code, perhaps I have methods which accept a GetterSetter somewhere:
func SomeStuff(g GetterSetter, x int) int {
if x > 10 {
return g.GetVal() + 1
}
return g.GetVal()
}
If I call these methods from inside another type method, this will generate the error:
func (m MyTypeA) OtherThing(x int) {
SomeStuff(m, x)
}
Either of the following calls will work:
func (m *MyTypeA) OtherThing(x int) {
SomeStuff(m, x)
}
func (m MyTypeA) OtherThing(x int) {
SomeStuff(&m, x)
}

Extend from above answers (Thanks for all of your answers)
I think it would be more instinctive to show all the methods of pointer / non pointer struct.
Here is the playground code.
https://play.golang.org/p/jkYrqF4KyIf
To summarize all the example.
Pointer struct type would include all non pointer / pointer receiver methods
Non pointer struct type would only include non pointer receiver methods.
For embedded struct
non pointer outer struct + non pointer embedded struct => only non pointer receiver methods.
non pointer outer struct + pointer embedded struct / pointer outer struct + non pointer embedded struct / pointer outer struct + pointer embedded struct => all embedded methods

Related

Can interface type and value be a type that does not implement the interface and its value?

Here is the link to the code and description I was looking at: https://tour.golang.org/methods/11
I change method M of type *T to T, that is changing from a pointer receiver to a value receiver as below.
package main
import (
"fmt"
"math"
)
type I interface {
M()
}
type T struct {
S string
}
func (t T) M() {
fmt.Println(t.S)
}
type F float64
func (f F) M() {
fmt.Println(f)
}
func main() {
var i I
i = &T{"Hello"}
describe(i)
i.M()
i = F(math.Pi)
describe(i)
i.M()
}
func describe(i I) {
fmt.Printf("(%v, %T)\n", i, i)
}
However, the change above gave me the same result as it was still a pointer receiver.
(&{Hello}, *main.T)
Hello
(3.141592653589793, main.F)
3.141592653589793
I am not sure I got this concept right. From my understanding since interface variable i got assign a pointer to an instance of struct T, the type of that interface variable should be a pointer to struct T, and since pointer to struct T does not implement method M, it will cause a panic.
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).
[...] The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
So all methods you declare with value receiver will also belong to the method set of the corresponding pointer type, and thus all interfaces a non-pointer type implements will also be implemented by the pointer type too (and possibly more).
Go has some shortcuts. For example:
a.Method()
a.Field
is the same as
(*a).Method()
(*a).Field
is similar to the concept here https://tour.golang.org/moretypes/4

How can I return a subtype of the specified return value (in this case interface{})?

I have an interface that defines one parameter to have type func(interface{}, proto.Message) interface{} and I'm trying to pass something of type func reduceMsg(a interface{}, b proto.Message) []*PersistentData to it. This results in the following compiler error:
Cannot use reduceMsg (type func(a interface{}, b proto.Message) []*PersistentData as type func(interface{}, proto.Message) interface{}
What is the reason for this error, and how can I work around it? It seems like returning a more specific type than interface{} should be legal. Here's a simple complete example that illustrates the issue:
package main
import "fmt"
func main() {
var t func() interface{} = func() []string { return []string{} }
fmt.Println(t)
}
The type of the object is the whole function signature. If the signature don't match, then it's not the same type and can't be assigned that way.
Anything can be assigned to the empty interface, because all types satisfy the interface, but in your problem neither type is the empty interface, you just have a function that returns an empty interface.
Not because a part of the function can be assigned to another it makes it the same. The type is the whole function signature. I think it's the same logic behind not being able to assign an int to an int8. You can cast them if you want, but for go, they are separate types and you need to deal with making the necessary conversions to be able to assign them.
What you can do is change your second function signature to return an empty interface like this:
func(interface{}, proto.Message) interface{}
func reduceMsg(a interface{}, b proto.Message) interface{} {
var a []*PersistentData
// do something here
return a
}
This way the function signature is the same, so it's consider the same type and you are returning an []*PersistentData. Of course you will need to do a type assertion before using it as such because the program will treat it as an {}interface because that is the type that the function returned.
Referencing the spec,
In assignments, each value must be assignable to the type of the operand to which it is assigned, with the following special cases:
Any typed value may be assigned to the blank identifier.
If an untyped constant is assigned to a variable of interface type or the blank identifier, the constant is first converted to its default type.
If an untyped boolean value is assigned to a variable of interface type or the blank identifier, it is first converted to type bool.
Assignability
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
In general, Go doesn't allow you to implicitly convert values from one type to another, with the exception of being able to use concrete-typed objects as though they were interfaces (that they implement).
In this particular case, since your function doesn't actually return an interface{}, the compiler would have to do some extra work to wrap up the return value as an interface{} and return it; if you really want to accomplish what you're trying you can do this explicitly yourself:
type Foo struct {
X int
}
func create(x int) Foo {
return Foo{X: x}
}
func main() {
var f func(int) interface{} = func(x int) interface{} {
return create(x)
}
}
which is basically doing (explicitly) the wrapping operation that you want the runtime to do implicitly.

Method Sets (Pointer vs Value Receiver)

I am having a hard time understanding as to why are these rules associated with method set of pointer type .vs. value type
Can someone please explain the reason (from the interface table perspective)
(Snippet from William Kennedy's blog)
Values Methods Receivers
-----------------------------------------------
T (t T)
*T (t T) and (t *T)
Methods Receivers Values
-----------------------------------------------
(t T) T and *T
(t *T) *T
Snippet from specification
Method sets
A type may have a method set associated with it. The method set of an interface type is its interface.
The method set of any other type T consists of all methods declared with receiver type T. 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). Further rules apply to structs containing anonymous fields, as described in the section on struct types. Any other type has an empty method set. In a method set, each method must have a unique non-blank method name.
The method set of a type determines the interfaces that the type implements and the methods that can be called using a receiver of that type.
If you have a *T you can call methods that have a receiver type of *T as well as methods that have a receiver type of T (the passage you quoted, Method Sets).
If you have a T and it is addressable you can call methods that have a receiver type of *T as well as methods that have a receiver type of T, because the method call t.Meth() will be equivalent to (&t).Meth() (Calls).
If you have a T and it isn't addressable (for instance, the result of a function call, or the result of indexing into a map), Go can't get a pointer to it, so you can only call methods that have a receiver type of T, not *T.
If you have an interface I, and some or all of the methods in I's method set are provided by methods with a receiver of *T (with the remainder being provided by methods with a receiver of T), then *T satisfies the interface I, but T doesn't. That is because *T's method set includes T's, but not the other way around (back to the first point again).
In short, you can mix and match methods with value receivers and methods with pointer receivers, and use them with variables containing values and pointers, without worrying about which is which. Both will work, and the syntax is the same. However, if methods with pointer receivers are needed to satisfy an interface, then only a pointer will be assignable to the interface — a value won't be valid.
From Golang FAQ:
As the Go specification says, the method set of a type T consists of all methods with receiver type T, while that of the corresponding pointer type *T consists of all methods with receiver *T or T. That means the method set of *T includes that of T, but not the reverse.
This distinction arises because if an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, there is no safe way for a method call to obtain a pointer. (Doing so would allow a method to modify the contents of the value inside the interface, which is not permitted by the language specification.)
Even in cases where the compiler could take the address of a value to pass to the method, if the method modifies the value the changes will be lost in the caller. As an example, if the Write method of bytes.Buffer used a value receiver rather than a pointer, this code:
var buf bytes.Buffer
io.Copy(buf, os.Stdin)
would copy standard input into a copy of buf, not into buf itself. This is almost never the desired behavior.
About Golang interface under the hood.
Go interface by Lance Taylor
Go interface by Russ Cox
-In go when we have a type we can attach methods on it, those methods attached to type are known as its method set.
Depending on Pointer or not pointer value , it will determine which method attach to it.
Case:1
Receiver (t T) Value T => https://go.dev/play/p/_agcEVFaySx
type square struct {
length int
}
type shape interface { shape as an interface
area() int
}
// receiver(t T)
func (sq square) area() int {
return sq.length * sq.length
}
func describe(s shape) {
fmt.Println("area", s.area())
}
func main() {
sq := square{
length: 5,
}
describe(sq)// value `sq` (T)
}
Case 2: Receiver (t T) Value T
// receiver(t *T)
func (sq *square) area() int {
return sq.length * sq.length
}
func main() {
describe(sq)// value sq (T)
}
Case 4: Receiver (t *T) Value T
// receiver(t *T)
func (sq *square) area() int {
return sq.length * sq.length
}
func main() {
describe(&sq)// value sq (*T)
}
Case 4: Receiver (t *T) Value T
this case fails
// receiver(t *T)
func (sq *square) area() int {
return sq.length * sq.length
}
func main() {
describe(&sq)// value sq (T)
}
we input normal value rather than pointer , but method receiver takes pointer value,it will not accept ,fails.
But we call area method like this sq.area()//rather than using interface to access it.

Why no methods defined for named pointer types?

In the documentation for effective Go it states:
As we saw with ByteSize, methods can be defined for any named type
(except a pointer ...
type ByteSlice []byte
func (slice ByteSlice) Append(data []byte) []byte {
// Body exactly the same as above
}
It then goes on to provide an example with a pointer as receiver:
func (p *ByteSlice) Append(data []byte) {
slice := *p
// Body as above, without the return.
*p = slice
}
Doesn't that contradict ? Or does it mean that this isn't valid:
type ByteSlice []byte
type Pb *ByteSlice
func (p Pb) Append(data []byte) []byte {
}
Though it looks just like a typedef!
Named pointer types could lead to ambiguities like so:
type T int
func (t *T) Get() T {
return *t + 1
}
type P *T
func (p P) Get() T {
return *p + 2
}
func F() {
var v1 T
var v2 = &v1
var v3 P = &v1
fmt.Println(v1.Get(), v2.Get(), v3.Get())
}
In the last case (esp. v3) per the current spec, it's ambiguous which Get() method should be called. Yes, there's no reason that the method resolution couldn't be defined, but it's one more detail to add to the language for something that already has a solution.
A named type that is a pointer isn't the same as a pointer to a named type.
This is what the language reference says:
That parameter section must declare a single parameter, the receiver.
Its type must be of the form T or *T (possibly using parentheses)
where T is a type name. The type denoted by T is called the receiver
base type; it must not be a pointer or interface type and it must be
declared in the same package as the method.
That's clear enough: if T denotes a pointer type, then you can't use it as a method receiver.
Note the careful language of the reference here: the phrase "Its type must be of the form T or T*" refers to the syntax-level specification of the method receiver (that is, the "form" of the type). That's different from the phrase "The type denoted by T", where it's talking about the type that T names (that is, what the type "denotes").

Go: Variable to a function, returning an interface

In Go, why can I not have a variable to a function, which returns an interface type?
Here's a minimal test case:
type DummyInterface interface {
Method(string) string
}
// Dummy implements the DummyInterface interface
type Dummy struct{}
func (d Dummy) Method(i string) string {
return i
}
// DummyFunc returns a Dummy pointer (which implements the DummyInterface interface)
var DummyFunc (func() *Dummy) = func() *Dummy {
a := Dummy{}
return &a
}
// DummyInterfaceFunc is declared as returning function returning an object which implements DummyInterface -- it
// is set to DummyFunc, which does return a conforming object
var DummyInterfaceFunc (func() DummyInterface) = DummyFunc
This fails to compile (Playground example here), stating:
cannot use DummyFunc (type func() *Dummy) as type func() DummyInterface in assignment
Yet, as you can see, a *Dummy does implement DummyInterface.
Why is this?
Because *Dummy is not the same type as DummyInterface. The rule that you can assign an object to something of an interface type that object implements only applies in that literal case. If the interface type appears in one of the parameters of a type (i.e. the return type of a function), assignment is not possible.
Refer to the assignability rules for more information.
Assignability
A value x is assignable to a variable of type T ("x is assignable to
T") in any of these cases:
x's type is identical to T.
x's type V and T have identical underlying types and at least one of V or T is not a named type.
T is an interface type and x implements T.
x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not
a named type.
x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
x is an untyped constant representable by a value of type T.
This is a similar concept to: Can I convert a []T to an []interface{}?
Basically func() *Dummy is a different type from func() DummyInterface, and conversion between them is not possible.
You will need to use the interface throughout to make the function signature the same.

Resources