# interface
###### tags: `go`
---
# mindset
<iframe width='853' height='480' src='https://embed.coggle.it/diagram/YKJOeq_K-GlZJak_/085f1074095d4d0c0e28aa032acbe150651bbddc3705f8d50a20d66dc1593ae1' frameborder='0' allowfullscreen></iframe>
---
## design concept
### spec
`Interface types`
> An interface type specifies a method set called its interface. A variable of interface type can store a value of any type with a method set that is any superset of the interface. Such a type is said to implement the interface. The value of an uninitialized variable of interface type is nil.
`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.
>
>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.
### Russ Cox
https://research.swtch.com/interfaces
- duck typing like you would in a purely dynamic language like Python but still have the compiler catch obvious mistakes
- interface values: Languages with methods typically fall into one of two camps: prepare tables for all the method calls statically (as in C++ and Java), or do a method lookup at each call (as in Smalltalk and its many imitators, JavaScript and Python included) and add fancy caching to make that call efficient. Go sits halfway between the two: **it has method tables but computes them at run time**
- empty interface : iface with memory optimization
- Method Lookup Performance: Smalltalk and the many dynamic systems that have followed it perform **a method lookup every time a method gets called. For speed, many implementations use a simple one-entry cache at each call site**, often in the instruction stream itself. In a multithreaded program, these caches must be managed carefully, since **multiple threads could be at the same call site simultaneously**. Even once the races have been avoided, **the caches would end up being a source of memory contention**. Because Go has the hint of static typing to go along with the dynamic method lookups, it can move the lookups back from the call sites to the point when the value is stored in the interface


itab: interface table or itable
The itable begins with some metadata about the types involved and then becomes a list of function pointers. Note that the itable corresponds to the interface type, not the dynamic type. In terms of our example, the itable for Stringer holding type Binary lists the methods used to satisfy Stringer, which is just String: Binary's other methods (Get) make no appearance in the itable.
### Rob Pike
https://groups.google.com/g/golang-nuts/c/osyRcx_hcH8
> On May 25, 2010, at 2:25 PM, Qwertie wrote:
>> I'm curious how much slower Go interface dispatch is compared to
>> traditional vtable dispatch.
>
>It's essentially the same. **Method dispatch on an interface variable
is the same as a vtable dispatch**.
>
>> There have been some suggestions in older posts that Go code is slow
>> like dynamic languages - is Go still highly unoptimized? If interface
>> dispatch is not optimized, does there exist a theoretically fast
>> dispatch technique for go interfaces?
>
>The relatively expensive operation is assignment to an interface value
>, but even it is pretty cheap. The first time a concrete type hits an
interface type, it builds a hash table entry that points to a vtable.
Second and subsequent assignments of the same type will do a much
cheaper hash lookup to find the vtable. But the method dispatch
itself is always equivalent to a vtable lookup.
For the detail-obsessed, this program:
package main
type X interface { m() }
type C int
func (c C) m() {}
func main() {
var c C = 3
var x X = c // line 10
x.m() // line 11
}
Produces this code from 6g:
--- prog list "main" ---
0002 (x.go:11) TEXT main+0(SB),$64-0
0003 (x.go:9) MOVL $3,AX
0004 (x.go:10) MOVQ $type."".X+0(SB),(SP)
0005 (x.go:10) MOVQ $type."".C+0(SB),8(SP)
0006 (x.go:10) MOVL AX,16(SP)
0007 (x.go:10) CALL ,runtime.ifaceT2I+0(SB)
0008 (x.go:10) LEAQ 24(SP),SI
0009 (x.go:10) LEAQ x+-24(SP),DI
0010 (x.go:10) MOVSQ ,
0011 (x.go:10) MOVSQ ,
0012 (x.go:11) LEAQ x+-24(SP),BX
0013 (x.go:11) MOVQ 8(BX),BP
0014 (x.go:11) MOVQ BP,(SP)
0015 (x.go:11) MOVQ (BX),BX
0016 (x.go:11) MOVQ 32(BX),BX
0017 (x.go:11) CALL ,BX
0018 (x.go:11) RET ,
You can see that line 10, which assigns to the interface, calls a
helper function (ifaceT2I) that converts the type to an interface. It
will build the object the first time C and X are connected. Line 11
is essentially an vtable call: it pushes the receiver on the stack and
then does an indirect function call.
### Ian Lance Taylor
https://www.airs.com/blog/archives/277
> Interfaces in Go are similar to ideas in several other programming languages: **pure abstract virtual base classes in C++; typeclasses in Haskell; duck typing in Python; etc**. That said, I’m not aware of any other language which combines interface values, static type checking, dynamic runtime conversion, and no requirement for explicitly declaring that a type satisfies an interface. The result in Go is powerful, flexible, efficient, and easy to write.
### 小結
go interface 設計可以減少空間 (對比 vtable 佔用較多空間), 相比於一般 runtime 時 method lookup + cache 的動態語言, 效能較佳
## _type
`runtime/type.go`
```go=
// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
// ../reflect/type.go:/^type.rtype.
// ../internal/reflectlite/type.go:/^type.rtype.
type _type struct {
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag tflag
align uint8
fieldAlign uint8
kind uint8
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
gcdata *byte
str nameOff
ptrToThis typeOff
}
```
## interface type in reflect

```go=
// imethod represents a method on an interface type
type imethod struct {
name nameOff // name of method
typ typeOff // .(*FuncType) underneath
}
// interfaceType represents an interface type.
type interfaceType struct {
rtype
pkgPath name // import path
methods []imethod // sorted by hash
}
func (t *rtype) AssignableTo(u Type) bool {
if u == nil {
panic("reflect: nil type passed to Type.AssignableTo")
}
uu := u.(*rtype)
return directlyAssignable(uu, t) || implements(uu, t)
}
// implements reports whether the type V implements the interface type T.
func implements(T, V *rtype) bool {
if T.Kind() != Interface {
return false
}
t := (*interfaceType)(unsafe.Pointer(T))
if len(t.methods) == 0 {
return true
}
// The same algorithm applies in both cases, but the
// method tables for an interface type and a concrete type
// are different, so the code is duplicated.
// In both cases the algorithm is a linear scan over the two
// lists - T's methods and V's methods - simultaneously.
// Since method tables are stored in a unique sorted order
// (alphabetical, with no duplicate method names), the scan
// through V's methods must hit a match for each of T's
// methods along the way, or else V does not implement T.
// This lets us run the scan in overall linear time instead of
// the quadratic time a naive search would require.
// See also ../runtime/iface.go.
if V.Kind() == Interface {
v := (*interfaceType)(unsafe.Pointer(V))
i := 0
for j := 0; j < len(v.methods); j++ {
tm := &t.methods[i]
tmName := t.nameOff(tm.name)
vm := &v.methods[j]
vmName := V.nameOff(vm.name)
if vmName.name() == tmName.name() && V.typeOff(vm.typ) == t.typeOff(tm.typ) {
if !tmName.isExported() {
tmPkgPath := tmName.pkgPath()
if tmPkgPath == "" {
tmPkgPath = t.pkgPath.name()
}
vmPkgPath := vmName.pkgPath()
if vmPkgPath == "" {
vmPkgPath = v.pkgPath.name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.methods) {
return true
}
}
}
return false
}
v := V.uncommon()
if v == nil {
return false
}
i := 0
vmethods := v.methods()
for j := 0; j < int(v.mcount); j++ {
tm := &t.methods[i]
tmName := t.nameOff(tm.name)
vm := vmethods[j]
vmName := V.nameOff(vm.name)
if vmName.name() == tmName.name() && V.typeOff(vm.mtyp) == t.typeOff(tm.typ) {
if !tmName.isExported() {
tmPkgPath := tmName.pkgPath()
if tmPkgPath == "" {
tmPkgPath = t.pkgPath.name()
}
vmPkgPath := vmName.pkgPath()
if vmPkgPath == "" {
vmPkgPath = V.nameOff(v.pkgPath).name()
}
if tmPkgPath != vmPkgPath {
continue
}
}
if i++; i >= len(t.methods) {
return true
}
}
}
return false
}
func (t *interfaceType) Method(i int) (m Method) {
if i < 0 || i >= len(t.methods) {
return
}
p := &t.methods[i]
pname := t.nameOff(p.name)
m.Name = pname.name()
if !pname.isExported() {
m.PkgPath = pname.pkgPath()
if m.PkgPath == "" {
m.PkgPath = t.pkgPath.name()
}
}
m.Type = toType(t.typeOff(p.typ))
m.Index = i
return
}
// NumMethod returns the number of interface methods in the type's method set.
func (t *interfaceType) NumMethod() int { return len(t.methods) }
// MethodByName method with the given name in the type's method set.
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
if t == nil {
return
}
var p *imethod
for i := range t.methods {
p = &t.methods[i]
if t.nameOff(p.name).name() == name {
return t.Method(i), true
}
}
return
}
```
## interface 的比較
`alg.go`
```go=
func nilinterequal(p, q unsafe.Pointer) bool {
x := *(*eface)(p)
y := *(*eface)(q)
return x._type == y._type && efaceeq(x._type, x.data, y.data)
}
func efaceeq(t *_type, x, y unsafe.Pointer) bool {
if t == nil {
return true
}
eq := t.equal
if eq == nil {
panic(errorString("comparing uncomparable type " + t.string()))
}
if isDirectIface(t) {
// Direct interface types are ptr, chan, map, func, and single-element structs/arrays thereof.
// Maps and funcs are not comparable, so they can't reach here.
// Ptrs, chans, and single-element items can be compared directly using ==.
return x == y
}
return eq(x, y)
}
func ifaceeq(tab *itab, x, y unsafe.Pointer) bool {
if tab == nil {
return true
}
t := tab._type
eq := t.equal
if eq == nil {
panic(errorString("comparing uncomparable type " + t.string()))
}
if isDirectIface(t) {
// See comment in efaceeq.
return x == y
}
return eq(x, y)
}
```
## Improvement
### new itab lookup table
https://go-review.googlesource.com/c/go/+/44472/6/src/runtime/iface.go
## Articles
https://github.com/teh-cmc/go-internals/blob/master/chapter2_interfaces/README.md#reconstructing-an-itab-from-an-executable
---
## Dynamic dispatch
## go: initializing itab table in runtime

### java

source: https://www.geeksforgeeks.org/dynamic-method-dispatch-runtime-polymorphism-java/

source: https://lukasatkinson.de/2018/interface-dispatch
### C++

source: https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/
### dynamic dispatch between go and rust
rust: traits7
https://softwareengineering.stackexchange.com/questions/247298/how-are-rust-traits-different-from-go-interfaces
## Reference

LEAQ (%rdx), %rdi : move register value to rdi
MOVQ (%rdx), %rsi :move value the register point to to rdi
`movq (%rdi, %rsi, 8), %rbp`
This loads the value at the memory location %rdi + %rsi * 8 into the register %rbp. That is: get the value in the register %rdi and the value in the register %rsi. Multiply the latter by 8, and then add it to the former. Find the value at this location and place it into the register %rbp.
leaq (%rdi, %rsi, 8), %rbp
Just as the use of movq corresponded to dereferencing, the use of leaq here corresponds to not dereferencing. This line of assembly corresponds to the C line x = &array[i];. Recall that & changes the meaning of array[i] from dereferencing to simply specifying a location. Likewise, the use of leaq changes the meaning of (%rdi, %rsi, 8) from dereferencing to specifying a location.
```
MOVL 16(%ebp), %eax /* put long at ebp+16 into eax */
LEAL 16(%ebp), %eax /* add 16 to ebp and store in eax */
MOVQ (%rdx,%rcx,8), %rax /* put qword at rcx*8 + rdx into rax */
LEAQ (%rdx,%rcx,8), %rax /* put value of "rcx*8 + rdx" into rax */
MOVW 5(%bp,%si), %ax /* put word at si + bp + 5 into ax */
LEAW 5(%bp,%si), %ax /* put value of "si + bp + 5" into ax */
MOVQ 16(%rip), %rax /* put qword at rip + 16 into rax */
LEAQ 16(%rip), %rax /* add 16 to instruction pointer and store in rax */
MOVL label(,1), %eax /* put long at label into eax */
LEAL label(,1), %eax /* put the address of the label into eax */
```
https://www.airs.com/blog/archives/281
https://pabloariasal.github.io/2017/06/10/understanding-virtual-tables/
https://www.keithschwarz.com/cs143/WWW/sum2011/lectures/120_Runtime_Environments_2.pdf
{"metaMigratedAt":"2023-06-16T01:14:01.508Z","metaMigratedFrom":"Content","title":"interface","breaks":true,"contributors":"[{\"id\":\"42c52d5e-3a63-4721-a5c2-92e221ef68fb\",\"add\":14883,\"del\":707}]"}