majek04
November 30, 2017
51k

# Golang sucks

I found my notes from learning golang couple of years ago. Here are some things that caught me by surprise.

## majek04

November 30, 2017

## Transcript

6. ### Can Golang divide? • Python: -1 / 2 = ?

• Golang: -1 / 2 = ? 6 -1 -0.5 0
7. ### Can Golang divide? • Python: 1 % -2 = ?

• Golang: 1 % -2 = ? 7 -1 1
8. ### 8 func main() { var a int8 a = -127

/ -1; fmt.Println(a) } 127
9. ### 9 func main() { var a int8 a = -128

/ -1; fmt.Println(a) } error: constant 128 overﬂows int8
10. ### 10 func main() { var a int8 a = -127

- 1; a = a / -1; fmt.Println(a) } -128
11. ### 11 func main() { fmt.Println(-11 / 2, -11 >> 1)

} -5 -6 shift is the same as division?
12. ### 12 func main() { var a uint8 a = 1

a = a << 32 fmt.Println(a) } 0 in C it's 1

29. ### &^= operator 29 func main() { var a uint32 =

0xdeadbabe a &^= 0xffff0000 fmt.Printf("%08x\n", a) } 0000babe

a = a + 1
31. ### x == Nan 31 package main import ( "fmt" "math"

) func main() { a := float32(math.NaN()) fmt.Printf("%f\n", a) }
32. ### Mandatory downcasting 32 package main import ( "fmt" ) func

main() { var a int64 var b int32 b = 1 a = int64(b) fmt.Println(a) }

34. ### 34 package main import ( "fmt" ) func main() {

for { switch 1 { case 1: default: } } } Break
35. ### 35 package main import ( "fmt" ) func main() {

for { switch 1 { default: break // !!! } } fmt.Println("Done!") }
36. ### 4k on stack? 36 package main func main() { fmt.Println("Start",

objects()) a := make([]byte, 1 << 18) a[1] = 1 fmt.Println("slice of 1<<18", objects()) b := make([]byte, 1 << 19) b[1] = 1 fmt.Println("sloce of 1<<19", objects()) fmt.Println(">", a[:2], b[:2]) } https://play.golang.org/p/mG01rYDHk8

42. ### Signed vs unsigned 42 • shift >> operator requires unsigned

int • len() returns signed int

45. ### 45 func getTCPSocketFd(socket interface{}) int { // fd is platform-specific

and not exported socketValue := reflect.ValueOf(socket).Elem() fdValue := socketValue.FieldByName("fd") if !fdValue.IsValid() { panic("socket missing fd on this platform") } netFDValue := fdValue.Elem() sysFDValue := netFDValue.FieldByName("sysfd") if !sysFDValue.IsValid() { panic("socket missing fd on this platform") } return int(sysFD) }

52. ### byte slice and string and utf8 • String holds arbitrary

bytes. It is not required to hold Unicode text. • Range on string is magic: • Fact #3: identiﬁers are only exported if they’re part of the Unicode uppercase class 52 const nihongo = "⽇日本語" for index, runeValue := range nihongo { fmt.Printf("%#U starts at byte position %d\n", runeValue, i }

55. ### By value or by reference? 55 func Foo(a T) {

c := "b" *a = *T(&c) } type T *string func main() { c := "a" a := T(&c) Foo(a) fmt.Printf("%q\n", *a) }
56. ### By value or by reference? 56 • String --> immutable

• Pointer to String --> value is immutable • Struct --> mutable, pass-by-value is copying • Pointer to Struct --> mutable • Slice of structs --> mutable • Slice of pointers to structs --> mutable • Maps --> mutable • Chans --> mutable
57. ### Concurrency is half-baked • map is not thread safe (need

to use lock) • especially problematic for slow-iterations • Channels are slow • Mutex is still useful • Channels and network don't integrate • But NET package is blocking and has no multiplexing 57

61. ### C qsort is three-way 61 int compare_ints(const void *p, const

void *q) { int x = *(const int *)p; int y = *(const int *)q; if (x < y) return -1; else if (x > y) return 1; return 0; }
62. ### Diﬀerence? 62 type T struct { foo Foo bar Bar

} func Less(a *T, b *T) { if FooLess(a.foo, b.foo) { return BarLess(a.bar, b.bar) } else ???? }

64. ### 64 var fd *os.File var err error if fd, err

= listenConn.File(); err == nil { var fd *os.File var err error if fd, err := listenConn.File(); err == nil {
65. ### What is an enum? 65 type Stereotype int const (

TypicalNoob Stereotype = iota // 0 TypicalHipster // 1 ) func main() { var s Stereotype var i int s = 6 // What type is s? i = int(s) // What type is s? i = int(TypicalNoob) // What type is TypicalNoob? s = TypicalNoob + 1 // What type is TypicalNoob? }
66. ### 66 type Stereotype int const ( TypicalNoob Stereotype = iota

// 0 TypicalHipster // 1 ) func main() { var s Stereotype s = 6 switch s { case TypicalNoob: fmt.Println("Noob") case TypicalHipster: fmt.Println("Hipster") default: // How come "s" ever get here? } }
67. ### compare interface 67 func is_blank(value interface{}) bool { switch value.(type)

{ case int: if value == 0 { return true } case uint: if value == 0 { return true } } return false } func main() { var my_val uint = 0 fmt.Println(is_blank(my_val)) }

69. ### 69 func is_blank(value interface{}) bool { switch value.(type) { case

int: if value == 0 { return true } case uint: if value == uint(0) { // !!!!! return true } } return false } compare interface
70. ### 70 func is_blank(value interface{}) bool { switch value := value.(type)

{ // !!! case int: if value == 0 { return true } case uint: if value == 0 { return true } } return false } compare interface
71. ### Switching on type 71 package main import ( "fmt" )

func main() { var i int switch i.(type) { case int: fmt.Println("0") case string: fmt.Println("1") } } > cannot type switch on non-interface value i (type int)
72. ### Assertion vs Conversion • v = aType(t) // type conversion

• v = t.(aType) // type assertion 72
73. ### Casting and interface 73 type Lockable interface { Lock() }

func main() { var a = Foo() l := a.(Lockable) fmt.Println("lockable") } type Lockable interface { Lock() } func main() { var a = Foo() l := Lockable(a) fmt.Println("lockable") }
74. ### API evolution • While refactoring my code, can I turn

a struct into an interface with minimal changes? YES • Can I turn a struct into an interface with zero changes for users of my library? NO • To convert whatever-you-got from API to some interface (Lockable) you need to know if it's a struct, pointer to struct or interface. • It makes sense to cast everything to interface{}. 74

76. ### Structure inlining 76 type A struct {} type B struct

{} func (*A)Lock(){ fmt.Println("A") } func (*B)Lock(){ fmt.Println("B") } type C struct { A B } func main() { var c C // c.Lock() // ambiguous selector c.A.Lock() fmt.Println(c) }

78. ### 78 type I interface { F() } type S struct{}

func (p *S) F() { fmt.Printf("p = %v\n", p) } func main() { // A nil interface value var i I fmt.Printf("i == nil: %t\n\n", i == nil) // A non-nil inteface value, containing a nil value of // underlying type: i = (*S)(nil) fmt.Printf("i == nil: %t\n", i == nil) fmt.Printf("i.(*S) == nil: %t\n", i.(*S) == nil) // We can even call methods of S on it: i.F() }

80. ### Errno 80 func ExtractErrno(err error) int { if pe, ok

:= err.(*ProxyError); ok == true { err = pe.Err } if pe, ok := err.(*os.PathError); ok == true { err = pe.Err } if ope, ok := err.(*net.OpError); ok == true { err = ope.Err } if sce, ok := err.(*os.SyscallError); ok == true { err = sce.Err } if se, ok := err.(syscall.Errno); ok == true { return int(se) } return 0 }

82. ### Three indices 82 var array [10]int slice := array[2:4] slice

= array[2:4:7]
83. ### Vendoring is a mess • Fact #18: if you change

your github username, you break every package that depended on one of your packages (extra transition milestone!) • golang prefers the use of global namespace for modules which is wrong 83
84. ### Copy is ﬁne, with relative imports • github.com/cloudﬂare/golibs • github.com/cloudﬂare/golibs/foo

• github.com/cloudﬂare/golibs/bar • Copy / rename is impossible 84

86. ### new vs make 86 // Allocate enough memory to store

a bytes.Buffer value // and return a pointer to the value's address. var buf bytes.Buffer p := &buf // Use a composite literal to perform allocation and // return a pointer to the value's address. p := &bytes.Buffer{} // Use the new function to perform allocation, which will // return a pointer to the value's address. p := new(bytes.Buffer)