Top Banner
How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016
60

How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

May 29, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

How to avoid Go gotchasby learning internals

Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Page 2: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Gotchas• Go has some gotchas

• Good examples:

• 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs

• Go Traps

• Golang slice append gotcha

Page 3: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Gotchas• Luckily, Go has very few gotchas

• Especially in comparison with other languages

Go

C++

0 75 150 225 300

Page 4: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Gotchas

• So, what is gotcha?

• “a gotcha is a valid construct in a system, program or programming language that works as documented but is counter-intuitive and almost invites mistakes because it is both easy to invoke and unexpected or unreasonable in its outcome”

Page 5: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Gotchas

• Two solutions:

• “fix” the language

• fix the intuition.

• Let’s build some intuition to fight gotchas then.

Page 6: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Gotchas

• Let’s learn some internals and in memory representations

• It worked for me, should work for you as well.

Page 7: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

basic typesCode:

i := 1234 j := int32(4) i64 := int64(999) f := float32(3.14)

Page 8: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Code:

i := 1234 j := int32(4) i64 := int64(999) f := float32(3.14)

1234

i

4

j

3.14

fi64

999

int int32

float32int64

basic types

Page 9: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

structsCode:

type Point struct { X, Y int }

p1 := Point{10, 20}

10

int

20

int

p1

Page 10: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Code:

type Point struct { X, Y int }

p1 := Point{10, 20} p2 := &Point{10, 20}

10

int

20

int

p1

10

int

20

int

p2

0x..

*Point

basic types

Page 11: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

structsCode:

func Foo(p Point) { // ... }

p1 := Point{10, 20} Foo(p1)

10

int

20

int

p1

10

int

20

int

Foo() copy

Page 12: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

structsCode:

func Foo(p *Point) { // ... }

p2 := &Point{10, 20} Foo(p2)

Foo()

copy 10

int

20

int

p2

0x..

*Point

0x..

Page 13: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]intCode:

Page 14: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]int

Go code: src/runtime/malloc.go// newarray allocates an array of n elements of type typ. func newarray(typ *_type, n int) unsafe.Pointer { if n < 0 || uintptr(n) > maxSliceCap(typ.size) { panic(plainError("runtime: allocation size out of range")) } return mallocgc(typ.size*uintptr(n), typ, true) }

Code:

Page 15: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]intCode:

int

Memory:

Page 16: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]intCode: 4 or 8 bytes blocks

(32 or 64 bit arch)

int

Memory:

Page 17: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]intCode:

int0 1 2 3 4

Memory:

Page 18: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

var arr [5]intCode:

int0 1 2 3 4

0 0 0 0 0Memory:

Page 19: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

arrayCode:

Memory:

int0 1 2 3 4

0 0 0 0 42

var arr [5]int arr[4] = 42

Page 20: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []intCode:

Page 21: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []intCode:

Go code: src/runtime/slice.gotype slice struct { array unsafe.Pointer len int cap int }

Page 22: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []intCode:

Go code: src/runtime/slice.go

array

len

cap

0 1 2 3 4

foo

type slice struct { array unsafe.Pointer len int cap int }

Page 23: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

sliceCode:

array

len

cap

0 1 2 3 4

nil

0

0

var foo []intfoo

Page 24: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []int foo = make([]int, 5)

Code:

array

len

cap

000 0 00x..

5

50 1 2 3 40 1 2 3 4

foo

Page 25: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []int foo = make([]int, 3, 5)

Code:

array

len

cap

00 00x..

3

50 1 2 3 40 1 2 3 4

foo

Page 26: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

var foo []int foo = make([]int, 5) foo[3] = 42 foo[4] = 100

Code:

array

len

cap

4200 0 1000 1 2 3 4

0x..

5

50 1 2 3 40 1 2 3 4

foo

Page 27: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

sliceCode:

array

len

cap

0x..

5

5

var foo []int foo = make([]int, 5) foo[3] = 42 foo[4] = 100

bar := foo[1:4]

4200 0 1000 1 2 3 40 1 2 3 40 1 2 3 4

foo

Page 28: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

sliceCode:

array

len

cap

4200 0 100

0

1 2 3 40x..

5

50

1 2 3 40 1 2 3 4

var foo []int foo = make([]int, 5) foo[3] = 42 foo[4] = 100

bar := foo[1:4] array

len

cap

bar

0x..

3

3

foo

Page 29: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

sliceCode:

array

len

cap

42990 0 100

0

1 2 3 4

foo

0x..

5

50

1 2 3 40 1 2 3 4

var foo []int foo = make([]int, 5) foo[3] = 42 foo[4] = 100

bar := foo[1:4] bar[1] = 99

array

len

cap

bar

0x..

3

3

0 1 2

Page 30: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

sliceCode:

var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte { b, _ := ioutil.ReadFile(filename) return digitRegexp.Find(b) }

Page 31: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

slice

array

len

cap

32r 1 $

0

b

0x..

10^6 0

array

len

cap

digitRegexp.Find

0x..

3

3

10^6

xa b c d …

10MB slice

Page 32: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

appendCode:

a := make([]int, 32) a = append(a, 1)

Page 33: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

appendCode:

a := make([]int, 32) a = append(a, 1) fmt.Println("len:", len(b), "cap:", cap(b))

len: 33 cap: 64Output:

Page 34: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

append

array

len

cap

000 0 0a

0x..

32

32

0 1 2 3 40 1 2 30 31

32 ints

a = append(a, 1)

Page 35: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

len

cap

000 0 0

a

0x..

33

640 1 2 3 40 1 2 30 31

… 132 33 34

…35 62 63

32 ints more

32 + 1

doubling 32

000 0 00 1 2 3 40 1 2 30 31

32 ints

Page 36: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

append

array

len

cap

000 0 0

a

0x..

34

640 1 2 3 40 1 2 30 31

… 1 232 33 34

…35 62 63

33 + 1 a = append(a, 2)

64 ints

Page 37: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfacesCode:

type error interface { Error() string }

Page 38: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfacesCode:

Go code: src/runtime/runtime2.go

type iface struct { tab *itab data unsafe.Pointer }

type error interface { Error() string }

Page 39: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

type iface struct { tab *itab data unsafe.Pointer }

type error interface { Error() string }

interfacesCode:

Go code: src/runtime/runtime2.go itab = interface table

Page 40: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

type iface struct { tab *itab data unsafe.Pointer }

type error interface { Error() string }

interfacesCode:

Go code: src/runtime/runtime2.go

type itab struct { inter *interfacetype _type *_type link *itab bad int32 unused int32 fun [1]uintptr }

Page 41: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfacesCode:

tab

data

type error interface { Error() string }

Page 42: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

data

tab

nil

0x..

interfacesCode:

inter

type

nil

error

fun

itab

type error interface { Error() string }

var err error

err

nil interface

Page 43: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfacesCode:

type error interface { Error() string }

func foo() error { return nil }

data

tab

nil

0x..inter

type

nil

error

fun

itab

err

Page 44: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfacesCode:

data

tab

nil

0x..inter

type

nil

error

fun

itab

errfunc foo() error { var err error // err == nil return err }

err := foo() if err != nil { // false }

Page 45: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func foo() error { var err *os.PathError // err == nil return err }

err := foo() if err != nil { // ??? }

Code:

Page 46: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func foo() error { var err *os.PathError // err == nil return err }

err := foo() if err != nil { // true }

Code:

Page 47: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func foo() error { var err *os.PathError // err == nil return err }

err := foo() if err != nil { // true }

Code:

tab0x..

inter

type

*os.PathError

error

fun

itab

err

data

os.PathError

err

nil

0x..

Page 48: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

tab

interfaces

func foo() error { err := &os.PathError{ "open", name, e } return err }

err := foo() if err != nil { // true }

Code:

data0x..

0x..inter

type

*os.PathError

error

fun

itab

err

os.PathError

err“open”

Page 49: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func foo() error { var err *os.PathError // err == nil return err }

func foo() error { var err error // err == nil return err }

data

tab

nil

0x..inter

typenil

error

fun

itab

err

data

tab0x..

inter

type

*os.PathError

error

fun

itab

err

0x..

os.PathError

nil

err

Page 50: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

tab0x..

inter

type

*os.PathError

error

fun

itab

err

data

os.PathError

err

nil

0x..data

tab

nil

0x..inter

type

nil

error

fun

itab

err

!=

Page 51: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

type eface struct { _type *_type data unsafe.Pointer }

type empty interface{}

interfacesCode:

Go code: src/runtime/runtime2.go

_type

data

Page 52: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

int64

0x..

int64

42

empty

foo

var foo int64 = 42

func bar() interface{} { return foo }

Code:

Page 53: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func bar() interface{} { return int64(42) }

Code:

Page 54: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func bar() []interface{} { return []int64{1,2,3,4} }

Code:

Page 55: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

interfaces

func bar() []interface{} { return []int64{1,2,3,4} }

Code:

$ go build cannot use []int literal (type []int) as type []interface {} in return argument

Page 56: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

array

len

cap

[]int

0x..

32

32

4

3131 2 320 1 2 30 1 2 30 31

32 ints

array

len

cap

0x..

32

32

0…

32 interfaces{}[]interface{}

int

0x..

int

1

empty

data

int

0x..

int

2

empty

data

int

0x..

int3

empty

data

0int

0x..

int

31

empty

data

int

0x..

int

32

empty

data

Page 57: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

If you want to do something expensive - do it explicitly

Page 58: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Links

https://divan.github.io/posts/avoid_gotchas/

Page 59: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Links• Must read:

• Go Data Structures

• Go Data Structures: Interfaces

• Go Slices: usage and internals

• Gopher Puzzlers

• And, of course:

• Go source code

• Effective Go

• Go spec

Page 60: How to avoid Go gotchas - divan's blog · How to avoid Go gotchas by learning internals Ivan Danyliuk, Codemotion Milano 26 Nov 2016

Thank you @idanyliuk