Newsletter

First published: Sept. 2, 2010, 7:26 p.m. MDT
Last edited: Sept. 3, 2010, 2:44 a.m. MDT

Thoughts on Go

This is the first post of a new newsletter category entitled Research. I aim to update Thursdays with what will likely end up being only mild regularity.

I'm looking at Go to see what people are currently doing with programming languages to try and make parallel computing easier. I've only spent two days with Go, but here are my most salient impressions.

So, let's talk about how to fix the channel issue I mentioned up above. I think the knee-jerk reaction to the idea of a channel is to make channels full duplex. This makes some sense in an IPC context (certainly TCP), but the more I think about it, the less sense I think it makes inside of a process. Most of the channel idioms I've seen so far in Go code don't use the bidirectional nature of channels. Channels seem to be used to either write only or read only. So, if we exploit that, then we can very naturally introduce the concept of closing a channel. Instead of make(chan int) (or equivalent) returning just the new channel, it should instead return the input side and the output side of the channel separately. Then, specific sides of the channel can be force-closed or closed when garbage collected, and the other side of the channel can then throw an error. Note that while I realize you can close any single direction of a channel without requiring the two objects instead of one, having a specific channel-in object and a channel-out object allows most of this channel closing maintenance to be handled by the garbage collector.

Allowing for closing channels, or signaling that a channel is over ("I've generated all the data I can, cap'n!") allows for idioms that indefinitely compute some string of values, but only until it's no longer needed. Conversely, you could make channels that return a limited amount of data, and the reader could easily ascertain that the data stream has ended. Right now, if you create a goroutine that continuously fills or reads from a channel, it will do so until the program ends, at which point it is forcibly terminated. Of course, it is currently possible to work around this by providing another control channel to the goroutine, but that seems (like much of the rest of the language) kind of hacky. If they did this right you could simulate lazy lists or delayed computations in a nicely abstracted and parallel way.

I suppose the suggestion of a channel that you're reading from or writing to closing and throwing an error brings up the whole issue of exceptions. Go doesn't have exceptions, and instead sticks with the C idiom of return values indicating error status. Luckily, Go provides multiple return value support so you can do things like rv, ok = call(), and then check the value of ok for success; however, I really think exception throwing would be useful here, mainly in simplifying boiler-plate code. It's not like you can't implement exceptions with goroutines or something.

Anyway, that's my impression. I really wish Go wasn't so warty, because it seems like it could be real cool. On the other hand, I appreciate how much work it leaves to do in this field :).