40

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!

Brian Campbell
  • 322,767
  • 57
  • 360
  • 340
  • 11
    Hey, why the downvotes and close votes? We do code golf on here, and we do some open-ended questions about the strengths or weaknesses of various technologies, as long as they're not too contentious or subject; why not some demos of what a new language is good for? If you think this should be community wiki say so and I might to that, but I don't think this question should be closed. – Brian Campbell Nov 14 '09 at 18:16
  • 4
    Code golf questions have a specific goal in mind. This question, however, just seems too open-ended. Asking people to do *anything* with a language is just too vague. – gnovice Nov 14 '09 at 18:26
  • possible duplicate: http://stackoverflow.com/questions/1720201/go-examples-and-idioms – György Andrasek Nov 14 '09 at 18:59
  • I'm asking people to do anything that is cool and exercises the unique new features of the language. I want to see how these features work together, and how someone other than the language designers themselves take advantage of those features. Would anyone vote to reopen if I clarified in the title that I am specifically looking for demonstrations that exercise the unique features of Go? – Brian Campbell Nov 14 '09 at 19:05
  • 1
    Then that would be definite duplicate: http://stackoverflow.com/questions/1720201/go-examples-and-idioms/1730300#1730300 – György Andrasek Nov 14 '09 at 20:54
  • 1
    No, it's not a duplicate. I'm looking for complete programs that demonstrate the expressive power of the language, not just small snippets and idioms; read the title, and the body of my post. But as people seem not to like this question, I'm willing to let it go. – Brian Campbell Nov 15 '09 at 00:28
  • 1
    Code golf has a solid backing despite my feeling that it is not appropriate ( http://meta.stackexchange.com/questions/20912/so-weekly-code-golf ), and this question simply doesn't have a correct answer. Not a Real Question. – dmckee --- ex-moderator kitten Nov 15 '09 at 22:57
  • 3
    Although this is an open-ended question, the Go language is a special exception in that it is very new and so little example code exists that a question like this, which would be pointless in the case of C or Perl, is actually something very valuable. –  Nov 16 '09 at 04:54
  • 1
    Right, thanks Kinopiko. This would make no sense for a language that's been around for years. The point of this question is to see some "first impression" code; what can people do in a language that's been released for two days (when I asked the question). I typed up the question the day Go was released, but hesitated on posting it as there were lots of bad, generic Go questions on the first day, and I wanted to give people more chance to absorb the language. I feel that open ended questions which ask for code are more valuable than open ended questions that are just about abstract topics. – Brian Campbell Nov 16 '09 at 05:40
  • I'm surprised my answer was upvoted beyond the chat server (and I upvoted the chat server). My clock face program is just something like "my first program ever", but Brian's is actually using some interesting features of the language, including the network package and channels and so on. Please have another look at it. –  Nov 18 '09 at 04:42
  • Since "the community" found this to be vulgar and in need of closing, where would be a good place to ask for a short program to showcase Go's capabilities? – user1683793 Sep 27 '19 at 21:52
  • @user1683793 This question was posted in the early days of StackOverflow, when we were still trying to figure out what kids of questions were appropriate. As we've learned about what works, it was decided that this kind of question wasn't really a good fit. A few alternatives: https://codegolf.stackexchange.com has been specifically created for code-golf type challenges; creating short programs that solve some challenge. http://www.rosettacode.org/ is a site in which the same problem is solved in a number of different programming languages, allowing you to compare how they look. – Brian Campbell Sep 28 '19 at 18:20

5 Answers5

12

This is a web proxy I wrote to provide unauthenticated access to a web service that required HTTP basic auth. I needed it for an internal thingy (and still use it):

package main

import (
    "flag"
    "log"
    "net/http"
    "net/url"
)

var target = flag.String("target", "http://www.google.com/", "Where to go.")
var addr = flag.String("listen", ":12345", "Address/port on which to listen.")
var auth = flag.String("auth", "", "Authorization header to add (optional).")

func main() {
    flag.Parse()

    targetUrl, uerr := url.Parse(*target)
    if uerr != nil {
        log.Fatalf("Error parsing target ``%s'': ", target, uerr.String())
    }

    proxy := http.ReverseProxy{Director: func(req *http.Request) {
        req.URL.Scheme = targetUrl.Scheme
        req.URL.Host = targetUrl.Host
        req.Host = targetUrl.Host
        if *auth != "" {
            req.Header.Set("Authorization", *auth)
        }
    }}

    log.Fatal(http.ListenAndServe(*addr, &proxy))
}
Dustin
  • 89,080
  • 21
  • 111
  • 133
8

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.


This is the same code fixed with go fix (and some manual tweaking) and then automatically formatted using go fmt. Some newlines where inserted manually.

package main

import (
    "bufio"
    "image"
    "image/color"
    "image/png"
    "math"
    "os"
    "time"
)

const clock_size = 200
const radius = clock_size / 3

var colour color.RGBA

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(image.Rect(0, 0, clock_size, clock_size))
    colour.A = 255
    circle(clock)
    time := time.Now()
    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)
}
fuz
  • 88,405
  • 25
  • 200
  • 352
  • 7
    "I've NEVER seen a language as strict as Go about types." OCaml uses +. instead of + for double. – Łukasz Lew Feb 17 '10 at 17:40
  • `gofmt` would be really nice :). – crazy2be Jun 16 '12 at 23:49
  • Please fix the code: `./clock.go:5: undefined: image.RGBAColor ./clock.go:21: cannot use clock_size (type int) as type image.Rectangle in function argument ./clock.go:21: too many arguments in call to image.NewRGBA ./clock.go:24: undefined: time.LocalTime` – Flavius Aug 06 '12 at 11:17
  • 1
    @Flavius use go fix to fix the code yourself. – fuz Feb 27 '13 at 21:50
4

I really like go's channels and the select statement, so here's something that shows how easy it is to express the "go and get as many things as possible within a certain time" concept.

This generates as many random numbers as possible within 300 milliseconds and returns the biggest one generated in that time.

package main

import (
  "fmt"
  "math/rand"
  "time"
)

func main() {
  timeout := time.After(300 * time.Millisecond)
  numbers := make(chan int) // This channel will be used 
  var numberCount int = 0
  var maxNumber int = 0

  // Start putting random numbers on the numbers channel
  go func() {
    for {
      numbers <- rand.Int()
    }
  }()

  for {
    select {
    case <- timeout:
      fmt.Printf("%v numbers generated. Max number found: %v.\n", numberCount, maxNumber)
      return

    case number := <- numbers:
      numberCount++
      if number > maxNumber {
        maxNumber = number
      }
    }
  }
}
JJ Geewax
  • 10,342
  • 1
  • 37
  • 49
  • 1
    `setTimeout()` is nearly identical to `time.After()` – Lily Ballard May 23 '12 at 23:17
  • Also, since the `select` randomly picks a channel if both are available, you may be pulling numbers after the timeout has elapsed. If you care about the odd couple of numbers there, you might want to do a second non-blocking read from timeout in the numbers case. – Lily Ballard May 23 '12 at 23:18
4

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
  • 322,767
  • 57
  • 360
  • 340
  • I love this example, but I can't seem to wrap my head around how this specific bit is actually working: c.(client).receive I thought the convention was client(c).receive Do you mind explaining? – Billy Jo Nov 26 '09 at 02:05
  • 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 Nov 26 '09 at 04:21
  • Ah, I see. I hadn't gotten as far as type assertions in the spec. Thanks. – Billy Jo Nov 26 '09 at 06:15
  • Just a note to people who read this now (like me) Vectors are replaced in go by slices – daniel gratzer Dec 25 '12 at 00:16
-1

I copied this from somewhere. Fairly simple, but shows some features.

package main
import ("fmt"; "os" ;"bufio";"io")
func main() {
        if len(os.Args) < 2 {
                fmt.Printf("usage: catfile \n")
        } else if pFile, err := os.OpenFile(os.Args[1], os.O_RDONLY, 0); err != nil {
                fmt.Printf("error opening file : %s\n", err)
        } else {
            defer pFile.Close()
        displayFile(pFile)
    }
}

func displayFile(pFile *os.File) {
        oReader := bufio.NewReader(pFile);
        for {
                if sLine, err := oReader.ReadString('\n'); err == nil {
            fmt.Printf("%s", sLine)
        } else {
            if err != io.EOF {fmt.Printf("error reading file : %s\n", err)}
                    break
        } 
        }
}
gliptak
  • 3,592
  • 2
  • 29
  • 61
brianoh
  • 3,407
  • 6
  • 23
  • 23
  • 6
    Please try to attribute any code that you copied from elsewhere to its original source. Also, it helps to describe what the code is supposed to do, and to format the code to make it readable. I've edited your answer to format the code for you; if you indent every line with 4 spaces (or select the text and press the `{}` button) Stack Overflow will display it as code with all of the indentation preserved. – Brian Campbell May 04 '11 at 14:31
  • This doesn't compile well on my side. It says: "too many argument in call to os.Open. Does this mean the API have changed? – Daniel Baktiar Apr 03 '12 at 08:33
  • 1
    If it does not compile and you suspect an API change, try `go fix` on it. – Kissaki Jun 03 '12 at 17:26