tags:

views:

1178

answers:

2

So, the big buzz in the last few days is Go, the new language from Google. Assuming you're all obsessive programming language geeks like me, you've all downloaded it, built it, and run your "Hello, 世界" program (isn't it nice using a language written by the inventors of UTF-8?). You've all read the tutorial, Effective Go, and some of the other docs.

Now, what are you going to do with it?

I'd like to see some demos that show off the power of Go. What can you do in a brief program? Show off your best example code. While the true measure of a language can't really be taken until you've written and maintained a large codebase with a team of many programmers over the course of a project with changing requirements, seeing how much you can do in a limited amount of code does help to demonstrate the expressive power of a language. I'd like to see short, complete programs that truly exercise the unique new features of Go; not just snippets or "Hello, World".

So, post some cool code you've written with Go. Take advantage of its unique features, like its goroutines and channels for concurrency, or its interface based type system. Can you write a primitive chat server, or cool IRC bot? Implement a parallel Mandelbrot set that scales to many cores? Write an interpreter for some tiny language? And can you do it all in 30 lines?

I chose 30 arbitrarily as about as much as you can fit into a Stack Overflow code block without it overflowing and getting a scroll bar; it should be enough to do something interesting without golfing too much, but short enough to keep everyone's attention for a quick demo. For instance, with just a bit of reformatting, the example web server should be able to fit (not counting the data).

Show us your Go code!

+5  A: 

OK, I'll get the ball rolling. Here's my first Go program. It's a very primitive chat server, and fits in 30 lines of 80 characters if I compress it down a bit; formatted with gofmt, it is 60 lines. It listens on a hard coded port (4242), does basically no error handling, and doesn't handle client disconnection other than stopping trying to read from a client if it gets an error.

package main
import ("net";"container/vector";"bufio";"strings")
type client struct { conn net.Conn; send chan string; receive chan string }
func main() {
    if listener, err := net.Listen("tcp", "0.0.0.0:4242"); err == nil {
     master := make(chan string, 100);
     clients := vector.New(0);
     go runServer(master, clients);
     for {
      if conn, err := listener.Accept(); err == nil {
       c := client{ conn, master, make(chan string, 100) };
       clients.Push(c);
       go runClient(c);
      } else { break } } } }
func runServer(master chan string, clients *vector.Vector) {
    for { 
     message := <-master;
     clients.Do(func (c interface{}) { c.(client).receive <- message }); } }
func runClient(c client) {
    input := make(chan string, 10);
    go readLines(c, input);
    for {
     select {
     case inMessage := <-input: c.send <- inMessage;
     case outMessage := <-c.receive: c.conn.Write(strings.Bytes(outMessage));
     } } }
func readLines(c client, input chan string) {
    reader := bufio.NewReader(c.conn);
    for { if line, err := reader.ReadString('\n'); err == nil 
      { input <- line; } else { break } } }

Build and run with:

$ 6g server.go
$ 6l -o server server.6
$ ./server

And then in a few other terminals, connect with

$ nc localhost 4242 
Brian Campbell
I love this example, but I can't seem to wrap my head around how this specific bit is actually working:c.(client).receiveI thought the convention wasclient(c).receiveDo you mind explaining?
Bill Ayakatubby
Sure. That's a type assertion (http://golang.org/doc/go_spec.html#Type_assertions); it asserts that the type is what you specify (or conforms to the interface that you specify), and allows you to call methods that are defined on that type or interface. The syntax that you mention is a conversion (http://golang.org/doc/go_spec.html#Conversions), which converts between compatible types (such as integer types). I believe that conversions only work for buit-in types (numbers and strings).
Brian Campbell
Ah, I see. I hadn't gotten as far as type assertions in the spec. Thanks.
Bill Ayakatubby
+5  A: 

This makes a PNG (on stdout) of a clock face showing the current time. It's barely golfed to fit thirty lines, so the code is not quite as clean as it should be.

package main
import ("image"; "image/png"; "math"; "bufio"; "os"; "time")
const clock_size = 200;
const radius = clock_size / 3;
var colour image.RGBAColor;
func circle (clock *image.RGBA) {
    for angle := float64(0); angle < 360; angle++ {
        radian_angle := math.Pi * 2 * angle / 360;
        x := radius * math.Sin (radian_angle) + clock_size/2;
        y := radius * math.Cos (radian_angle) + clock_size/2;
        clock.Set (int (x), int (y), colour);}}
func hand (clock *image.RGBA, angle float64, length float64) {
    radian_angle := math.Pi * 2 * angle;
    x_inc := math.Sin (radian_angle);
    y_inc := -math.Cos (radian_angle);
    for i := float64(0); i < length; i++ {
        x := i * x_inc + clock_size/2;
        y := i * y_inc + clock_size/2;
        clock.Set (int (x), int (y), colour);}}
func main () {
    clock := image.NewRGBA (clock_size, clock_size);
    colour.A = 255;
    circle (clock);
    time := time.LocalTime ();
    hand (clock, (float64(time.Hour) + float64(time.Minute)/60)/12, radius*0.6); // hour hand
    hand (clock, (float64(time.Minute) + float64(time.Second)/60)/60, radius*0.8); // minute hand
    out := bufio.NewWriter(os.Stdout);
    defer out.Flush();
    png.Encode(out, clock);
}

Run it like

8.out > clock.png

Notice all those float64 casts? I've NEVER seen a language as strict as Go about types.

Kinopiko
"I've NEVER seen a language as strict as Go about types."OCaml uses +. instead of + for double.
Łukasz Lew