proposal: spec: panic on send/receive on nil channel (original) (raw)

In Go 1 a send or receive operation on a nil channel blocks forever. This is by analogy with the select statement, in which a case with a nil channel is ignored. In particular, these four code snippets all block forever:

var c1 chan int
<-c1

var c2 chan int
select {
case <-c2:
}

var c3 chan int
c3 <- 1

var c4 chan int
select {
case c4 <- 1:
}

However, the fact is that send statements and receive expressions are not the same as select cases. They look different in the program and they are implemented differently. While it is nice to have a send or receive operation behave identically to a select statement with a single case that corresponds to that operation, it is not necessary, and I claim that changing that correspondence will not cause confusion.

I claim further that the fact that nil channels block forever is a point of confusion for new Go programmers. They must learn to call make to create a channel. When learning Go, it is easy to forget that. This then leads to confusion when programs simply block rather than reporting an error. Sample comments:

https://groups.google.com/d/msg/golang-nuts/QltQ0nd9HvE/mAb2K4UHWxUJ
https://groups.google.com/d/msg/golang-nuts/JFTymqVDBcs/E8GDJiQFBQAJ
http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#using_nil_ch

My final claim is that essentially no real programs rely on the current behavior for nil channels. I have no way to prove this claim, but in general blocking forever is a goroutine leak, and when people do want to block forever anyhow they use select {}.

Give the above, I recommend that for Go 2 we change this corner case and make send or receive operations on nil channels panic. To be clear I am not proposing that we change the behavior of select statements with nil channels, and I am not proposing that we change any aspect of the behavior for closed channels. In the above four code snippets, the first and third will panic, while the second and fourth will continue to behave as in Go 1.