go.talks: new talk Go for Pythonistas

R=adg
CC=golang-dev
https://golang.org/cl/16990043
diff --git a/2013/go4python.slide b/2013/go4python.slide
new file mode 100644
index 0000000..c1ed696
--- /dev/null
+++ b/2013/go4python.slide
@@ -0,0 +1,446 @@
+Go for Pythonistas
+
+Francesc Campoy Flores
+Gopher at Google
+http://campoy.cat
+
+@francesc
+campoy@golang.com
+
+* Goal of this talk
+
+Whetting your appetite for Go
+
+.image go4python/img/gopher.jpg
+
+* My tactics
+
+1. Showing you how Go is like Python.
+
+2. Showing you how Go is _not_ like Python.
+
+* Python, Go, and me
+
+Software Engineer at Google: _Feb_11-Aug_12_
+
+- Lots of C++ and Python.
+
+- SQL to C++ compiler in Python.
+
+Go Developer Relations: _Aug_12_ - `datetime.now()`
+
+- Lots of Go.
+
+* Things I don't like about Python (it'll be short)
+
+* Beautiful and simple
+
+Dynamic typing - nice because it's concise, like Python.
+
+	a = "hello"
+	b = 1
+	# but also
+	a = 2
+
+Static typing - can be verbose, like Java or C++.
+
+	Foo foo = new Foo();
+
+Static typing with inferred types, like Go.
+
+	a := "hello"
+	b := 1
+	// but no
+	a = 2
+
+Statically-typed Python? Check Guido's [[http://www.mypy-lang.org/][mypy]]
+
+* Run time pyrotechnics
+
+.play go4python/dyntyp.py /name/,
+
+I don't want start a flame war here but ...
+
+*100%*code*coverage*is*a*symptom*
+
+- Code coverage should point you to untested cases.
+- Not a way to find typos!
+- 100% code coverage doesn't mean bug free.
+
+* Other things I don't like
+
+- Deploying - managing dependencies.
+
+- Performance - "not too slow" is often not fast enough.
+
+- Magic! (e.g.: `__magic__`: `**kargs`, `__getattr__`)
+
+A list of magic methods in Python:
+
+.link http://www.rafekettler.com/magicmethods.html
+
+* And I *do* like concurrency!
+
+A lot has been said about Python's infamous Global Interpreter Lock.
+
+You should watch [[http://blip.tv/carlfk/mindblowing-python-gil-2243379][Mindblowing Python GIL]], by David Beazley.
+
+* Things I like about Python
+
+* Things I like about Python
+
+- The Zen of Python. ([[http://talks.golang.org/2012/zen.slide#1][Go and the Zen of Python]])
+
+- Hashes and arrays are part of the language.
+
+- The standard library.
+
+- Magic! A bit of code can do a lot.
+
+* A bit of code
+
+* fib.py
+
+Have you ever heard of Fibonacci?
+
+.play go4python/fib.py /fib/,
+
+* fib.go
+
+Something familiar?
+
+.play go4python/fib.go /func/,
+
+* Fibonacci without generators? What?
+
+Python generators are awesome.
+
+.code go4python/fib-gen.py /fib/,/^$/
+
+Mechanically complex.
+
+.play go4python/fib-gen.py /f = fib/,/^$/
+
+But very easy to use.
+
+.play go4python/fib-gen.py /for x/,/^$/
+
+* Python generators
+
+.image go4python/img/fib-py.png 500 320
+
+Note the generator executes concurrently. Hmm... I like concurrency.
+
+* Go concurrency
+
+Based on *goroutines* and *channels*.
+
+- Goroutines: very light processing actors (the gophers).
+
+- Channels: typed, synchronized, thread-safe pipes (the arrows).
+
+.image go4python/img/funnelin.jpg
+
+* "Generator" goroutines
+
+.image go4python/img/fib-go.png 500 350
+
+* "Generator" goroutines
+
+Uses a channel send instead of `yield`.
+
+.code go4python/fib-gen.go /fib/,/^}/
+
+.play go4python/fib-gen.go /main\(/,
+
+* "Generator" goroutines
+
+A more generator-like style:
+
+.play go4python/fib-gen2.go /func/,
+
+* Exercise: generating prime numbers
+
+Write a function that returns a channel and sends the first n prime numbers on
+it.
+
+Given the function `prime`:
+
+.code go4python/genex.go /prime/,/^}/
+
+Use the Go playground:
+
+.link http://golang.org/s/go4py-ex1
+
+* Solution: generating prime numbers
+
+.code go4python/genex.go /primes\(/,/^}/
+
+.play go4python/genex.go /main\(/,
+
+* Exercise: Fibonacci primes
+
+Write a `filterPrimes` function that takes a channel of ints as a
+parameter and returns another channel of ints.
+
+All the prime numbers that `filterPrimes` receives from the input channel are
+sent into the output channel.
+
+Complete this code snippet:
+
+.link http://golang.org/s/go4py-ex2
+
+* Solution: Fibonacci primes
+
+.code go4python/genex2.go /filterPrimes\(/,/^}/
+
+.play go4python/genex2.go /main\(/,
+
+* But there's much more
+
+Goroutines and channels aren't just for generators. They can be used to model
+all kinds of concurrent systems.
+
+To learn more:
+
+- [[http://talks.golang.org/2012/concurrency.slide#1][Concurrency patterns]], by Rob Pike
+
+- [[http://talks.golang.org/2013/advconc.slide#1][Advanced Concurrency Patterns]], by Sameer Ajmani
+
+* Object-oriented Go
+
+* Object-oriented Go
+
+A type declaration.
+
+.code go4python/typesandmethods.go /Name/,/^}/
+
+A method declaration.
+
+.code go4python/typesandmethods.go /String/,/^}/
+
+Constructing a `Name` and using it.
+
+.play go4python/typesandmethods.go /William/,/Print/
+
+* Methods on anything
+
+There's more to types than structs.
+
+.code go4python/typesandmethods.go /SimpleName/
+
+You can define methods on any type.
+
+.code go4python/typesandmethods.go /SimpleName\)/
+
+Or almost any type.
+
+	func (s string) NoWay()
+
+You can *only* define methods on types within the same package.
+
+* Duck typing
+
+* Duck typing
+
+_If_it_walks_like_a_duck_..._
+
+What defines a duck?
+
+- Is there an explicit list of "duck" features?
+
+- What if the duck is not exactly a duck?
+
+s/duck/file-like object/g
+
+* Quack?
+
+.image go4python/img/duck.jpg 500 500
+
+* Go interfaces
+
+Simply a set of methods.
+
+From the `fmt` package:
+
+	type Stringer interface {
+		String() string
+	}
+
+`fmt.Println` calls the String method if the parameter is a `Stringer`.
+
+.play go4python/typesandmethods.go /second/,/Print/
+
+A type with all the methods of the interface implements the interface.
+
+*Implicit*satisfaction*==*No*"implements"*
+
+Structural typing: it doesn't just sound like a duck, it *is* a duck.
+
+And that's checked at compile time.
+
+* Decorators
+
+* Decorators
+
+A convenient way to wrap a function.
+
+.code go4python/deco.py /auth_required/,/^$/
+
+A function can be decorated using `@`.
+
+.code go4python/deco.py /myHandler/,/user/
+
+* Decorators
+
+If we run it.
+
+.play go4python/deco.py /try/,
+
+This is unauthorized:
+
+.link http://localhost:8080/hi
+
+This is authorized:
+
+.link http://localhost:8080/hi?user=john
+
+* Decorators in Go?
+
+Not exactly, but close enough.
+
+Go doesn't provide decorators in the language, but its function literal syntax and simple scoping rules make it easy to do something similar.
+
+.code go4python/deco.go /hiHandler/,/^\)/
+
+A wrapper function.
+
+.code go4python/deco.go /authRequired/,/^$/
+
+* Decorators in Go?
+
+.play go4python/deco.go /func main/,/^}/
+
+This is unauthorized:
+
+.link http://localhost:8080/hi
+
+This is authorized:
+
+.link http://localhost:8080/hi?user=john
+
+* Exercise: errors in HTTP handlers
+
+In Go, functions can return errors to indicate that something bad happened.
+
+The `net/http` package from the standard library defines the type `HandlerFunc`.
+
+	type HandlerFunc func(ResponseWriter, *Request)
+
+But it's often useful to unify the error handling into a single function to avoid
+repetition.
+
+.code go4python/decoex.go /errorHandler/
+
+Write a decorator that given a `errorHandler` returns a `http.HandlerFunc`.
+If an error occurs it logs it and returns an http error page.
+
+* Exercise: errors in HTTP handlers (continuation)
+
+Given the function `handler`.
+
+.code go4python/decoex.go /handler/,/^}/
+
+We want to use it as follows.
+
+.code go4python/decoex.go /HandleFunc/
+
+Implement `handleError` using the playground.
+
+.link http://golang.org/s/go4py-ex3
+
+* Solution: errors in HTTP handlers
+
+.code go4python/decoex.go /handleError/,/^}/
+
+.code go4python/decoex.go /Fake/,/^$/
+
+.play go4python/decoex.go /john/,/^$/
+
+* Monkey patching
+
+* Monkey patching
+
+"A monkey patch is a way to extend or modify the run-time code of dynamic languages without altering the original source code." - _Wikipedia_
+
+.image go4python/img/monkey.jpg 400 500
+
+* Monkey patching
+
+Also known as "duck punching" ... poor duck.
+
+Often used for testing purposes.
+
+For example, say we want to test this function:
+
+.code go4python/monkey.py /def say_hi/,/^$/
+
+Which depends on a function that makes an HTTP request:
+
+.code go4python/monkey.py /def auth/,/^$/
+
+* Monkey patching
+
+We can test `say_hi` without making HTTP requests by stubbing out `auth`:
+
+.play go4python/monkey.py /sayhitest/,/done/
+
+* Gopher punching!
+
+The same effect can be achieved in Go.
+
+.code go4python/monkey.go /sayHi/,/^}/
+
+Which depends on
+
+.code go4python/monkey.go /auth /,/^}/
+
+* Gopher punching!
+
+Our test code can change the value of auth easily.
+
+.play go4python/monkey.go /TestSayHi/,/^}/
+
+* Conclusion
+
+* Conclusion
+
+Go is a bit like Python
+
+- simple
+- flexible
+- fun
+
+but a bit different too
+
+- fast
+- concurrent
+- statically typed
+
+_Disclaimer_:_
+
+- "No pythons, ducks, monkeys or gophers were harmed while writing this talk"
+
+* Try it
+
+Next steps
+
+.link http://golang.org
+
+Learn Go from your browser
+
+.link http://tour.golang.org
+
+The community: golang-nuts
+
+.link https://groups.google.com/d/forum/golang-nuts
diff --git a/2013/go4python/deco.go b/2013/go4python/deco.go
new file mode 100644
index 0000000..b589a26
--- /dev/null
+++ b/2013/go4python/deco.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+)
+
+func authRequired(f http.HandlerFunc) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		if r.FormValue("user") == "" {
+			http.Error(w, "unknown user", http.StatusForbidden)
+			return
+		}
+		f(w, r)
+	}
+}
+
+var hiHandler = authRequired(
+	func(w http.ResponseWriter, r *http.Request) {
+		fmt.Fprintf(w, "Hi, %v", r.FormValue("user"))
+	},
+)
+
+func main() {
+	http.HandleFunc("/hi", hiHandler)
+	http.ListenAndServe(":8080", nil)
+}
diff --git a/2013/go4python/deco.py b/2013/go4python/deco.py
new file mode 100644
index 0000000..bf46318
--- /dev/null
+++ b/2013/go4python/deco.py
@@ -0,0 +1,29 @@
+#!/usr/bin/python
+
+from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
+from urlparse import urlparse,parse_qs
+
+PORT_NUMBER = 8080
+
+def auth_required(myfunc):
+	def checkuser(self):
+		user = parse_qs(urlparse(self.path).query).get('user')
+		if user:
+			self.user = user[0]
+			myfunc(self)
+		else:
+			self.wfile.write('unknown user')
+	return checkuser
+
+
+class myHandler(BaseHTTPRequestHandler):
+	@auth_required
+	def do_GET(self):
+		self.wfile.write('Hello, %s!' % self.user)
+
+try:
+	server = HTTPServer(('', PORT_NUMBER), myHandler)
+	server.serve_forever()
+
+except KeyboardInterrupt:
+	server.socket.close()
diff --git a/2013/go4python/decoex.go b/2013/go4python/decoex.go
new file mode 100644
index 0000000..42725db
--- /dev/null
+++ b/2013/go4python/decoex.go
@@ -0,0 +1,66 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	"net/http"
+)
+
+type errorHandler func(http.ResponseWriter, *http.Request) error
+
+func handleError(f errorHandler) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		err := f(w, r)
+		if err != nil {
+			log.Printf("%v", err)
+			http.Error(w, "Oops!", http.StatusInternalServerError)
+		}
+	}
+}
+
+func handler(w http.ResponseWriter, r *http.Request) error {
+	name := r.FormValue("name")
+	if name == "" {
+		return fmt.Errorf("empty name")
+	}
+	fmt.Fprintln(w, "Hi,", name)
+	return nil
+}
+
+// resp implements http.ResponseWriter writing
+type dummyResp struct {
+	io.Writer
+	h int
+}
+
+func newDummyResp() http.ResponseWriter {
+	return &dummyResp{Writer: &bytes.Buffer{}}
+}
+
+func (w *dummyResp) Header() http.Header { return make(http.Header) }
+func (w *dummyResp) WriteHeader(h int)   { w.h = h }
+func (w *dummyResp) String() string      { return fmt.Sprintf("[%v] %q", w.h, w.Writer) }
+
+func main() {
+	http.HandleFunc("/hi", handleError(handler))
+
+	// ListenAndServe is not allowed on the playground.
+	// http.ListenAndServe(":8080", nil)
+
+	// In the playground we call the handler manually with dummy requests.
+
+	// Fake request without 'name' parameter.
+	r := &http.Request{}
+	w := newDummyResp()
+	handleError(handler)(w, r)
+	fmt.Println("resp a:", w)
+
+	// Fake request with 'name' parameter 'john'.
+	r.Form["name"] = []string{"john"}
+	w = newDummyResp()
+	handleError(handler)(w, r)
+	fmt.Println("resp b:", w)
+
+}
diff --git a/2013/go4python/dyntyp.py b/2013/go4python/dyntyp.py
new file mode 100644
index 0000000..fa9e4ea
--- /dev/null
+++ b/2013/go4python/dyntyp.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+
+import random
+
+name = 'pythonista'
+
+# This code only works half of the time.
+if random.random() > 0.5:
+	print 'hey '+name+', you win!'
+else:
+	print 'sorry '+nane+', you lose'
diff --git a/2013/go4python/fib-gen.go b/2013/go4python/fib-gen.go
new file mode 100644
index 0000000..5142cc7
--- /dev/null
+++ b/2013/go4python/fib-gen.go
@@ -0,0 +1,21 @@
+package main
+
+import "fmt"
+
+func fib(c chan int, n int) {
+	a, b := 0, 1
+	for i := 0; i < n; i++ {
+		a, b = b, a+b
+		c <- a // HL
+	}
+	close(c)
+}
+
+func main() {
+	c := make(chan int)
+	go fib(c, 10) // HL
+
+	for x := range c { // HL
+		fmt.Println(x)
+	}
+}
diff --git a/2013/go4python/fib-gen.py b/2013/go4python/fib-gen.py
new file mode 100644
index 0000000..bc02cfd
--- /dev/null
+++ b/2013/go4python/fib-gen.py
@@ -0,0 +1,18 @@
+#!/usr/bin/python
+
+def fib(n):
+    a, b = 0, 1
+    for i in range(n):
+        a, b = b, a + b
+        yield a
+
+f = fib(10)
+try:
+	while True:
+		print f.next()
+except StopIteration:
+	print 'done'
+
+for x in fib(10):
+	print x
+print 'done'
diff --git a/2013/go4python/fib-gen2.go b/2013/go4python/fib-gen2.go
new file mode 100644
index 0000000..9625ba1
--- /dev/null
+++ b/2013/go4python/fib-gen2.go
@@ -0,0 +1,22 @@
+package main
+
+import "fmt"
+
+func fib(n int) chan int {
+	c := make(chan int) // HL
+	go func() {         // HL
+		a, b := 0, 1
+		for i := 0; i < n; i++ {
+			a, b = b, a+b
+			c <- a // HL
+		}
+		close(c)
+	}()
+	return c
+}
+
+func main() {
+	for x := range fib(10) {
+		fmt.Println(x)
+	}
+}
diff --git a/2013/go4python/fib.go b/2013/go4python/fib.go
new file mode 100644
index 0000000..dbfef11
--- /dev/null
+++ b/2013/go4python/fib.go
@@ -0,0 +1,24 @@
+package main
+
+import "fmt"
+
+func fib(n int) int {
+	a, b := 0, 1
+	for i := 0; i < n; i++ {
+		a, b = b, a+b
+	}
+	return b
+}
+
+func fibRec(n int) int {
+	if n <= 1 {
+		return 1
+	}
+	return fibRec(n-1) + fibRec(n-2)
+}
+
+func main() {
+	for i := 0; i < 10; i++ {
+		fmt.Println(fib(i), fibRec(i))
+	}
+}
diff --git a/2013/go4python/fib.py b/2013/go4python/fib.py
new file mode 100755
index 0000000..afc57fa
--- /dev/null
+++ b/2013/go4python/fib.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+
+def fib(n):
+    a, b = 0, 1
+    for i in range(n):
+        a, b = b, a + b
+    return b
+
+def fib_rec(n):
+	if n <= 1:
+		return 1
+	else:
+		return fib_rec(n-1) + fib_rec(n-2)
+
+for x in range(10):
+	print fib(x), fib_rec(x)
diff --git a/2013/go4python/genex.go b/2013/go4python/genex.go
new file mode 100644
index 0000000..6914d5f
--- /dev/null
+++ b/2013/go4python/genex.go
@@ -0,0 +1,35 @@
+package main
+
+import "fmt"
+
+// prime returns true if n is a prime number.
+func prime(n int) bool {
+	for i := 2; i < n; i++ {
+		if n%i == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+// primes returns a channel of ints on which it writes the first n prime
+// numbers before closing it.
+func primes(n int) chan int {
+	c := make(chan int)
+	go func() {
+		for i := 1; n > 0; i++ {
+			if prime(i) {
+				c <- i
+				n--
+			}
+		}
+		close(c)
+	}()
+	return c
+}
+
+func main() {
+	for p := range primes(10) {
+		fmt.Println(p)
+	}
+}
diff --git a/2013/go4python/genex2.go b/2013/go4python/genex2.go
new file mode 100644
index 0000000..50daa06
--- /dev/null
+++ b/2013/go4python/genex2.go
@@ -0,0 +1,48 @@
+package main
+
+import "fmt"
+
+// prime returns true if n is a prime number.
+func prime(n int) bool {
+	for i := 2; i < n; i++ {
+		if n%i == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+// fib returns a channel on which the first n Fibonacci numbers are written.
+func fib(n int) chan int {
+	c := make(chan int)
+	go func() {
+		a, b := 0, 1
+		for i := 0; i < n; i++ {
+			a, b = b, a+b
+			c <- a
+		}
+		close(c)
+	}()
+	return c
+}
+
+// filterPrimes returns a channel of ints on which it writes all the prime
+// numbers read from cin, and closes the returned channel when cin is closed.
+func filterPrimes(cin chan int) chan int {
+	cout := make(chan int)
+	go func() {
+		for v := range cin {
+			if prime(v) {
+				cout <- v
+			}
+		}
+		close(cout)
+	}()
+	return cout
+}
+
+func main() {
+	for p := range filterPrimes(fib(20)) {
+		fmt.Println(p)
+	}
+}
diff --git a/2013/go4python/img/duck.jpg b/2013/go4python/img/duck.jpg
new file mode 100644
index 0000000..344b31e
--- /dev/null
+++ b/2013/go4python/img/duck.jpg
Binary files differ
diff --git a/2013/go4python/img/fib-go.png b/2013/go4python/img/fib-go.png
new file mode 100644
index 0000000..6917140
--- /dev/null
+++ b/2013/go4python/img/fib-go.png
Binary files differ
diff --git a/2013/go4python/img/fib-py.png b/2013/go4python/img/fib-py.png
new file mode 100644
index 0000000..96bad1a
--- /dev/null
+++ b/2013/go4python/img/fib-py.png
Binary files differ
diff --git a/2013/go4python/img/funnelin.jpg b/2013/go4python/img/funnelin.jpg
new file mode 100644
index 0000000..2bf6873
--- /dev/null
+++ b/2013/go4python/img/funnelin.jpg
Binary files differ
diff --git a/2013/go4python/img/gopher.jpg b/2013/go4python/img/gopher.jpg
new file mode 100644
index 0000000..0a64306
--- /dev/null
+++ b/2013/go4python/img/gopher.jpg
Binary files differ
diff --git a/2013/go4python/img/monkey.jpg b/2013/go4python/img/monkey.jpg
new file mode 100644
index 0000000..f4b5569
--- /dev/null
+++ b/2013/go4python/img/monkey.jpg
Binary files differ
diff --git a/2013/go4python/monkey.go b/2013/go4python/monkey.go
new file mode 100644
index 0000000..161180a
--- /dev/null
+++ b/2013/go4python/monkey.go
@@ -0,0 +1,41 @@
+package main
+
+import (
+	"fmt"
+	"net/http"
+)
+
+var authURL = ""
+
+var auth = func(user string) bool {
+	res, err := http.Get(authURL + "/" + user)
+	return err == nil && res.StatusCode == http.StatusOK
+}
+
+func sayHi(user string) {
+	if !auth(user) {
+		fmt.Printf("unknown user %v\n", user)
+		return
+	}
+	fmt.Printf("Hi, %v\n", user)
+}
+
+func TestSayHi() {
+	auth = func(string) bool { return true }
+	sayHi("John")
+
+	auth = func(string) bool { return false }
+	sayHi("John")
+}
+
+func init() {
+	auth = func(string) bool { return true }
+}
+
+func TestAnythingElse() {
+	// auth has been already set to the fake version
+}
+
+func main() {
+	TestSayHi()
+}
diff --git a/2013/go4python/monkey.py b/2013/go4python/monkey.py
new file mode 100644
index 0000000..6f33a7c
--- /dev/null
+++ b/2013/go4python/monkey.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+import urllib
+
+auth_url = 'http://google.com'
+
+def auth(usr):
+	try:
+		r = urllib.urlopen(auth_url + '/' + usr)
+		return r.getcode() == 200
+	except:
+		return False
+
+def say_hi(usr):
+	if auth(usr):
+		print 'Hi, %s' % usr
+	else:
+		print 'unknown user %s' % usr
+
+def sayhitest():
+	# Test authenticated user
+	globals()['auth'] = lambda x: True
+	say_hi('John')
+
+	# Test unauthenticated user
+	globals()['auth'] = lambda x: False
+	say_hi('John')
+#done OMIT
+
+sayhitest()
diff --git a/2013/go4python/typesandmethods.go b/2013/go4python/typesandmethods.go
new file mode 100644
index 0000000..53bc1e2
--- /dev/null
+++ b/2013/go4python/typesandmethods.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+	"fmt"
+	"strings"
+)
+
+type Name struct {
+	First  string
+	Middle string
+	Last   string
+}
+
+func (n Name) String() string {
+	return fmt.Sprintf("%s %c. %s", n.First, n.Middle[0], strings.ToUpper(n.Last))
+}
+
+type SimpleName string
+
+func (s SimpleName) String() string { return string(s) }
+
+func main() {
+	n := Name{"William", "Mike", "Smith"}
+	fmt.Printf("%s", n.String())
+	return
+	// second OMIT
+	n = Name{"William", "Mike", "Smith"}
+	fmt.Println(n)
+}