Why implicit non-pointer methods not satisfy interface? - go

Assuming we have an understanding that,
For explicit method definition for type X, GO compiler implicitly defines the same method for type *X and vice versa, if I declare,
func (c Cat) foo(){
//do stuff_
}
and declare,
func (c *Cat) foo(){
// do stuff_
}
then GO compiler gives error,
Compile error: method re-declared
which indicates that, pointer method is implicitly defined and vice versa
In the below code,
package main
type X interface{
foo();
bar();
}
type Cat struct{
}
func (c Cat) foo(){
// do stuff_
}
func (c *Cat) bar(){
// do stuff_
}
func main() {
var c Cat
var p *Cat
var x X
x = p // OK; *Cat has explicit method bar() and implicit method foo()
x = c //compile error: Cat has explicit method foo() and implicit method bar()
}
GO compiler gives error,
cannot use c (type Cat) as type X in assignment:
Cat does not implement X (bar method has pointer receiver)
at x = c, because, implicit pointer methods satisfy interfaces, but implicit non-pointer methods do not.
Question:
Why implicit non-pointer methods do not satisfy interfaces?

Let's look into the language specification:
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).
In your example, the method set of the interface type x is [foo(), bar()]. The method set of the type Cat is [foo()], and the method set of the type *Cat is [foo()] + [bar()] = [foo(), bar()].
This explains, why variable p satisfies the interface x, but variable c doesn't.

Method set
Following the spec:
The method set of any other named type T consists of all methods with receiver type T. The method set of the corresponding pointer type *T is the set of all methods with receiver *T or T (that is, it also contains the method set of T).
Method set definition sounds weird until you follow addressable and not addressable types concept.
Addressable and not addressable types
It is possible to call a pointer receiver method on a value if the value is of addressable type.
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
It is ok to call pointer receiver methods on values till you are dealing with addressable types (struct is addressable):
type Cat struct {}
func (c *Cat) bar() string { return "Mew" }
func main() {
var c Cat
c.bar()
}
Variables of interface type are not addressable
But not all Go types are addressable. Also variables referenced through interfaces are not addressable.
It is impossible to call pointer receiver on values of not addressable types:
type X interface {
bar() string
}
type Cat struct{}
func (c *Cat) bar() string { return "Mew" }
/* Note `cat` variable is not a `struct` type value but
it is type of `X` interface therefor it is not addressable. */
func CatBar(cat X) {
fmt.Print(cat.bar())
}
func main() {
var c Cat
CatBar(c)
}
So with the following error Go runtime prevents segment fault:
cannot use c (type Cat) as type X in assignment:
Cat does not implement X (bar method has pointer receiver)

Add a little to dev.bmax's answer.
type Cat struct{
}
func (c Cat) foo(){
// do stuff_
}
func (c *Cat) bar(){
// do stuff_
}
you can do
var c cat
c.bar() // ok to call bar(), since c is a variable.
but not
cat{}.bar() // not ok to call bar(), c is not a variable.
It's legal to call a *T method on an argument of type T so long as the argument is a variable; the compiler implicitly takes its address. But this is mere syntactic sugar: a value of type T does not posses all methods that a *T pointer does, and as a result it might satisfy fewer interfaces.
On the other hand, you can always call foo() with Cat or *Cat.

How about this?
package main
import (
"fmt"
)
type Growler interface{
Growl() bool
}
type Cat struct{
Name string
Age int
}
// *Cat is good for both objects and "references" (pointers to objects)
func (c *Cat) Speak() bool{
fmt.Println("Meow!")
return true
}
func (c *Cat) Growl() bool{
fmt.Println("Grrr!")
return true
}
func main() {
var felix Cat // is not a pointer
felix.Speak() // works :-)
felix.Growl() // works :-)
var ginger *Cat = new(Cat)
ginger.Speak() // works :-)
ginger.Growl() // works :-)
}

Related

Confused by generics - pointer type parameter?

I'm confused by generics. I've read a bunch of answers to similar questions and I'm still stumped.
I get that the answer here involves telling the compiler that T and *T are related. That while the implicit type conversion from one to the other happens normally in straight code, that doesn't happen in generics without more code. Could someone please walk me through this?
package main
type Mungeable interface {
Munge() // a Mungeable is a thing that can be Munge'd
}
type Box[T Mungeable] struct {
Contents *T // A box is a type based on a Mungeable
}
type Foo struct{} // Foo is a struct...
func (f *Foo) Munge() {} // ...that can be munged.
func (b *Box[Foo]) Print() {
_ = b.Contents.Munge()
}
produces:
./prog.go:16:17: b.Contents.Munge undefined (type *Foo is pointer to type parameter, not type parameter)
Go build failed.
what do I need to change to get this to compile?
playground here: https://go.dev/play/p/gNqxWhlmWmz
Mungable is an interface, a pointer to an interface has no method-set (unlike a pointer to concrete type, which has a method-set containing the methods of its base type in addition to whatever methods were declared for the pointer type), so you need to dereference the pointer before calling the interface's method.
Another issue is that Munge does not have a return value, therefore the assignment statement _ = ...Munge() will cause a compile time error.
The following works:
package main
type Mungeable interface {
Munge() // a Mungeable is a thing that can be Munge'd
}
type Box[T Mungeable] struct {
Contents *T // A box is a type based on a Mungeable
}
type Foo struct{} // Foo is a struct...
func (f *Foo) Munge() {} // ...that can be munged.
func (b *Box[Foo]) Print() {
(*b.Contents).Munge()
}
func main() {}
https://go.dev/play/p/HWW6k47Cdvh
Your understanding of methods and interfaces is wrong. The method set of Foo includes those that defined with the receiver of type Foo, while the method set of *Foo includes methods defined with the receiver of both types Foo and *Foo. Given these declarations
type Mungeable interface {
Munge()
}
type Foo struct {}
func (f *Foo) Munge() {}
Then Foo does not implement Mungeable, it is *Foo that does so. This is reflected in the fact that you cannot assign a value of type Foo to a variable of type Mungeable, and var x Mungeable = new(Foo) is fine. On the contrary, if your Munge method is defined as so
func (f Foo) Munge() {}
Then both Foo and *Foo would implement Mungeable.
The second mistake of yours is that func (f *Box[Foo]) Print() does not define a method with the receiver of type Box[Foo], it defines a method with the receiver of generics type Box with the type parameter declared as Foo. In other words, it is the same as func (f *Box[T]) Print(). If you want to act on Box[Foo] only, then I think you must put it in the parameter list, as I don't think Go allows specialisation of generics classes.
The solution to your problem is that you can just make Contents of type T and change type parameter to *Foo, like this:
package main
type Mungeable interface {
Munge() // a Mungeable is a thing that can be Munge'd
}
type Box[T Mungeable] struct {
Contents T // A box is a type based on a Mungeable
}
type Foo struct{} // Foo is a struct...
func (f *Foo) Munge() {} // ...that can be munged.
func Print(b *Box[*Foo]) {
b.Contents.Munge()
}

Cannot use variable of type *T as type in argument

I'm learning Go 1.18 generics and I'm trying to understand why I'm having trouble here. Long story short, I'm trying to Unmarshal a protobuf and I want the parameter type in blah to "just work". I've simplified the problem as best I could, and this particular code is reproducing the same error message I'm seeing:
./prog.go:31:5: cannot use t (variable of type *T) as type stringer in argument to do:
*T does not implement stringer (type *T is pointer to type parameter, not type parameter)
package main
import "fmt"
type stringer interface {
a() string
}
type foo struct{}
func (f *foo) a() string {
return "foo"
}
type bar struct{}
func (b *bar) a() string {
return "bar"
}
type FooBar interface {
foo | bar
}
func do(s stringer) {
fmt.Println(s.a())
}
func blah[T FooBar]() {
t := &T{}
do(t)
}
func main() {
blah[foo]()
}
I realize that I can completely simplify this example by not using generics (i.e., pass the instance to blah(s stringer) {do(s)}. However, I do want to understand why the error is happening.
What do I need to change with this code so that I can create an instance of T and pass that pointer to a function expecting a particular method signature?
In your code there's no relationship between the constraints FooBar and stringer. Furthermore the methods are implemented on the pointer receivers.
A quick and dirty fix for your contrived program is simply to assert that *T is indeed a stringer:
func blah[T FooBar]() {
t := new(T)
do(any(t).(stringer))
}
Playground: https://go.dev/play/p/zmVX56T9LZx
But this forgoes type safety, and could panic at run time. To preserve compile time type safety, another solution that somewhat preserves your programs' semantics would be this:
type FooBar[T foo | bar] interface {
*T
stringer
}
func blah[T foo | bar, U FooBar[T]]() {
var t T
do(U(&t))
}
So what's going on here?
First, the relationship between a type parameter and its constraint is not identity: T is not FooBar. You cannot use T like it was FooBar, therefore *T is definitely not equivalent to *foo or *bar.
So when you call do(t), you're attempting to pass a type *T into something that expects a stringer, but T, pointer or not, just does not inherently have the a() string method in its type set.
Step 1: add the method a() string into the FooBar interface (by embedding stringer):
type FooBar interface {
foo | bar
stringer
}
But that's not enough yet, because now none of your types actually implement it. Both declare the method on the pointer receiver.
Step 2: change the types in the union to be pointers:
type FooBar interface {
*foo | *bar
stringer
}
This constraint now works, but you have another problem. You can't declare composite literals when the constraint doesn't have a core type. So t := T{} is also invalid. We change it to:
func blah[T FooBar]() {
var t T // already pointer type
do(t)
}
Now this compiles, but t is actually the zero value of a pointer type, so it's nil. Your program doesn't crash because the methods just return some string literal.
If you need to also initialize the memory referenced by the pointers, inside blah you need to know about the base types.
Step 3: So you add T foo | bar as one type param, and change the signature to:
func blah[T foo | bar, U FooBar]() {
var t T
do(U(&t))
}
Done? Not yet. The conversion U(&t) is still invalid because the type set of both U and T don't match. You need to now parametrize FooBar in T.
Step 4: basically you extract FooBar's union into a type param, so that at compile time its type set will include only one of the two types:
type FooBar[T foo | bar] interface {
*T
stringer
}
The constraint now can be instantiated with T foo | bar, preserve type safety, pointer semantics and initialize T to non-nil.
func (f *foo) a() string {
fmt.Println("foo nil:", f == nil)
return "foo"
}
func main() {
blah[foo]()
}
Prints:
foo nil: false
foo
Playground: https://go.dev/play/p/src2sDSwe5H
If you can instantiate blah with pointer types, or even better pass arguments to it, you can remove all the intermediate trickery:
type FooBar interface {
*foo | *bar
stringer
}
func blah[T FooBar](t T) {
do(t)
}
func main() {
blah(&foo{})
}

why pointer type can access all methods of embed type

The following is the source code to try the embed type.
Modify function is defined as func (f *F) Modify(f2 F). Could anyone explain why the Modify function is not shown in the first reflection loop? But in the second reflection loop, both Modify and Validate can be got from *s.
package main
import "fmt"
import "reflect"
type F func(int) bool
func (f F) Validate(n int) bool {
return f(n)
}
func (f *F) Modify(f2 F) {
*f = f2
}
type B bool
func (b B) IsTrue() bool {
return bool(b)
}
func (pb *B) Invert() {
*pb = !*pb
}
type I interface {
Load()
Save()
}
func PrintTypeMethods(t reflect.Type) {
fmt.Println(t, "has", t.NumMethod(), "methods:")
for i := 0; i < t.NumMethod(); i++ {
fmt.Print(" method#", i, ": ",
t.Method(i).Name, "\n")
}
}
func main() {
var s struct {
F
*B
I
}
PrintTypeMethods(reflect.TypeOf(s))
fmt.Println()
PrintTypeMethods(reflect.TypeOf(&s))
}
output:
struct { main.F; *main.B; main.I } has 5 methods:
method#0: Invert
method#1: IsTrue
method#2: Load
method#3: Save
method#4: Validate
*struct { main.F; *main.B; main.I } has 6 methods:
method#0: Invert
method#1: IsTrue
method#2: Load
method#3: Modify
method#4: Save
method#5: Validate
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 embedded 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.
Struct types
A field or method f of an embedded field in a struct x is called
promoted if x.f is a legal selector that denotes that field or method
f.
...
Given a struct type S and a defined type T, promoted methods are
included in the method set of the struct as follows:
If S contains an embedded 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 embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.
If a method m is defined for a type T, that method is available for both T and *T:
type T struct {}
func (t T) m() {}
func main() {
t:=T{}
tp:=&T{}
t.m() // valid: m defined for T
tp.m() // valid: m defined for *T
}
If a method is defined with a pointer receiver, it is only defined for *T and not for T':
func (t *T) n() {}
func main() {
t:=T{}
tp:=&TP{
t.n() // Valid: &t is passed to n
tp.b // valid
mp:=map[int]T{1:t}
mp[1].n() // not valid. mp[1] is not addressable
pp:=map[int]*T{1:&t}
pp[1].n() // valid: pp[1] is *T
}
The reason for this is simple: it prevents unintentionally modifying the copy instead of the indented object. If a method with pointer receiver was available for the value type as well, with the following code:
mp[1].n()
n, taking a pointer receiver, would have modified a copy of the value of mp[1], and not the value stored at mp[1]. The fact that methods with pointer receivers are not available for value types prevents that, and this becomes a compile error, because n is not defined for T, and mp[1] is not addressable, preventing the value to be converted to a pointer by the compiler.

What is meant by 'non-interface method' in the section about method values in the golang specification?

The Go Programming Language Specification says:
As with selectors, a reference to a non-interface method with a value receiver using a pointer will automatically dereference that pointer: pt.Mv is equivalent to (*pt).Mv.
and:
As with method calls, a reference to a non-interface method with a pointer receiver using an addressable value will automatically take the address of that value: t.Mp is equivalent to (&t).Mp.
So, what is non-interface method in the given context?
Interface method means the method you refer to (you call) is a call on an interface value (whose method set contains the method). Similarly, non-interface method means the method you refer to (you call) is not a call on an interface value (but on a concrete type).
For example:
var r io.Reader = os.Stdin
r.Read(nil) // Interface method: type of r is an interface (io.Reader)
var p image.Point = image.Point{}
p.String() // Non-interface method, p is a concrete type (image.Point)
To demonstrate the auto-dereferencing and address taking, see this example:
type myint int
func (m myint) ValueInt() int { return int(m) }
func (m *myint) PtrInt() int { return int(*m) }
func main() {
var m myint = myint(1)
fmt.Println(m.ValueInt()) // Normal
fmt.Println(m.PtrInt()) // (&m).PtrInt()
var p *myint = new(myint)
*p = myint(2)
fmt.Println(p.ValueInt()) // (*p).ValueInt()
fmt.Println(p.PtrInt()) // Normal
}
It outputs (try it on the Go Playground):
1
1
2
2
type T struct {}
func (t *T) f() {}
func main() {
x := T{}
x.f()
}
Above, x.f is a non-interface method.

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

Resources