Showing posts with label golang_interface. Show all posts
Showing posts with label golang_interface. Show all posts

Mar 23, 2019

[Go] interesting read of Eli Bendersky's "Does a concrete type implement an interface in Go?"

Eli Bendersky has post an interesting article titled
"Does a concrete type implement an interface in Go?"


I really do love seeing C++ experts playing with other languages from their deep understanding of C/C++/Assembly :-)


Go's interface stores embedded data's type information, RTTI in C++, a pointer to v-table minus offset is type information, plus offset are pointers to member functions(index honors declared sequence).

Go's interface stores embedded data act as this pointer in C++, while calling the member functions, copying the embedded data as first parameter into member functions.

Thus, if embedded data is pointer type, then copy the pointer into the member functions.

Alas, if embedded data is instance of the data type, then copy the instance into the member functions.

Go's interface implement:
https://github.com/golang/go/blob/56131cbd1d61ec446e10dfe72a96f329ed3d952a/src/go/types/type.go#L244

Thus, Go's interface type provides an extra layer of abstraction for interface exchanges.

package main

import "fmt"

type fun struct {
}

func (f *fun) run() {
 fmt.Println("stateless member function call.")
}

type I interface {
 run()
}

func main() {
 I((*fun)(nil)).run()
}

C++: https://godbolt.org/z/YWAXze
#include <iostream>

struct fun {
    void run()
    {
        using std::cout;
        using std::endl;
        cout << "stateless member function call." << endl;
    }
};

int main()
{
    static_cast<fun*>(nullptr)->run();
}


Reference:
A book about the internals of the Go programming language
https://github.com/teh-cmc/go-internals

Go 1.1 Function Calls - Russ Cox, February 2013
https://docs.google.com/document/d/1bMwCey-gmqZVTpRax-ESeVuZGmjwbocYs1iHplK-cjo/pub

Go Data Structures: Interfaces, Russ Cox, December 1, 2009.
https://research.swtch.com/interfaces

Go Interfaces, Ian Lance Taylor
https://www.airs.com/blog/archives/277

[golang] reflection quick note
http://vsdmars.blogspot.com/2019/01/golang-reflection-quick-note.html

Feb 15, 2019

[Go] escape analysis discussion

func call(f func()) {
    f()
}

func g() {
    var x int
    
    call(
        func() { x = 1 },  // No escape since 'x' is not used by caller
    )
}

Originally, closures always stored addresses of referenced variables.

At some point an optimization was added that captured variables that are not later modified by the outer function have their values, not their addresses, recorded in the closure.
Please refer to this question on stackoverflow, which is quite interesting due to this side-effect with golang's closure behavior:
https://stackoverflow.com/questions/42162879/mutex-within-loop-leads-to-unexpected-output
package main

import (
    "fmt"
    "sync"
)

func main() {
    mutex := new(sync.Mutex)

    for i := 1; i < 5; i++ {
        for j := 1; j < 5; j++ {
            mutex.Lock()
            go func() {
                fmt.Printf("%d + %d = %d\n", i, j, j+i)
                mutex.Unlock()
            }()
        }
    }
}
---
Result:
1 + 2 = 3
1 + 3 = 4
1 + 4 = 5
2 + 5 = 7
2 + 2 = 4
2 + 3 = 5
2 + 4 = 6
3 + 5 = 8
3 + 2 = 5
3 + 3 = 6
3 + 4 = 7
4 + 5 = 9
4 + 2 = 6
4 + 3 = 7
4 + 4 = 8
---

If not for this optimization, the same problems that force heap allocation above would force heap allocation even for:
func call(f func() int) { 
    f()
}

func g() {
    var x int
    call(func() int { return x })
}

If we tweak that example to modify x after the closure creation, that will disable the closure-value optimization:
func call(f func() int) {
    f()
}

func g() {
    var x int
    call(func() int { return x })  // 'x' escaped to heap since 'x++' from the caller
    x++
}

if the closure itself escapes, then the addresses of the variables are understood to escape too:
func call(f func() *int) *int { 
    f()
    return nil
}

func h() { 
    var y int
    call(
    func() *int { return &y }
    )
}


Or even this:
func h() {
    var y int
    _ = func() *int { return &y }()
}


Both of them decide that &y escapes, and there isn't even a call to analyze in the second.

Golang currently treats values returned by functions (including closures) as escaping to the heap, so there's really no point in worrying that f() might return a value from within the closure.

package p

//go:noinline
func call1(f func() error) error {
 // Leaks *f to result.
 return f()
}

func F1() error {
 y := new(int)
 return call1(func() error {
  y = nil
  return nil
 })
}


//go:noinline
func call2(f func() error) error {
 // No param leakage.
 f()
 return nil
}

func F2() error {
 y := new(int)
 return call2(func() error {
  y = nil
  return nil
 })
}



There's a discussion about interface as function parameter type which causing variable passing in heap allocated.
Reference:
https://www.reddit.com/r/golang/comments/9f9pu8/do_blank_interface_values_escape_to_the_heap/
https://www.reddit.com/r/golang/comments/badeql/golang_memory_escape_analysis_is_naive/
https://stackoverflow.com/a/44699604

The above stackoverflow answer is incorrect, it's not the interface{} being allocated on the heap but the variable it's taken should be allocated on the heap which interface{}'s second pointer will points to it.
(The first pointer will point to type information, or the word will contains the type information, depends on the implement)

Jul 13, 2018

[Go] nil for interface

It isn't that surprise once we know that the interface internal structure contains 2 words. In the below case, explodes interface has a saving to *Bomb, which is nil, but the interface itself isn't nil, which contains *Bomb.
type Explodes interface {
    Bang()
    Boom()
}

// Type Bomb implements Explodes
type Bomb struct {}
func (*Bomb) Bang() {}
func (Bomb) Boom() {}

func main() {
    var bomb *Bomb = nil
    var explodes Explodes = bomb
    println(bomb, explodes) // '0x0 (0x10a7060,0x0)'
    if explodes != nil {
        println("Not nil!") // 'Not nil!' What are we doing here?!?!
        explodes.Bang()     // works fine
        explodes.Boom()     // panic: value method main.Bomb.Boom called using nil *Bomb pointer
    } else {
        println("nil!")     // why don't we end up here?
    }
}
Use reflect to check interface's underlying value is nil or not:
if explodes != nil && !reflect.ValueOf(explodes).IsNil() {
    println("Not nil!") // we no more end up here
    explodes.Bang()
    explodes.Boom()
} else {
    println("nil!")     // 'nil' -- all good!
}

Jun 22, 2018

[Go] define interface type during variable declaration :-)

declare interface on the fly
package main

import (
 "fmt"
)

type Fun struct{
 a int
}

func (f Fun) run() int{
 return 42
}


type Run interface{
 run() int
}

func main() {
 var r interface{ run() int} = Fun{42}
 fmt.Println(r.run())
}
declare struct on the fly
package main

import (
 "fmt"
)

type Fun struct{
 a int
}

func (f Fun) run() int{
 return 42
}


type Run interface{
 run() int
}

func main() {
 var r struct{a int} = Fun{42}
 fmt.Println(r.a)
}