Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Golang sucks

majek04
November 30, 2017

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
Tweet

More Decks by majek04

Other Decks in Programming

Transcript

  1. 4

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

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

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

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

    / -1; fmt.Println(a) } error: constant 128 overflows int8
  6. 10 func main() { var a int8 a = -127

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

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

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

  10. 15

  11. 17

  12. 18

  13. 21

  14. 23

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

    0xdeadbabe a &^= 0xffff0000 fmt.Printf("%08x\n", a) } 0000babe
  16. x == Nan 31 package main import ( "fmt" "math"

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

    main() { var a int64 var b int32 b = 1 a = int64(b) fmt.Println(a) }
  18. 34 package main import ( "fmt" ) func main() {

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

    for { switch 1 { default: break // !!! } } fmt.Println("Done!") }
  20. 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
  21. 39

  22. 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) }
  23. 51

  24. 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: identifiers 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 }
  25. 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) }
  26. 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
  27. 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
  28. 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; }
  29. Difference? 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 ???? }
  30. 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 {
  31. 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? }
  32. 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? } }
  33. 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)) }
  34. 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
  35. 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
  36. 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)
  37. Assertion vs Conversion • v = aType(t) // type conversion

    • v = t.(aType) // type assertion 72
  38. 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") }
  39. 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
  40. 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) }
  41. 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() }
  42. 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 }
  43. 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
  44. Copy is fine, with relative imports • github.com/cloudflare/golibs • github.com/cloudflare/golibs/foo

    • github.com/cloudflare/golibs/bar • Copy / rename is impossible 84
  45. 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)
  46. 87