SlideShare a Scribd company logo
Go Says WAT?
Jon Bodner

August 28, 2018
Commodore BASIC
Logo
6502 Assembly
HyperTalk
Lisp
Pascal
Go
C
C++
Java
Ruby
Python
Visual Basic
SQL
JavaScript
DBase IV
RexxProlog Snobol
AppleScript
x86 Assembly
FORTRAN
Objective-C
Scala
Groovy
Go Says WAT?
Go Says WAT?
https://www.destroyallsoftware.com/talks/wat
WAT
Go Says WAT?
Go Says WAT?
Why doesn’t this compile?
Why aren’t these things equal?
Where did my updates go?
Why does Go allow this?
Go Says WAT?
func doubleVals(s []int) {
    for k, v := range s {
        s[k] = v * 2
    }
}
func main() {
    s := []int{1, 2, 3}
    fmt.Println(s) // prints [1 2 3]
    doubleVals(s)
    fmt.Println(s) // prints [2 4 6]
}
func grow(s []int) {
    s = append(s, 4, 5, 6)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Println(s)
    grow(s)
    fmt.Println(s)
}
Question #1
Does Not Compile Panics
Prints 

[1 2 3]
[1 2 3]
Prints 

[1 2 3]
[1 2 3 4 5 6]
A
C
B
D
Does Not Compile Panics
Prints 

[1 2 3]
[1 2 3]
Prints 

[1 2 3]
[1 2 3 4 5 6]
A
C
B
D
func grow(s []int) {
    s = append(s, 4, 5, 6)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Println(s)
    grow(s)
    fmt.Println(s)
}
This reassigned
the slice pointer!
func grow(s []int) {
    fmt.Printf("Start of grow:t%pt%vn", s, s)
    s = append(s, 4, 5, 6)
    fmt.Printf("End of grow:t%pt%vn", s, s)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Printf("Before grow:t%pt%vn", s, s)
    grow(s)
    fmt.Printf("After grow:t%pt%vn", s, s)
}
func grow(s []int) {
    fmt.Printf("Start of grow:t%pt%vn", s, s)
    s = append(s, 4, 5, 6)
    fmt.Printf("End of grow:t%pt%vn", s, s)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Printf("Before grow:t%pt%vn", s, s)
    grow(s)
    fmt.Printf("After grow:t%pt%vn", s, s)
}
func grow(s []int) {
    fmt.Printf("Start of grow:t%pt%vn", s, s)
    s = append(s, 4, 5, 6)
    fmt.Printf("End of grow:t%pt%vn", s, s)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Printf("Before grow:t%pt%vn", s, s)
    grow(s)
    fmt.Printf("After grow:t%pt%vn", s, s)
}
func grow(s []int) {
    fmt.Printf("Start of grow:t%pt%vn", s, s)
    s = append(s, 4, 5, 6)
    fmt.Printf("End of grow:t%pt%vn", s, s)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Printf("Before grow:t%pt%vn", s, s)
    grow(s)
    fmt.Printf("After grow:t%pt%vn", s, s)
}
func grow(s []int) {
    fmt.Printf("Start of grow:t%pt%vn", s, s)
    s = append(s, 4, 5, 6)
    fmt.Printf("End of grow:t%pt%vn", s, s)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Printf("Before grow:t%pt%vn", s, s)
    grow(s)
    fmt.Printf("After grow:t%pt%vn", s, s)
}
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc42001a060 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc42001a060 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc42001a060 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
func grow(s []int) {
    s = append(s, 4, 5, 6)
}
func main() {
    s := make([]int, 0, 10)
    s = append(s, 1, 2, 3)
    fmt.Println(s)
    grow(s)
    fmt.Println(s)
}
Question #2
A
C
B
D
Does Not Compile Panics
Prints 

[1 2 3]
[1 2 3]
Prints 

[1 2 3]
[1 2 3 4 5 6]
A
C
B
D
Does Not Compile Panics
Prints 

[1 2 3]
[1 2 3]
Prints 

[1 2 3]
[1 2 3 4 5 6]
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc420012140 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc420012140 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
Before grow: 0xc420012140 [1 2 3]
Start of grow: 0xc420012140 [1 2 3]
End of grow: 0xc420012140 [1 2 3 4 5 6]
After grow: 0xc420012140 [1 2 3]
Go Says WAT?
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
func makeslice(et *_type, len, cap int) slice {
    // error checking removed
    p := mallocgc(et.size*uintptr(cap), et, true)
    return slice{p, len, cap}
}
/usr/local/go/src/runtime/slice.go
array len cap
3 10
1 2 3
In main
array len cap
3 10
1 2 3
In main
array len cap
3 10
In grow
array len cap
3 10
1 2 3
In main
array len cap
3 10
In grow
6
4 5 6
array len cap
3 10
1 2 3
In main
4 5 6
main can’t
see these!
type SliceHeader struct {
    Data uintptr
    Len int
    Cap int
}
func (v Value) Pointer() uintptr {
    k := v.kind()
    switch k {
    // skipping other cases
    case Slice:
        return (*SliceHeader)(v.ptr).Data
    }
}
/usr/local/go/src/reflect/value.go
type SliceHeader struct {
    Data uintptr
    Len int
    Cap int
}
func (v Value) Pointer() uintptr {
    k := v.kind()
    switch k {
    // skipping other cases
    case Slice:
        return (*SliceHeader)(v.ptr).Data
    }
}
/usr/local/go/src/reflect/value.go
func grow(s *[]int) {
    *s = append(*s, 4, 5, 6)
}
func main() {
    s := []int{1, 2, 3}
    fmt.Println(s)
    grow(&s)
    fmt.Println(s)
}
package main
import (
    "fmt"
)
func main() {
    var m map[string]int
    fmt.Println(m["hello"])
    m["hello"] = 20
    fmt.Println(m["hello"])
}
Question #3
Prints 

0
then Panics
Prints 

0
20
A
C
B
D
Does Not Compile Panics Immediately
Prints 

0
then Panics
Prints 

0
20
A
C
B
D
Does Not Compile Panics Immediately
v := m[k]
m[k] = v
Map Read
Map Write
func walkexpr(n *Node, init *Nodes) *Node {
// skip unrelated code
    switch n.Op {
// skip other cases
    case OINDEXMAP:
        // Replace m[k] with *map{access1,assign}(maptype, m, &k)
        if n.Etype == 1 {
            n = mkcall1(mapfn(mapassign[fast], t), nil, init,
typename(t), map_, key)
        } else {
            n = mkcall1(mapfn(mapaccess1[fast], t),
types.NewPtr(t.Val()), init,
typename(t), map_, key)
        }
// rest of function
}
/usr/local/go/src/cmd/compile/internal/gc/walk.go
func walkexpr(n *Node, init *Nodes) *Node {
// skip unrelated code
    switch n.Op {
// skip other cases
    case OINDEXMAP:
        // Replace m[k] with *map{access1,assign}(maptype, m, &k)
        if n.Etype == 1 {
            n = mkcall1(mapfn(mapassign[fast], t), nil, init,
typename(t), map_, key)
        } else {
            n = mkcall1(mapfn(mapaccess1[fast], t),
types.NewPtr(t.Val()), init,
typename(t), map_, key)
        }
// rest of function
}
/usr/local/go/src/cmd/compile/internal/gc/walk.go
func walkexpr(n *Node, init *Nodes) *Node {
// skip unrelated code
    switch n.Op {
// skip other cases
    case OINDEXMAP:
        // Replace m[k] with *map{access1,assign}(maptype, m, &k)
        if n.Etype == 1 {
            n = mkcall1(mapfn(mapassign[fast], t), nil, init,
typename(t), map_, key)
        } else {
            n = mkcall1(mapfn(mapaccess1[fast], t),
types.NewPtr(t.Val()), init,
typename(t), map_, key)
        }
// rest of function
}
/usr/local/go/src/cmd/compile/internal/gc/walk.go
func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
// skip
    if h == nil || h.count == 0 {
        return unsafe.Pointer(&zeroVal[0])
    }
// rest of function
}
func mapassign(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
    if h == nil {
        panic(plainError("assignment to entry in nil map"))
    }
// rest of function
}
/usr/local/go/src/runtime/hashmap.go
func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
// skip
    if h == nil || h.count == 0 {
        return unsafe.Pointer(&zeroVal[0])
    }
// rest of function
}
func mapassign(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
    if h == nil {
        panic(plainError("assignment to entry in nil map"))
    }
// rest of function
}
/usr/local/go/src/runtime/hashmap.go
func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
// skip
    if h == nil || h.count == 0 {
        return unsafe.Pointer(&zeroVal[0])
    }
// rest of function
}
func mapassign(t *maptype, h *hmap, key unsafe.Pointer)
unsafe.Pointer {
    if h == nil {
        panic(plainError("assignment to entry in nil map"))
    }
// rest of function
}
/usr/local/go/src/runtime/hashmap.go
func main() {
    m := map[string]int{
        "G": 7, "A": 1,
        "C": 3, "E": 5,
        "D": 4, "B": 2,
        "F": 6, "I": 9,
        "H": 8,
    }
    var order []string
    for k, _ := range m {
        order = append(order, k)
    }
    fmt.Println(order)
}
Question #4
Order inserted 

[G A C E D B F I H]
Alphabetical

[A B C D E F G H I]
Reverse
Alphabetical

[I H G F E D C B A]
¯_(ツ)_/¯
A
C
B
D
Order inserted 

[G A C E D B F I H]
Alphabetical

[A B C D E F G H I]
Reverse
Alphabetical

[I H G F E D C B A]
¯_(ツ)_/¯
A
C
B
D
(k,v)
hash(k) = 164742372
hash(k) % (# of buckets) = 4
(k,v)
(k2,v2)
(k,v) (k3,v3)
func main() {
    m := map[string]int{
        "G": 7, "A": 1, "C": 3, "E": 5,
        "D": 4, "B": 2, "F": 6, "I": 9, "H": 8,
    }
    counts := map[string]int{}
    for i := 0; i < 1000000; i++ {
        var order strings.Builder
        for k, _ := range m {
            order.WriteString(k)
        }
        counts[order.String()]++
    }
    fmt.Println(len(counts))
}
Question #5
1 between 1 and 20
between 20 

and 10,000
between 10,000 

and 1,000,000
A
C
B
D
1 between 1 and 20
between 20 

and 10,000
between 10,000 

and 1,000,000
A
C
B
D
Go Says WAT?
• Map order used to be (mostly) consistent
• Maps were vulnerable to Hash DoS
(k,v) (k2,v2) (k3,v3) (k4,v4)
• Maps now include a random seed
• Maps now start iteration from a random bucket,
and from a random element in the bucket
func makemap(t *maptype, hint int, h *hmap) *hmap {
// skip code
    // initialize Hmap
    if h == nil {
        h = (*hmap)(newobject(t.hmap))
    }
    h.hash0 = fastrand()
//rest of function
}
/usr/local/go/src/runtime/hashmap.go
func mapiterinit(t *maptype, h *hmap, it *hiter) {
// skip unrelated code
    // decide where to start
    r := uintptr(fastrand())
    if h.B > 31-bucketCntBits {
        r += uintptr(fastrand()) << 31
    }
    it.startBucket = r & bucketMask(h.B)
    it.offset = uint8(r >> h.B & (bucketCnt - 1))
// rest of function
}
/usr/local/go/src/runtime/hashmap.go
func addStuff(m map[string]int) {
    m["b"] = 20
}
func main() {
    m := map[string]int {
        "a": 10,
    }
    fmt.Println(m)
    addStuff(m)
    fmt.Println(m)
}
Question #6
Prints

map[a:10]
map[a:10]
Prints

map[a:10]
map[a:10 b:20]
A
C
B
D
Does Not Compile Panics
Prints

map[a:10]
map[a:10]
Prints

map[a:10]
map[a:10 b:20]
A
C
B
D
Does Not Compile Panics
func makemap(t *maptype, hint int, h *hmap) *hmap
func makeslice(et *_type, len, cap int) slice
func makemap(t *maptype, hint int, h *hmap) *hmap
func makeslice(et *_type, len, cap int) slice
Pointer!
func makemap(t *maptype, hint int, h *hmap) *hmap
func makeslice(et *_type, len, cap int) slice
Not a pointer!
package main
import "fmt"
func double(i int) (result int) {
    result = i * 2
    return
}
func main() {
    result := double(5)
    fmt.Println(result)
}
package main
import "fmt"
func double(i int) (result int) {
    result = i * 2
    return 20
}
func main() {
    result := double(5)
    fmt.Println(result)
}
Question #7
Prints

10
Prints

20
A
C
B
D
Does Not Compile Panics
Prints

10
Prints

20
A
C
B
D
Does Not Compile Panics
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
Question #8
Prints

20
Prints

31
Prints

33
Prints

61
A
C
B
D
Prints

20
Prints

31
Prints

33
Prints

61
A
C
B
D
Go Says WAT?
• Defers run right before a function exits
• Defers run in reverse order; last one declared is
the first to run
• Go inserts an assignment to the named return
parameter if you specify an explicit return value
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
assigns 20 to result
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
multiplies result by 3
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
adds 1 to result
func watDefer(i int) (result int) {
    defer func() {
        result = result + 1
    }()
    defer func() {
        result = result * 3
    }()
    result = i * 2
    return 20
}
func main() {
    result := watDefer(5)
    fmt.Println(result)
}
prints 61
• state.call in 

/usr/local/go/src/cmd/compile/
internal/gc/ssa.go
• walkstmt in

/usr/local/go/src/cmd/compile/
internal/gc/walk.go
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
Question #9
Prints

1
Prints

94
A
C
B
D
Does Not Compile Panics
Prints

1
Prints

94
A
C
B
D
Does Not Compile Panics
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
function block a
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
function block a
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
function block a
inner block a
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
inner block a
package main
import "fmt"
func main() {
    a := 1
    for i := 0;i<5;i++ {
        a := a + 1
        a = a * 2
    }
    fmt.Println(a)
}
function block a
func watShadow(i int) (ret int) {
    ret = i * 2
    if ret > 10 {
        ret := 10
        return
    }
    return
}
func main() {
    result := watShadow(50)
    fmt.Println(result)
}
Question #10
Does Not Compile Panics
Prints

10
Prints

100
A
C
B
D
Does Not Compile Panics
Prints

10
Prints

100
A
C
B
D
Go Says WAT?
• You get a compiler error message: “ret is
shadowed during return”
• Cannot shadow a variable with same name as
named return parameter and use an empty return
in the block
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
// Skipping lots of code
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class() == PPARAM {
continue
}
if ln.Class() != PPARAMOUT {
break
}
if asNode(ln.Sym.Def) != ln {
yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
// Skipping more code
}
/usr/local/go/src/cmd/compile/internal/gc/noder.go
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
// Skipping lots of code
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class() == PPARAM {
continue
}
if ln.Class() != PPARAMOUT {
break
}
if asNode(ln.Sym.Def) != ln {
yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
// Skipping more code
}
/usr/local/go/src/cmd/compile/internal/gc/noder.go
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
// Skipping lots of code
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class() == PPARAM {
continue
}
if ln.Class() != PPARAMOUT {
break
}
if asNode(ln.Sym.Def) != ln {
yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
// Skipping more code
}
/usr/local/go/src/cmd/compile/internal/gc/noder.go
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
// Skipping lots of code
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class() == PPARAM {
continue
}
if ln.Class() != PPARAMOUT {
break
}
if asNode(ln.Sym.Def) != ln {
yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
// Skipping more code
}
/usr/local/go/src/cmd/compile/internal/gc/noder.go
func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node {
// Skipping lots of code
if n.List.Len() == 0 && Curfn != nil {
for _, ln := range Curfn.Func.Dcl {
if ln.Class() == PPARAM {
continue
}
if ln.Class() != PPARAMOUT {
break
}
if asNode(ln.Sym.Def) != ln {
yyerror("%s is shadowed during return", ln.Sym.Name)
}
}
}
// Skipping more code
}
/usr/local/go/src/cmd/compile/internal/gc/noder.go
func watShadowDefer(i int) (ret int) {
    ret = i * 2
    if ret > 10 {
        ret := 10
        defer func() {
            ret = ret + 1
        }()
    }
    return
}
func main() {
    result := watShadowDefer(50)
    fmt.Println(result)
}
Question #11
Does Not Compile Prints

11
Prints

100
Prints

101
A
C
B
D
Does Not Compile Prints

11
Prints

100
Prints

101
A
C
B
D
func watShadowDefer(i int) (ret int) {
    ret = i * 2
    if ret > 10 {
        ret := 10
        defer func() {
            ret = ret + 1
        }()
    }
    return
}
func main() {
    result := watShadowDefer(50)
    fmt.Println(result)
}
inner block ret
–Me (and everyone else)
“Use go vet -shadow”
package main
import (
    "math"
    "fmt"
)
func main() {
    a := math.MaxUint64
    fmt.Println(a)
}
Question #12
Prints

18446744073709551615
Prints

9223372036854775807
A
C
B
D
Does Not Compile Panics
Prints

18446744073709551615
Prints

9223372036854775807
A
C
B
D
Does Not Compile Panics
Go Says WAT?
package main
import (
    "fmt"
)
func main() {
    var b byte = 'h'
    fmt.Println(b)
}
package main
import (
    "fmt"
)
func main() {
    var b byte = '😀'
    fmt.Println(b)
}
// Integer limit values.
const (
    MaxInt8 = 1<<7 - 1
    MinInt8 = -1 << 7
    MaxInt16 = 1<<15 - 1
    MinInt16 = -1 << 15
    MaxInt32 = 1<<31 - 1
    MinInt32 = -1 << 31
    MaxInt64 = 1<<63 - 1
    MinInt64 = -1 << 63
    MaxUint8 = 1<<8 - 1
    MaxUint16 = 1<<16 - 1
    MaxUint32 = 1<<32 - 1
    MaxUint64 = 1<<64 - 1
)
/usr/local/go/src/math/const.go
• Constants have default types for type inference!
• Default type for integer constant is int
• Default type for rune constant is rune
• Default type for float constant is float64
package main
import (
    "math"
    "fmt"
)
func main() {
    var a uint64 = math.MaxUint64
    fmt.Println(a)
}
type T struct {}
func (t *T) Num() int {
    return 2
}
func main() {
    var t *T
    fmt.Println(t == nil)
    fmt.Println(t.Num())
}
Question #13
Prints

true
2
Prints

false
2
A
C
B
D
Does Not Compile Panics
Prints

true
2
Prints

false
2
A
C
B
D
Does Not Compile Panics
Go Says WAT?
https://speakerdeck.com/campoy/understanding-nil
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
Question #14
false
true
true
true
true
false
A
C
B
D
false
false
false
true
true
true
true
false
A
C
B
D
false
false
type MyError string
func(me MyError) Error() string {
    return string(me)
}
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
Question #15
false
true
true
true
true
false
A
C
B
D
false
false
false
true
true
true
true
false
A
C
B
D
false
false
Go Says WAT?
Nil is weird
Interface
Type
Underlying
Value
Underlying
Type
tab data
var err error
error nilnil
tab data
var err error
var me *MyError
err = me
error nil*MyError
tab data
var err error
var err1 error
err = err1
error nilnil
tab data
• two variables with concrete types compares
values only
• two variables with interface types compares
underlying types and values
• an interface and a concrete type compares
concrete type with underlying type and
compares values
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
Interface type
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
Both type and data are nil
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
Return back nil type
and nil data
func err1() error {
    var err error
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err1()
    fmt.Println(err == nil)
}
Both type and data are nil
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
Concrete type
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
Value is nil
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
Return back *MyError type
and nil data
func err2() error {
    var err *MyError
    fmt.Println(err == nil)
    return err
}
func main() {
    err := err2()
    fmt.Println(err == nil)
}
Type is not nil
type Numer interface {
    Num() int
}
type T struct{}
func (t *T) Num() int {
    return 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
func main() {
    var t *T
    var n Numer
    fmt.Println(t == nil) // true
    fmt.Println(t.Num()) // 2
    fmt.Println(n == nil) // true
    // fmt.Println(n.Num()) // this would panic!
n = t
    fmt.Println(n == nil) // false
    fmt.Println(n.Num()) // 2
}
package main
import "fmt"
func main() {
    true := false
    fmt.Println(true)
}
Question #16
Prints

true
Prints

false
A
C
B
D
Does Not Compile Panics
Prints

true
Prints

false
A
C
B
D
Does Not Compile Panics
Go Says WAT?
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
Types:
    bool byte complex64 complex128 error float32 float64
    int int8 int16 int32 int64 rune string
    uint uint8 uint16 uint32 uint64 uintptr
Constants:
    true false iota
Zero value:
    nil
Functions:
    append cap close complex copy delete imag len
    make new panic print println real recover
package main
import "fmt"
var x int
func main() {
    x := 20
    {
        x := 30
        fmt.Println(x)
    }
    nil := "WAT"
    fmt.Println(x,nil)
}
package main
import "fmt"
var x int
func main() {
    x := 20
    {
        x := 30
        fmt.Println(x)
    }
    nil := "WAT"
    fmt.Println(x,nil)
}
Shadows package block identifier!
package main
import "fmt"
var x int
func main() {
    x := 20
    {
        x := 30
        fmt.Println(x)
    }
    nil := "WAT"
    fmt.Println(x,nil)
}
Shadows function block identifier!
package main
import "fmt"
var x int
func main() {
    x := 20
    {
        x := 30
        fmt.Println(x)
    }
    nil := "WAT"
    fmt.Println(x,nil)
}
Shadows universe block identifier!
type int string
func new(a int) {
    fmt.Println(a)
}
nil := "WAT"
iota := 2
• go vet, go vet -shadow, and
gometalinter don’t catch universe block
shadowing!
• Go doesn’t let you overload operators, functions,
and methods…
• But Go lets you shadow universe block identifiers
• WAT
Shadowing
Shadowing
Go Says WAT?
Thank you!
@jonbodner
github.com/jonbodner
medium.com/@jon_43067

More Related Content

ODP
EcmaScript 6
PDF
ECMAScript 6
PDF
Javascript
PPTX
ES6 in Real Life
PDF
Explaining ES6: JavaScript History and What is to Come
PPT
Whats new in_csharp4
PDF
The Ring programming language version 1.8 book - Part 86 of 202
PDF
ES6 - Next Generation Javascript
EcmaScript 6
ECMAScript 6
Javascript
ES6 in Real Life
Explaining ES6: JavaScript History and What is to Come
Whats new in_csharp4
The Ring programming language version 1.8 book - Part 86 of 202
ES6 - Next Generation Javascript

What's hot (16)

PDF
The mighty js_function
PDF
The Ring programming language version 1.4.1 book - Part 22 of 31
PDF
The Ring programming language version 1.6 book - Part 84 of 189
PDF
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
PDF
Recursion to iteration automation.
PPT
Stack queue
PDF
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
DOC
Ds 2 cycle
PDF
.NET 2015: Будущее рядом
PDF
Coscup2021-rust-toturial
PPT
Cquestions
PPTX
NetPonto - The Future Of C# - NetConf Edition
DOCX
Java Program
PDF
Functional Programming: An Introduction
PDF
Kamil witecki asynchronous, yet readable, code
PDF
Implementing virtual machines in go & c 2018 redux
The mighty js_function
The Ring programming language version 1.4.1 book - Part 22 of 31
The Ring programming language version 1.6 book - Part 84 of 189
서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015
Recursion to iteration automation.
Stack queue
Александр Гранин, Функциональная 'Жизнь': параллельные клеточные автоматы и к...
Ds 2 cycle
.NET 2015: Будущее рядом
Coscup2021-rust-toturial
Cquestions
NetPonto - The Future Of C# - NetConf Edition
Java Program
Functional Programming: An Introduction
Kamil witecki asynchronous, yet readable, code
Implementing virtual machines in go & c 2018 redux
Ad

Similar to Go Says WAT? (20)

PDF
All I know about rsc.io/c2go
PPT
About Go
PPTX
golang_getting_started.pptx
PDF
Introduction to Functional Programming with Haskell and JavaScript
PPTX
Functional Reactive Programming with RxJS
PDF
Implementing Software Machines in Go and C
PDF
Golang and Eco-System Introduction / Overview
PPTX
Workshop 1: Good practices in JavaScript
PDF
Advanced Debugging Using Java Bytecodes
PPTX
Go Programming Language (Golang)
PDF
Rooted 2010 ppp
PDF
Functional programming using underscorejs
PPTX
Groovy
PPTX
Es6 hackathon
PDF
Workshop 10: ECMAScript 6
PDF
Hacking parse.y (RubyKansai38)
ODP
Scala 2 + 2 > 4
PDF
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
PDF
Hacking Parse.y with ujihisa
All I know about rsc.io/c2go
About Go
golang_getting_started.pptx
Introduction to Functional Programming with Haskell and JavaScript
Functional Reactive Programming with RxJS
Implementing Software Machines in Go and C
Golang and Eco-System Introduction / Overview
Workshop 1: Good practices in JavaScript
Advanced Debugging Using Java Bytecodes
Go Programming Language (Golang)
Rooted 2010 ppp
Functional programming using underscorejs
Groovy
Es6 hackathon
Workshop 10: ECMAScript 6
Hacking parse.y (RubyKansai38)
Scala 2 + 2 > 4
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
Hacking Parse.y with ujihisa
Ad

Recently uploaded (20)

PPTX
CHAPTER 2 - PM Management and IT Context
PPTX
Monitoring Stack: Grafana, Loki & Promtail
PPTX
Computer Software and OS of computer science of grade 11.pptx
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PDF
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
PDF
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
PPTX
Reimagine Home Health with the Power of Agentic AI​
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Nekopoi APK 2025 free lastest update
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PDF
Cost to Outsource Software Development in 2025
PPTX
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PDF
iTop VPN 6.5.0 Crack + License Key 2025 (Premium Version)
PDF
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
PPTX
Oracle Fusion HCM Cloud Demo for Beginners
PDF
17 Powerful Integrations Your Next-Gen MLM Software Needs
PPTX
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
CHAPTER 2 - PM Management and IT Context
Monitoring Stack: Grafana, Loki & Promtail
Computer Software and OS of computer science of grade 11.pptx
Why Generative AI is the Future of Content, Code & Creativity?
Product Update: Alluxio AI 3.7 Now with Sub-Millisecond Latency
Tally Prime Crack Download New Version 5.1 [2025] (License Key Free
Reimagine Home Health with the Power of Agentic AI​
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
How to Choose the Right IT Partner for Your Business in Malaysia
Odoo Companies in India – Driving Business Transformation.pdf
Nekopoi APK 2025 free lastest update
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
Cost to Outsource Software Development in 2025
Log360_SIEM_Solutions Overview PPT_Feb 2020.pptx
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
iTop VPN 6.5.0 Crack + License Key 2025 (Premium Version)
How to Make Money in the Metaverse_ Top Strategies for Beginners.pdf
Oracle Fusion HCM Cloud Demo for Beginners
17 Powerful Integrations Your Next-Gen MLM Software Needs
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM

Go Says WAT?

  • 1. Go Says WAT? Jon Bodner August 28, 2018
  • 2. Commodore BASIC Logo 6502 Assembly HyperTalk Lisp Pascal Go C C++ Java Ruby Python Visual Basic SQL JavaScript DBase IV RexxProlog Snobol AppleScript x86 Assembly FORTRAN Objective-C Scala Groovy
  • 8. Why doesn’t this compile? Why aren’t these things equal? Where did my updates go? Why does Go allow this?
  • 10. func doubleVals(s []int) {     for k, v := range s {         s[k] = v * 2     } } func main() {     s := []int{1, 2, 3}     fmt.Println(s) // prints [1 2 3]     doubleVals(s)     fmt.Println(s) // prints [2 4 6] }
  • 11. func grow(s []int) {     s = append(s, 4, 5, 6) } func main() {     s := []int{1, 2, 3}     fmt.Println(s)     grow(s)     fmt.Println(s) } Question #1
  • 12. Does Not Compile Panics Prints [1 2 3] [1 2 3] Prints [1 2 3] [1 2 3 4 5 6] A C B D
  • 13. Does Not Compile Panics Prints [1 2 3] [1 2 3] Prints [1 2 3] [1 2 3 4 5 6] A C B D
  • 14. func grow(s []int) {     s = append(s, 4, 5, 6) } func main() {     s := []int{1, 2, 3}     fmt.Println(s)     grow(s)     fmt.Println(s) } This reassigned the slice pointer!
  • 15. func grow(s []int) {     fmt.Printf("Start of grow:t%pt%vn", s, s)     s = append(s, 4, 5, 6)     fmt.Printf("End of grow:t%pt%vn", s, s) } func main() {     s := []int{1, 2, 3}     fmt.Printf("Before grow:t%pt%vn", s, s)     grow(s)     fmt.Printf("After grow:t%pt%vn", s, s) }
  • 16. func grow(s []int) {     fmt.Printf("Start of grow:t%pt%vn", s, s)     s = append(s, 4, 5, 6)     fmt.Printf("End of grow:t%pt%vn", s, s) } func main() {     s := []int{1, 2, 3}     fmt.Printf("Before grow:t%pt%vn", s, s)     grow(s)     fmt.Printf("After grow:t%pt%vn", s, s) }
  • 17. func grow(s []int) {     fmt.Printf("Start of grow:t%pt%vn", s, s)     s = append(s, 4, 5, 6)     fmt.Printf("End of grow:t%pt%vn", s, s) } func main() {     s := []int{1, 2, 3}     fmt.Printf("Before grow:t%pt%vn", s, s)     grow(s)     fmt.Printf("After grow:t%pt%vn", s, s) }
  • 18. func grow(s []int) {     fmt.Printf("Start of grow:t%pt%vn", s, s)     s = append(s, 4, 5, 6)     fmt.Printf("End of grow:t%pt%vn", s, s) } func main() {     s := []int{1, 2, 3}     fmt.Printf("Before grow:t%pt%vn", s, s)     grow(s)     fmt.Printf("After grow:t%pt%vn", s, s) }
  • 19. func grow(s []int) {     fmt.Printf("Start of grow:t%pt%vn", s, s)     s = append(s, 4, 5, 6)     fmt.Printf("End of grow:t%pt%vn", s, s) } func main() {     s := []int{1, 2, 3}     fmt.Printf("Before grow:t%pt%vn", s, s)     grow(s)     fmt.Printf("After grow:t%pt%vn", s, s) }
  • 20. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc42001a060 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 21. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc42001a060 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 22. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc42001a060 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 23. func grow(s []int) {     s = append(s, 4, 5, 6) } func main() {     s := make([]int, 0, 10)     s = append(s, 1, 2, 3)     fmt.Println(s)     grow(s)     fmt.Println(s) } Question #2
  • 24. A C B D Does Not Compile Panics Prints [1 2 3] [1 2 3] Prints [1 2 3] [1 2 3 4 5 6]
  • 25. A C B D Does Not Compile Panics Prints [1 2 3] [1 2 3] Prints [1 2 3] [1 2 3 4 5 6]
  • 26. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc420012140 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 27. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc420012140 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 28. Before grow: 0xc420012140 [1 2 3] Start of grow: 0xc420012140 [1 2 3] End of grow: 0xc420012140 [1 2 3 4 5 6] After grow: 0xc420012140 [1 2 3]
  • 30. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 31. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 32. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 33. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 34. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 35. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 36. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 37. type slice struct {     array unsafe.Pointer     len int     cap int } func makeslice(et *_type, len, cap int) slice {     // error checking removed     p := mallocgc(et.size*uintptr(cap), et, true)     return slice{p, len, cap} } /usr/local/go/src/runtime/slice.go
  • 38. array len cap 3 10 1 2 3 In main
  • 39. array len cap 3 10 1 2 3 In main array len cap 3 10 In grow
  • 40. array len cap 3 10 1 2 3 In main array len cap 3 10 In grow 6 4 5 6
  • 41. array len cap 3 10 1 2 3 In main 4 5 6 main can’t see these!
  • 42. type SliceHeader struct {     Data uintptr     Len int     Cap int } func (v Value) Pointer() uintptr {     k := v.kind()     switch k {     // skipping other cases     case Slice:         return (*SliceHeader)(v.ptr).Data     } } /usr/local/go/src/reflect/value.go
  • 43. type SliceHeader struct {     Data uintptr     Len int     Cap int } func (v Value) Pointer() uintptr {     k := v.kind()     switch k {     // skipping other cases     case Slice:         return (*SliceHeader)(v.ptr).Data     } } /usr/local/go/src/reflect/value.go
  • 44. func grow(s *[]int) {     *s = append(*s, 4, 5, 6) } func main() {     s := []int{1, 2, 3}     fmt.Println(s)     grow(&s)     fmt.Println(s) }
  • 45. package main import (     "fmt" ) func main() {     var m map[string]int     fmt.Println(m["hello"])     m["hello"] = 20     fmt.Println(m["hello"]) } Question #3
  • 46. Prints 0 then Panics Prints 0 20 A C B D Does Not Compile Panics Immediately
  • 47. Prints 0 then Panics Prints 0 20 A C B D Does Not Compile Panics Immediately
  • 48. v := m[k] m[k] = v Map Read Map Write
  • 49. func walkexpr(n *Node, init *Nodes) *Node { // skip unrelated code     switch n.Op { // skip other cases     case OINDEXMAP:         // Replace m[k] with *map{access1,assign}(maptype, m, &k)         if n.Etype == 1 {             n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)         } else {             n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Val()), init, typename(t), map_, key)         } // rest of function } /usr/local/go/src/cmd/compile/internal/gc/walk.go
  • 50. func walkexpr(n *Node, init *Nodes) *Node { // skip unrelated code     switch n.Op { // skip other cases     case OINDEXMAP:         // Replace m[k] with *map{access1,assign}(maptype, m, &k)         if n.Etype == 1 {             n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)         } else {             n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Val()), init, typename(t), map_, key)         } // rest of function } /usr/local/go/src/cmd/compile/internal/gc/walk.go
  • 51. func walkexpr(n *Node, init *Nodes) *Node { // skip unrelated code     switch n.Op { // skip other cases     case OINDEXMAP:         // Replace m[k] with *map{access1,assign}(maptype, m, &k)         if n.Etype == 1 {             n = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)         } else {             n = mkcall1(mapfn(mapaccess1[fast], t), types.NewPtr(t.Val()), init, typename(t), map_, key)         } // rest of function } /usr/local/go/src/cmd/compile/internal/gc/walk.go
  • 52. func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { // skip     if h == nil || h.count == 0 {         return unsafe.Pointer(&zeroVal[0])     } // rest of function } func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {     if h == nil {         panic(plainError("assignment to entry in nil map"))     } // rest of function } /usr/local/go/src/runtime/hashmap.go
  • 53. func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { // skip     if h == nil || h.count == 0 {         return unsafe.Pointer(&zeroVal[0])     } // rest of function } func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {     if h == nil {         panic(plainError("assignment to entry in nil map"))     } // rest of function } /usr/local/go/src/runtime/hashmap.go
  • 54. func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { // skip     if h == nil || h.count == 0 {         return unsafe.Pointer(&zeroVal[0])     } // rest of function } func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {     if h == nil {         panic(plainError("assignment to entry in nil map"))     } // rest of function } /usr/local/go/src/runtime/hashmap.go
  • 55. func main() {     m := map[string]int{         "G": 7, "A": 1,         "C": 3, "E": 5,         "D": 4, "B": 2,         "F": 6, "I": 9,         "H": 8,     }     var order []string     for k, _ := range m {         order = append(order, k)     }     fmt.Println(order) } Question #4
  • 56. Order inserted 
 [G A C E D B F I H] Alphabetical [A B C D E F G H I] Reverse Alphabetical [I H G F E D C B A] ¯_(ツ)_/¯ A C B D
  • 57. Order inserted 
 [G A C E D B F I H] Alphabetical [A B C D E F G H I] Reverse Alphabetical [I H G F E D C B A] ¯_(ツ)_/¯ A C B D
  • 58. (k,v)
  • 60. hash(k) % (# of buckets) = 4
  • 61. (k,v)
  • 63. func main() {     m := map[string]int{         "G": 7, "A": 1, "C": 3, "E": 5,         "D": 4, "B": 2, "F": 6, "I": 9, "H": 8,     }     counts := map[string]int{}     for i := 0; i < 1000000; i++ {         var order strings.Builder         for k, _ := range m {             order.WriteString(k)         }         counts[order.String()]++     }     fmt.Println(len(counts)) } Question #5
  • 64. 1 between 1 and 20 between 20 and 10,000 between 10,000 and 1,000,000 A C B D
  • 65. 1 between 1 and 20 between 20 and 10,000 between 10,000 and 1,000,000 A C B D
  • 67. • Map order used to be (mostly) consistent • Maps were vulnerable to Hash DoS (k,v) (k2,v2) (k3,v3) (k4,v4)
  • 68. • Maps now include a random seed • Maps now start iteration from a random bucket, and from a random element in the bucket
  • 69. func makemap(t *maptype, hint int, h *hmap) *hmap { // skip code     // initialize Hmap     if h == nil {         h = (*hmap)(newobject(t.hmap))     }     h.hash0 = fastrand() //rest of function } /usr/local/go/src/runtime/hashmap.go
  • 70. func mapiterinit(t *maptype, h *hmap, it *hiter) { // skip unrelated code     // decide where to start     r := uintptr(fastrand())     if h.B > 31-bucketCntBits {         r += uintptr(fastrand()) << 31     }     it.startBucket = r & bucketMask(h.B)     it.offset = uint8(r >> h.B & (bucketCnt - 1)) // rest of function } /usr/local/go/src/runtime/hashmap.go
  • 71. func addStuff(m map[string]int) {     m["b"] = 20 } func main() {     m := map[string]int {         "a": 10,     }     fmt.Println(m)     addStuff(m)     fmt.Println(m) } Question #6
  • 74. func makemap(t *maptype, hint int, h *hmap) *hmap func makeslice(et *_type, len, cap int) slice
  • 75. func makemap(t *maptype, hint int, h *hmap) *hmap func makeslice(et *_type, len, cap int) slice Pointer!
  • 76. func makemap(t *maptype, hint int, h *hmap) *hmap func makeslice(et *_type, len, cap int) slice Not a pointer!
  • 77. package main import "fmt" func double(i int) (result int) {     result = i * 2     return } func main() {     result := double(5)     fmt.Println(result) }
  • 78. package main import "fmt" func double(i int) (result int) {     result = i * 2     return 20 } func main() {     result := double(5)     fmt.Println(result) } Question #7
  • 81. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) } Question #8
  • 85. • Defers run right before a function exits • Defers run in reverse order; last one declared is the first to run • Go inserts an assignment to the named return parameter if you specify an explicit return value
  • 86. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) }
  • 87. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) } assigns 20 to result
  • 88. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) } multiplies result by 3
  • 89. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) } adds 1 to result
  • 90. func watDefer(i int) (result int) {     defer func() {         result = result + 1     }()     defer func() {         result = result * 3     }()     result = i * 2     return 20 } func main() {     result := watDefer(5)     fmt.Println(result) } prints 61
  • 91. • state.call in 
 /usr/local/go/src/cmd/compile/ internal/gc/ssa.go • walkstmt in
 /usr/local/go/src/cmd/compile/ internal/gc/walk.go
  • 92. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } Question #9
  • 95. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) }
  • 96. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } function block a
  • 97. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } function block a
  • 98. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } function block a inner block a
  • 99. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } inner block a
  • 100. package main import "fmt" func main() {     a := 1     for i := 0;i<5;i++ {         a := a + 1         a = a * 2     }     fmt.Println(a) } function block a
  • 101. func watShadow(i int) (ret int) {     ret = i * 2     if ret > 10 {         ret := 10         return     }     return } func main() {     result := watShadow(50)     fmt.Println(result) } Question #10
  • 102. Does Not Compile Panics Prints 10 Prints 100 A C B D
  • 103. Does Not Compile Panics Prints 10 Prints 100 A C B D
  • 105. • You get a compiler error message: “ret is shadowed during return” • Cannot shadow a variable with same name as named return parameter and use an empty return in the block
  • 106. func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { // Skipping lots of code if n.List.Len() == 0 && Curfn != nil { for _, ln := range Curfn.Func.Dcl { if ln.Class() == PPARAM { continue } if ln.Class() != PPARAMOUT { break } if asNode(ln.Sym.Def) != ln { yyerror("%s is shadowed during return", ln.Sym.Name) } } } // Skipping more code } /usr/local/go/src/cmd/compile/internal/gc/noder.go
  • 107. func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { // Skipping lots of code if n.List.Len() == 0 && Curfn != nil { for _, ln := range Curfn.Func.Dcl { if ln.Class() == PPARAM { continue } if ln.Class() != PPARAMOUT { break } if asNode(ln.Sym.Def) != ln { yyerror("%s is shadowed during return", ln.Sym.Name) } } } // Skipping more code } /usr/local/go/src/cmd/compile/internal/gc/noder.go
  • 108. func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { // Skipping lots of code if n.List.Len() == 0 && Curfn != nil { for _, ln := range Curfn.Func.Dcl { if ln.Class() == PPARAM { continue } if ln.Class() != PPARAMOUT { break } if asNode(ln.Sym.Def) != ln { yyerror("%s is shadowed during return", ln.Sym.Name) } } } // Skipping more code } /usr/local/go/src/cmd/compile/internal/gc/noder.go
  • 109. func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { // Skipping lots of code if n.List.Len() == 0 && Curfn != nil { for _, ln := range Curfn.Func.Dcl { if ln.Class() == PPARAM { continue } if ln.Class() != PPARAMOUT { break } if asNode(ln.Sym.Def) != ln { yyerror("%s is shadowed during return", ln.Sym.Name) } } } // Skipping more code } /usr/local/go/src/cmd/compile/internal/gc/noder.go
  • 110. func (p *noder) stmtFall(stmt syntax.Stmt, fallOK bool) *Node { // Skipping lots of code if n.List.Len() == 0 && Curfn != nil { for _, ln := range Curfn.Func.Dcl { if ln.Class() == PPARAM { continue } if ln.Class() != PPARAMOUT { break } if asNode(ln.Sym.Def) != ln { yyerror("%s is shadowed during return", ln.Sym.Name) } } } // Skipping more code } /usr/local/go/src/cmd/compile/internal/gc/noder.go
  • 111. func watShadowDefer(i int) (ret int) {     ret = i * 2     if ret > 10 {         ret := 10         defer func() {             ret = ret + 1         }()     }     return } func main() {     result := watShadowDefer(50)     fmt.Println(result) } Question #11
  • 112. Does Not Compile Prints 11 Prints 100 Prints 101 A C B D
  • 113. Does Not Compile Prints 11 Prints 100 Prints 101 A C B D
  • 114. func watShadowDefer(i int) (ret int) {     ret = i * 2     if ret > 10 {         ret := 10         defer func() {             ret = ret + 1         }()     }     return } func main() {     result := watShadowDefer(50)     fmt.Println(result) } inner block ret
  • 115. –Me (and everyone else) “Use go vet -shadow”
  • 116. package main import (     "math"     "fmt" ) func main() {     a := math.MaxUint64     fmt.Println(a) } Question #12
  • 120. package main import (     "fmt" ) func main() {     var b byte = 'h'     fmt.Println(b) }
  • 121. package main import (     "fmt" ) func main() {     var b byte = '😀'     fmt.Println(b) }
  • 122. // Integer limit values. const (     MaxInt8 = 1<<7 - 1     MinInt8 = -1 << 7     MaxInt16 = 1<<15 - 1     MinInt16 = -1 << 15     MaxInt32 = 1<<31 - 1     MinInt32 = -1 << 31     MaxInt64 = 1<<63 - 1     MinInt64 = -1 << 63     MaxUint8 = 1<<8 - 1     MaxUint16 = 1<<16 - 1     MaxUint32 = 1<<32 - 1     MaxUint64 = 1<<64 - 1 ) /usr/local/go/src/math/const.go
  • 123. • Constants have default types for type inference! • Default type for integer constant is int • Default type for rune constant is rune • Default type for float constant is float64
  • 124. package main import (     "math"     "fmt" ) func main() {     var a uint64 = math.MaxUint64     fmt.Println(a) }
  • 125. type T struct {} func (t *T) Num() int {     return 2 } func main() {     var t *T     fmt.Println(t == nil)     fmt.Println(t.Num()) } Question #13
  • 130. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) } Question #14
  • 133. type MyError string func(me MyError) Error() string {     return string(me) } func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) } Question #15
  • 139. var err error error nilnil tab data
  • 140. var err error var me *MyError err = me error nil*MyError tab data
  • 141. var err error var err1 error err = err1 error nilnil tab data
  • 142. • two variables with concrete types compares values only • two variables with interface types compares underlying types and values • an interface and a concrete type compares concrete type with underlying type and compares values
  • 143. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) }
  • 144. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) } Interface type
  • 145. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) } Both type and data are nil
  • 146. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) } Return back nil type and nil data
  • 147. func err1() error {     var err error     fmt.Println(err == nil)     return err } func main() {     err := err1()     fmt.Println(err == nil) } Both type and data are nil
  • 148. func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) }
  • 149. func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) } Concrete type
  • 150. func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) } Value is nil
  • 151. func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) } Return back *MyError type and nil data
  • 152. func err2() error {     var err *MyError     fmt.Println(err == nil)     return err } func main() {     err := err2()     fmt.Println(err == nil) } Type is not nil
  • 153. type Numer interface {     Num() int } type T struct{} func (t *T) Num() int {     return 2 }
  • 154. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 155. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 156. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 157. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 158. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 159. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 160. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 161. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 162. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 163. func main() {     var t *T     var n Numer     fmt.Println(t == nil) // true     fmt.Println(t.Num()) // 2     fmt.Println(n == nil) // true     // fmt.Println(n.Num()) // this would panic! n = t     fmt.Println(n == nil) // false     fmt.Println(n.Num()) // 2 }
  • 164. package main import "fmt" func main() {     true := false     fmt.Println(true) } Question #16
  • 168. break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var
  • 169. Types:     bool byte complex64 complex128 error float32 float64     int int8 int16 int32 int64 rune string     uint uint8 uint16 uint32 uint64 uintptr Constants:     true false iota Zero value:     nil Functions:     append cap close complex copy delete imag len     make new panic print println real recover
  • 170. package main import "fmt" var x int func main() {     x := 20     {         x := 30         fmt.Println(x)     }     nil := "WAT"     fmt.Println(x,nil) }
  • 171. package main import "fmt" var x int func main() {     x := 20     {         x := 30         fmt.Println(x)     }     nil := "WAT"     fmt.Println(x,nil) } Shadows package block identifier!
  • 172. package main import "fmt" var x int func main() {     x := 20     {         x := 30         fmt.Println(x)     }     nil := "WAT"     fmt.Println(x,nil) } Shadows function block identifier!
  • 173. package main import "fmt" var x int func main() {     x := 20     {         x := 30         fmt.Println(x)     }     nil := "WAT"     fmt.Println(x,nil) } Shadows universe block identifier!
  • 175. func new(a int) {     fmt.Println(a) }
  • 177. • go vet, go vet -shadow, and gometalinter don’t catch universe block shadowing! • Go doesn’t let you overload operators, functions, and methods… • But Go lets you shadow universe block identifiers • WAT