I have a struct that holds a channel that is not initialized.
When I write into it, the routine is blocking as expected but the reader is never notified that something is in the pipe.
I am surprised that there is no error and I am wondering what is doing Go.
In the example bellow, neither the message pushed
nor got it
are printed. (Uncomment the intialization and it will work like a charm)
type MyStruct struct {
over chan bool
}
func main() {
nonInitialized := &MyStruct{}
// nonInitialized.over = make(chan bool)
go func() {
for i := 0; i < 10; i++ {
select {
case <-nonInitialized.over:
fmt.Println("got it")
default:
// proceed
}
fmt.Println("do some stuff")
time.Sleep(10 * time.Millisecond)
}
panic("took too long")
}()
// push on the non initialized channel
fmt.Println("pushing")
nonInitialized.over <- true
fmt.Println("pushed")
}
Here is the playground https://play.golang.org/p/76zrCuoeoh
(I know I should initialize the channel, this is not the purpose of the question, I want to know what is happening in Go with non initialized channels.)
An "uninitialized" field or variable of channel type will have the zero value of all channel types which is nil
. So let's examine how a nil
channel or operations on it behave.
It is worth collecting the channel axioms in one post:
nil
channel blocks forever (Spec: Send statements)nil
channel blocks forever (Spec: Receive operator)Reasoning for blocking in case of nil
channels: if a channel value is nil
, no one has a reference to it, so no one will ever be ready to receive from it (what we want to send); or send anything on it (what we would receive from it).
You can read further reasoning and more details about this in Dave Cheney: Channel Axioms.
For completeness:
nil
channel causes a run-time panic (just like closing an already closed channel).nil
channel is 0
; in accordance with nil
slices and maps having 0
length and capacity.Reasoning: "closed" is a state, but a nil
channel cannot have a state (there is only one nil
channel, and not one for "closed" and one for "not closed" channel). And there are no elements queued in a nil
channel (so len = 0), and it does not have a buffer capacity (so cap = 0).
This is expected behavior. A send to a nil
channel blocks forever. You can read about it in the specs here: https://golang.org/ref/spec#Send_statements
The same is also applicable for a recieve on a nil
channel. (https://golang.org/ref/spec#Receive_operator)
You can also keep this link handy for reference: http://dave.cheney.net/2014/03/19/channel-axioms
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With