go: it's not just for google

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

Upload: eleanor-mchugh

Post on 06-May-2015

6.844 views

Category:

Technology


1 download

DESCRIPTION

Another slab of Google Go madness with an emphasis on code and reflection.

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