
# Go

dudes at Bell labs:
- Ken Thompson		unix, turing award winner
- Rob Pike

now at google.

New *systems* programming language.

Pain points:
- slow builds
- dependency explosion - 
  /sys/stat.h included 37 times  (1984 test, probably much worse now)
  google build of a binary that totaled 4.2 MB of source turned into 8GB seen by compiler
- concurrency, multi-core support built-in
- memory allocation

## Brief tour

(from perspective of C)

- package/include system
- interfaces
  - duck typing
- slices vs arrays
- maps
- typesafe
- goroutines
- channels
- garbage collection

## Preliminaries:
- everything in GOPATH
- **go** build/install/get/run/...
- emacs go-mode comes w/ distribution

### Gotchas:
- all passed by value: pointers, but also stucts, arrays (use slices)
- no pointer arith
- ++ exists, but not expression
- no implicit conversions, but int(4.3)
- no type aliases
  - `type dint int` now distinct types
  - can add methods to user-defined types
- no ternary

**And**:
- no constructors/destructors
- no default args
- no exceptions (but panic/recover)
- no arrays of mixed type


## Packages:
- everything is part of a package
- variables, methods exported by starting with capitalized name


    package "dss"
    
    func invisible(int one) {
        ...
    }
    
    
    func Visible(int one) {
        ...
    }


called: 

    import "blah/pete/dss"
    
    dss.Visible(...)



## Modules
- packages are in modules
- modules encode dependencies, and can be used to fetch them, e.g.:
```
    go mod init
    g mod tidy
```

## Memory allocation
- allocation:
  - new() zeros,
  - make() initializes, for channels, maps, slices...


## Arrays
- fixed size
- passed by value to funcs
- arrays are defined using a fixed size, e.g. `sa :
[3]Int`, or
```
	var sa [3]int = [3]int{1, 2, 3}
	sb := [3]int{1, 2, 3}
	sb2 := [3]int{0:1, 2:3}
	sc := [...]int{1, 2, 3}
	fmt.Println(sa)
	fmt.Println(sb)
	fmt.Println(sb2)
	fmt.Println(sc)
```

## Slices!

	sl := arr[0:2]
	fmt.Println(sl)

	sl2 := []int{4, 5, 6}
	fmt.Println(sl2)

	sl3 := append(sl2, 7, 8)
	fmt.Println(sl3)

	sl2 = append(sl2, 9, 10)
	fmt.Println(sl2)
	fmt.Println(sl3)

[play](https://play.golang.org/p/eMseomDmtBl)

## Maps

    type Vertex struct {
         Lat, Lon, float64
    }
    
    m := map[string] Vertex {
      "one" : {40.8, -74.5},
      "two" : {41.8, -75.5},
    }

keys can be anything that can be sorted (strings, int..)

              = m["four"]
    m["four"] = ...

Returns default value if no exist.

    m["four"], ok = ...

"ok" *true* if in map


## Functions:
       func blah(i int...) int {
       func blah(i int...) (int, int) {
### Methods:
       func (d *Myobj) blah(i int...) (int, int) {


### Interfaces:
- not objects
- just method signatures
- implicit


    type Shape interface {
      func Area() int
    }

ANY type that implements the 'Area' method is implicitly a Shape

How?

Let's say I have another object:

    type Circle struct {
         radius	int
         ....
    }

Now I define:

    func (n *Circle) Area() int {	// receiver/name/args/return
         ....
    }

A Circle is now a Shape!
       - implicit (Duck typing)
       - variables

    c := new(Circle)
    
    var s Shape
    s = c

Can also define:

    func (n *Rect) Area() int ...

    var r      Rect
    s = &r


And a Rect is now a shape.


*Why maybe no good?*

### Cool things: stack is in the heap, so:


Allocation!

    func() *int {
           id := 2
           return &id
    }

### Anonymous functions == Closures!

    func intSeq() func() int {
         i := 0
         return func() int {
         	i += 1
    	    return i
         }
    }
    
    func main() {
         nextInt := intSeq()
         fmt.Println(nextInt())
         fmt.Println(nextInt())
         fmt.Println(nextInt())
    }
[play](https://play.golang.org/p/KIefyeKFEP)


### More fun: fib!

    func fib() func() int {
         i1, i2 := 0, 1
         return func() (r int) {
             r = i1
        	 i1, i2 = i2, i1+i2
        	 return
         }
    }
    
    func main() {
         f := fib()
         for i := 0; i < 10; i++ {
         	 fmt.Println(f())
         }
    }
[play](https://play.golang.org/p/jLDSk4Wend)


## Goroutines
Lightweight threads:

    f(x,y)
    go f(x,y)

Sync w/ *channels*, not explicit locks...


    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func slowFunc(done chan int) {
    	time.Sleep(2*time.Second)
    	fmt.Println("goroutine finish...")
    	done <- 1
    }
    func main() {
    	ch := make(chan int)
    	go slowFunc(ch)
    	fmt.Println("waiting...")
    	<-ch
    	fmt.Println("done!")	
    }
[play](https://go.dev/play/p/96dOj_Vp4m4)

blocking sends, receives until other side ready


    ch := make(chan int, 5)		// buffered

sync library


# Panic / Defer / Recover

```
package main

import (
	"fmt"

	"github.com/pkg/errors"
)

func A() {
	defer fmt.Println("A")
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("Panic: %+v\n", r)
		}
	}()
	B()
}
func B() {
	defer fmt.Println("B")
	C()
}
func C() {
	defer fmt.Println("C")
	Break()
}
func Break() {
	defer fmt.Println("D")
//	panic(errors.New("the show must go on"))
	fmt.Println("after panic")
}
func main() {
	A()
	fmt.Printf("After 'A'\n")
}
```
[play](https://go.dev/play/p/xNP3zxVI3SB)

"Note that unlike some languages which use exceptions for handling of many errors, in Go it is idiomatic to use error-indicating return values wherever possible."

    
