Golang type embedding implement - go

I have a type T which embed type B, and *B implements I. *T can be assigned to a variable of type I but not in the case of T, does this mean (*T)'s method set contains both value and pointer receiver of B?
package main
import (
"fmt"
)
type I interface {
Foo()
}
type B struct {}
type T struct {
B
}
func (a *B) Foo() {
fmt.Println("Bar")
}
func main() {
t := T{B{}}
// var i I = t -> error
var i I = &t
i.Foo()
}

Yes, method set of *T contains methods with receiver B and *B.
Spec: Struct types:
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.

Related

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.

Method set of a receiver type

Spec says:
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, to verify the point, below is the code:
package main
import "fmt"
// I interf
type I interface {
hello()
goodbye()
}
// T type
type T struct {
name string
}
func (t T) hello() {
fmt.Println("Hello", t.name)
}
func (t *T) goodbye() {
fmt.Println("Goodbye", t.name)
}
func main() {
var t1 T = T{"James"}
t1.hello()
t1.goodbye()
}
t1.goodbye() works despite goodbye() method is not part of method set of type T. Because, t1.goodbye() works internally as (&t1).goodbye() that satisfies below rule:
If you have a T and it isn't addressable, you can only call methods that have a receiver type of T, not *T.
But, specs says, method calling follows below rule:
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.
Does invocation of t1.goodbye() as (&t1).goodbye() break method calling rule?
From Calls in the spec...
A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m. If x is addressable and &x's method set contains m, x.m() is shorthand for (&x).m()
t1 is addressable.
&t1's method set contains goodbye().
t1.goodbye() is shorthand for (&t1).goodbye().

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 to use a derived type for sync.Map

My goal is to have a custom type the one I could derive and add extra methods, for example, when using a map this works:
package main
import "fmt"
type myMap map[string]string
func (m *myMap) Add() {
_, ok := (*m)["test"]
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But if want the same with sync.Map how to do it? I am currently trying this: https://play.golang.org/p/8PjpPY-Sjq
package main
import (
"fmt"
"sync"
)
type myMap sync.Map
func (m *myMap) Add() {
_, ok := (*m).Load("test")
println(ok)
}
func main() {
x := &myMap{}
fmt.Printf("x = %+v\n", x)
}
But get this error:
(*m).Load undefined (type myMap has no field or method Load)
Any ideas?
The Go Programming Language Specification
Struct types
A struct is a sequence of named elements, called fields, each of
which has a name and a type. Field names may be specified explicitly
(IdentifierList) or implicitly (EmbeddedField). Within a struct,
non-blank field names must be unique.
StructType = "struct" "{" { FieldDecl ";" } "}" .
FieldDecl = (IdentifierList Type | EmbeddedField) [ Tag ] .
EmbeddedField = [ "*" ] TypeName .
Tag = string_lit .
A field declared with a type but no explicit field name is called an
embedded field. An embedded field must be specified as a type name T
or as a pointer to a non-interface type name *T, and T itself may not
be a pointer type. The unqualified type name acts as the field name.
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.
Promoted fields act like ordinary fields of a struct except that they
cannot be used as field names in composite literals of the struct.
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 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.
Use an embedded field of a struct. For example,
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Load(k)
fmt.Println(k, v, ok)
}
Playground: https://play.golang.org/p/YCNeiYVhlT
Output:
true
test 42 true
The Go Programming Language Specification
Selectors
For a primary expression x that is not a package name, the selector
expression
x.f
denotes the field or method f of the value x (or sometimes *x; see
below). The identifier f is called the (field or method) selector; it
must not be the blank identifier. The type of the selector expression
is the type of f. If x is a package name, see the section on qualified
identifiers.
A selector f may denote a field or method f of a type T, or it may
refer to a field or method f of a nested embedded field of T. The
number of embedded fields traversed to reach f is called its depth in
T. The depth of a field or method f declared in T is zero. The depth
of a field or method f declared in an embedded field A in T is the
depth of f in A plus one.
Rule 1:
For a value x of type T or *T where T is not a pointer or interface
type, x.f denotes the field or method at the shallowest depth in T
where there is such an f. If there is not exactly one f with
shallowest depth, the selector expression is illegal.
Sometimes, there is ambiguity in complex cases of nested embedding. If so, specify the full qualifiers explicitly. For example, m.Map.LoadOrStore and x.Map.Load.
package main
import (
"fmt"
"sync"
)
type myMap struct {
sync.Map
}
func (m *myMap) Add(key, value interface{}) bool {
_, loaded := m.Map.LoadOrStore(key, value)
return !loaded
}
func main() {
x := &myMap{}
k := "test"
ok := x.Add(k, 42)
fmt.Println(ok)
v, ok := x.Map.Load(k)
fmt.Println(k, v, ok)
}
The line: type myMap sync.Map defines a new type based on an existing type.
According to the Language Specification:
A defined type may have methods associated with it. It does not
inherit any methods bound to the given type
It means, that myMap only inherits the fields of sync.Map (which is a struct) but not it's methods. It doesn't work like class inheritance in other languages.
Specifically, sync.Map does not have any exported fields, so using it to define a new type is pointless.
Instead you should define a struct type that contains sync.Map as a field. Then you'll have access to it's methods. #peterSO's answer shows how to do that.

Interface fulfilled by struct embedding

I'm confused by my experiments with the following program, related to fulfilling interface with struct embedding, with named types and pointer receivers, respectively:
package main
import "fmt"
type MyInt interface {
mytest()
}
type Base struct {
}
func (b *Base) mytest() {
fmt.Println("From base")
}
type Derived struct {
Base
}
type Derived2 struct {
*Base
}
func main() {
// Only this one has problem
// However, if we change mytest's receiver from *Base to Base, all the four assignments are OK
var _ MyInt = Derived{}
// OK
var _ MyInt = &Derived{}
var _ MyInt = Derived2{}
var _ MyInt = &Derived2{}
}
See the comments in the code for my confusions. Are there any principal ways to explain them?
From the Go language specification:
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.
The case that doesn't work in your code:
var _ MyInt = Derived{}
Here the method set of Derived (which contains an anonymous field Base) includes methods of Base by rule 1. Since mytest is a method of *Base and not Base, it's promoted to a method of *Derived (by the second rule), but not of Derived.
Why is it like that? Well, it's similar to the rule for method sets of structs: methods of T are also methods of T*, but not vice-versa. That's because a method of a pointer receiver can expect to be able to mutate its receiver, but a method of a non-pointer receiver can't.
As per your code function mytest can be called on receiver which pointer to Base.
Struct Derived inherits/embeds Base and Derived2 inherits/embeds *Base i.e. pointer to base.
For
var _MyInt = &Derived2{}: Here pointer of Derived2 is created and since Dervied2 inherits from *Base calling mytest on _MyInt will work
var _MyInt = Derived2{}: Instance of Derived2 is created and since Dervied2 inherits from *Base calling mytest on _MyInt will work
var _MyInt = &Derived{}: Here pointer of Derived is created and since Dervied inherits from Base calling mytest on _MyInt will work
var _MyInt = Derived{}: Instance of Derived is created and since Dervied inherits from Base calling mytest on _MyInt will not work has pointer to Base is expected.
You rightly pointed out that changing receiver from *Base to Base will work because Go will be able recognize Object from pointer and will be able to call mytest.
As per golang 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).
Hope this helps

Resources