Top Banner
Go it’s not just for Google Eleanor McHugh http://slides.games-with-brains.net/ Rough Cut!
54

Go: It's Not Just For Google

May 06, 2015

Download

Technology

Eleanor McHugh

Another slab of Google Go madness with an emphasis on code and reflection.
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: Go: It's Not Just For Google

Goit’s not just for Google

Eleanor McHugh

http://slides.games-with-brains.net/

Rough Cut!

Page 2: Go: It's Not Just For Google

compiled

Page 3: Go: It's Not Just For Google

garbage collected

Page 4: Go: It's Not Just For Google

imperative

Page 5: Go: It's Not Just For Google

package main

import “fmt”

const HELLO string = “hello”var WORLD string = “world”

func main() { fmt.Println(HELLO, WORLD)}

Page 6: Go: It's Not Just For Google

strongly typed

Page 7: Go: It's Not Just For Google

value

boolean, numeric, array

value

structure, interface

reference pointer, slice, string, map, channel

function function, method, closure

Page 8: Go: It's Not Just For Google

underlyingtype

methodset

expressedtype

Page 9: Go: It's Not Just For Google

underlyingtype

methodset

expressedtype

embeddedtypes

Page 10: Go: It's Not Just For Google

package Integer

type Int int

func (i *Int) Add(x int) { *i += Int(x)}

Page 11: Go: It's Not Just For Google

type Buffer []Int

func (b Buffer) Swap(i, j int) { b[i], b[j] = b[j], b[i]}

func (b Buffer) Clone() Buffer { s := make(Buffer, len(b)) copy(s, b) return s}

func (b Buffer) Move(i, n int) { if n > len(b) - i { n = len(b) - i } segment_to_move := b[:i].Clone() copy(b, b[i:i + n]) copy(b[n:i + n], segment_to_move)}

Page 12: Go: It's Not Just For Google

package main

import “fmt”import "Integer"

func main() { i := Integer.Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b.Swap(1, 2) b.Move(3, 2) b[0].Add(3) fmt.Printf(“b[0:2] = %v\n”, b[0:2])}

produces:b[0:2] = [6 4]

Page 13: Go: It's Not Just For Google

testable

Page 14: Go: It's Not Just For Google

func (b Buffer) Eq(o Buffer) (r bool) { if len(b) == len(o) { for i := len(b) - 1; i > 0; i-- { if b[i] != o[i] { return } } r = true } return}

Page 15: Go: It's Not Just For Google

func TestSwap(t *testing.T) { i := Buffer{0, 1, 2, 3, 4, 5} b := i.Clone() b.Swap(1, 2) if !b[1:3].Eq(Buffer{2, 1}) { t.Fatalf("b = %v", b) }}

Page 16: Go: It's Not Just For Google

package Vectorimport . "Integer"

type Vector struct { Buffer}

func (v *Vector) Clone() *Vector { return &Vector{v.Buffer.Clone()}}

func (v *Vector) Slice(i, j int) Buffer { return v.Buffer[i:j]}

Page 17: Go: It's Not Just For Google

package Vectorimport "testing"

func TestVectorSwap(t *testing.T) { i := Vector{Buffer{0, 1, 2, 3, 4, 5}} v := i.Clone() v.Swap(1, 2) r := Vector{Buffer{0, 2, 1, 3, 4, 5}} switch { case !v.Eq(r.Buffer): fallthrough case !v.Buffer.Eq(r.Buffer): t.Fatalf("b[0:5] = %v", v) }}

Page 18: Go: It's Not Just For Google

include $(GOROOT)/src/Make.inc

TARG=integer

GOFILES=\ integer.go\ vector.go

include $(GOROOT)/src/Make.pkg

Page 19: Go: It's Not Just For Google

func BenchmarkVectorClone6(b *testing.B) { v := Vector{Buffer{0, 1, 2, 3, 4, 5}} for i := 0; i < b.N; i++ { _ = v.Clone() }}

func BenchmarkVectorSwap(b *testing.B) { b.StopTimer() v := Vector{Buffer{0, 1, 2, 3, 4, 5}} b.StartTimer() for i := 0; i < b.N; i++ { v.Swap(1, 2) }}

Page 20: Go: It's Not Just For Google

$ gotest -bench="Benchmark"rm -f _test/scripts.a6g -o _gotest_.6 integer.go vector.go nominal_typing_test.go embedded_typing_benchmark_test.go embedded_typing_test.gorm -f _test/scripts.agopack grc _test/scripts.a _gotest_.6 PASSinteger.BenchmarkVectorSwap200000000 8 ns/opinteger.BenchmarkVectorClone6 10000000 300 ns/op

Page 21: Go: It's Not Just For Google

dynamic

Page 22: Go: It's Not Just For Google

type Adder interface { Add(j int) Subtract(j int) Result() interface{} Reset()}

Page 23: Go: It's Not Just For Google

type IAdder int

func (i IAdder) Add(j int) { i[0] += i[j]}

func (i IAdder) Subtract(j int) { i[0] -= i[j]}

func (i IAdder) Result() interface{} { return i[0]}

func (i IAdder) Reset() { i[0] = *new(int)}

Page 24: Go: It's Not Just For Google

type FAdder []float32

func (f FAdder) Add(j int) { f[0] += f[j]}

func (f FAdder) Subtract(j int) { f[0] -= f[j]}

func (f FAdder) Result() interface{} { return f[0]}

Page 25: Go: It's Not Just For Google

func TestAdder(t *testing.T) { var a Adder

a = IAdder{0, 1, 2} a.Add(1) if i.Result().(int) != 1 { t.Fatalf("IAdder::Add(1) %v != %v", a.Result(), 1) } a.Subtract(2) if a.Result().(int) != -1 { t.Fatalf("IAdder::Subtract(2) %v != %v", a.Result()), -1 }

a = FAdder{0.0, 1.0, 2.0} a.Add(1) if a.Result().(float32) != 1.0 { t.Fatalf("FAdder::Add(1) %v != %v", a.Result(), 1.0) }}

Page 26: Go: It's Not Just For Google

reflected

Page 27: Go: It's Not Just For Google

package generalise

import "reflect"

func Allocate(i interface{}, limit... int) (n interface{}) { switch v := reflect.ValueOf(i); v.Kind() { case reflect.Slice: l := v.Cap() if len(limit) > 0 { l = limit[0] } n = reflect.MakeSlice(v.Type(), l, l).Interface()

case reflect.Map: n = reflect.MakeMap(v.Type()).Interface() } return}

Page 28: Go: It's Not Just For Google

package generalise

import . "reflect"

func Allocate(i interface{}, limit... int) (n interface{}) { switch v := ValueOf(i); v.Kind() { case Slice: l := v.Cap() if len(limit) > 0 { l = limit[0] } n = MakeSlice(v.Type(), l, l).Interface()

case Map: n = MakeMap(v.Type()).Interface() } return}

Page 29: Go: It's Not Just For Google

func throwsPanic(f func()) (b bool) { defer func() { if x := recover(); x != nil { b = true } }() f() return}

Page 30: Go: It's Not Just For Google

func TestAllocate(t *testing.T) { var s2 []int

s1 := []int{0, 1, 2} m := map[int] int{1: 1, 2: 2, 3: 3} switch { case throwsPanic(func() { s2 = Allocate(s1, 1).([]int) }): t.Fatal("Unable to allocate new slice")

case len(s2) != 1 || cap(s2) != 1: t.Fatal("New slice should be %v not %v", make([]int, 0, 1), s2)

case throwsPanic(func() { Allocate(m) }): t.Fatal("Unable to allocate new map") }}

Page 31: Go: It's Not Just For Google

func Duplicate(i interface{}) (clone interface{}) { if clone = Allocate(i); clone != nil { switch clone := ValueOf(clone); clone.Kind() { case Slice: Copy(clone, ValueOf(i))

case Map: m := ValueOf(i) for _, k := range m.Keys() { clone.SetMapIndex(k, m.MapIndex(k)) } } } return}

Page 32: Go: It's Not Just For Google

func TestDuplicateSlice(t *testing.T) { s1 := []int{0, 1, 2} var s2 []int

if throwsPanic(func() { s2 = Duplicate(s1).([]int) }) { t.Fatalf("Unable to duplicate slice %v\n", s1) } switch { case len(s1) != len(s2): fallthrough case cap(s1) != cap(s2): fallthrough case s1[0] != s2[0]: fallthrough case s1[1] != s2[1]: fallthrough case s1[2] != s2[2]: fallthrough t.Fatalf("Duplicating %v produced %v", s1, s2) }}

Page 33: Go: It's Not Just For Google

func TestDuplicateMap(t *testing.T) { m1 := map[int]int{1: 1, 2: 2, 3: 3} var m2 map[int]int

if throwsPanic(func() { m2 = Duplicate(m1).(map[int]int) }) { t.Fatalf("Unable to duplicate map %v\n", m1) }

switch { case len(m1) != len(m2): fallthrough case m1[1] != m2[1]: fallthrough case m1[2] != m2[2]: fallthrough case m1[3] != m2[3]: fallthrough t.Fatalf("Duplicating %v produced %v", m1, m2) }}

Page 34: Go: It's Not Just For Google

low-level

Page 35: Go: It's Not Just For Google

package raw

import . "reflect"import "unsafe"

var _BYTE_SLICE Type = Typeof([]byte(nil))

type MemoryBlock interface { ByteSlice() []byte}

func valueHeader(v reflect.Value) (Header *reflect.SliceHeader) { if v.IsValid() { s := int(v.Type().Size()) header = &reflect.SliceHeader{ v.UnsafeAddr(), s, s } } return}

Page 36: Go: It's Not Just For Google

func SliceHeader(i interface{}) (Header *SliceHeader, Size, Align int) { switch value := Indirect(ValueOf(i)); value.Kind() { case Slice: Header = (*SliceHeader)(unsafe.Pointer(value.UnsafeAddr())) t := value.Type().Elem() Size = int(t.Size()) Align = t.Align() case Interface: Header, Size, Align = SliceHeader(value.Elem()) } return}

func Scale(oldHeader *SliceHeader, oldESize, newESize int) (h *SliceHeader) { if oldHeader != nil { s := float64(oldESize) / float64(newESize) h = &SliceHeader{ Data: oldHeader.Data } h.Len = int(float64(oldHeader.Len) * s) h.Cap = int(float64(oldHeader.Cap) * s) } return}

Page 37: Go: It's Not Just For Google

func ByteSlice(i interface{}) []byte { switch i := i.(type) { case []byte: return i case MemoryBlock: return i.ByteSlice() }

var header *SliceHeader switch v := ValueOf(i); value.Kind() { case Interface, Ptr: header = valueHeader(v.Elem())

case Slice: h, s, _ := SliceHeader(i) header = Scale(h, s, 1)

case String: s := v.Get() h := *(*StringHeader)(unsafe.Pointer(&s)) header = &SliceHeader{ h.Data, h.Len, h.Len }

default: header = valueHeader(v) } return unsafe.Unreflect(_BYTE_SLICE, unsafe.Pointer(header)).([]byte)}

Page 38: Go: It's Not Just For Google

concurrent

Page 39: Go: It's Not Just For Google

package mainimport "fmt"

func main() { var c chan int c = make(chan int) limit := 16 go func() { for i := limit; i > 0; i-- { fmt.Print(<-c) } }() for i := limit; i > 0; i-- { select { case c <- 0: case c <- 1: } }}

produces:0110011101011010

Page 40: Go: It's Not Just For Google

func main() { var c chan int c = make(chan int, 16) go func() { for i := 16; i > 0; i-- { fmt.Print(<-c) } }() go func() { select { case c <- 0: case c <- 1: } }() for {}}

produces:0110011101011010

Page 41: Go: It's Not Just For Google

package generalise

type SignalSource func(status chan bool)

func Wait(s SignalSource) { done := make(chan bool) defer close(done) go s(done) <-done}

func WaitAll(count int, s SignalSource) { done := make(chan bool) defer close(done) go s(done) for i := 0; i < count; i++ { <- done }}

Page 42: Go: It's Not Just For Google

type Iteration func(k, x interface{}) bool

func (i Iteration) apply(k, v interface{}, c chan bool) { go func() { c <-i(k, v) }()}

func (f Iteration) Each(c interface{}) { switch c := ValueOf(c); c.Kind() { case Slice: WaitAll(c.Len(), SignalSource(func(done chan bool) { for i := 0; i < c.Len(); i++ { f.apply(i, c.Elem(i).Interface(), done) }}))

case Map: WaitAll(c.Len(), SignalSource(func(done chan bool) { for _, k := range c.Keys() { f.apply(k, c.Elem(k).Interface(), done) }})) }}

Page 43: Go: It's Not Just For Google

type Results chan interface{}

type Combination func(x, y interface{}) interface{}

func (f Combination) Reduce(c, s interface{}) (r Results) { r = make(Results) go func() { Iteration(func(k, x interface{}) (ok bool) { s = f(s, x) return true }).Each(c) r <- s }() return}

Page 44: Go: It's Not Just For Google

type Transformation func(x interface{}) interface{}

func (t Transformation) Transform(x interface{}) Value { return ValueOf(t(x))}

func (t Transformation) Map(c interface{}) (r interface{}) { r = Allocate(c) if i := MapIterator(r); i != nil { i.Each(c) } return}

Page 45: Go: It's Not Just For Google

func MapIterator(c interface{}) (i Iteration) { switch n := ValueOf(c); n.Kind() { case Slice: i = Iteration(func(k, x interface{}) bool { n.Elem(k.(int)).SetValue(t.GetValue(x)) return true })

case Map: i = Iteration(func(k, x interface{}) bool { n.SetMapIndex(ValueOf(k), t.GetValue(x)) return true }) } return}

Page 46: Go: It's Not Just For Google

func main() { s := []int{0, 1, 2, 3, 4, 5} d := Transformation(func(x interface{}) interface{} { return x.(int) * 2 } ).Map(s) sum := Combination(func(x, y interface{}) interface{} { return x.(int) + y.(int) }) fmt.Printf("s = %v, sum = %v\n", s, (<- sum.Reduce(s, 0)).(int)) fmt.Printf("d = %v, sum = %v\n", d, (<- sum.Reduce(d, 0)).(int))}

produces:s = [0 1 2 3 4 5], sum = 15d = [0 2 4 6 8 10], sum = 30

Page 47: Go: It's Not Just For Google

extensible

Page 48: Go: It's Not Just For Google

include $(GOROOT)/src/Make.inc

TARG=sqlite3

CGOFILES=\ sqlite3.go\ database.go

ifeq ($(GOOS),darwin)CGO_LDFLAGS=/usr/lib/libsqlite3.0.dylibelseCGO_LDFLAGS=-lsqlite3endif

include $(GOROOT)/src/Make.pkg

Page 49: Go: It's Not Just For Google

package sqlite3

// #include <sqlite3.h>import "C"import "fmt"import "os"

type Database struct { handle *C.sqlite3 Filename string Flags C.int}

func (db *Database) Error() os.Error { return Errno(C.sqlite3_errcode(db.handle))}

Page 50: Go: It's Not Just For Google

const( OK = Errno(iota) ERROR CANTOPEN = Errno(14))

var errText = map[Errno]string { ERROR: "SQL error or missing database", CANTOPEN: "Unable to open the database file",}

type Errno int

func (e Errno) String() (err string) { if err = errText[e]; err == "" { err = fmt.Sprintf("errno %v", int(e)) } return }

Page 51: Go: It's Not Just For Google

func (db *Database) Open(flags... int) (e os.Error) { db.Flags = 0 for _, v := range flags { db.Flags = db.Flags | C.int(v) } f := C.CString(db.Filename) if err := Errno(C.sqlite3_open_v2(f, &db.handle, db.Flags, nil)); err != OK { e = err } else if db.handle == nil { e = CANTOPEN } return}

func (db *Database) Close() { C.sqlite3_close(db.handle) db.handle = nil}

Page 52: Go: It's Not Just For Google

func Open(filename string, flags... int) (db *Database, e os.Error) { defer func() { if x := recover(); x != nil { db.Close() db = nil e = ERROR } }() db = &Database{ Filename: filename } if len(flags) == 0 { e = db.Open( C.SQLITE_OPEN_FULLMUTEX, C.SQLITE_OPEN_READWRITE, C.SQLITE_OPEN_CREATE ) } else { e = db.Open(flags...) } return}

Page 53: Go: It's Not Just For Google

fun!

Page 54: Go: It's Not Just For Google

finding out more

http://golang.org/

twitter://#golightly

http://github.com/feyeleanor/

wikipedia or google