On 18 March 2014 18:28, Ian Lance Taylor <
ia...@golang.org> wrote:
> On Tue, Mar 18, 2014 at 11:03 AM, Jan Mercl <
0xj...@gmail.com> wrote:
>>
>> Can someone of the Go authors (language designers) provide the
>> motivation for channel closing not being idempotent, please?
>>
>> Elsewhere I have a discussion on this topic and I'm falling miserably
>> to communicate what I think is the reason. Either it's my poor English
>> or I'm just wrong. Especially in the later case I would love to learn
>> the correct answer.
>
> Here is a motivation:
>
> A channel "close" is really just a send of a special value on a
> channel. It is a special value that promises that no more values will
> be sent. Attempting to send a value on a channel after it has been
> closed will panic, since actually sending the value would violate the
> guarantee provided by close. Since a close is just a special kind of
> send, it is also not permitted after the channel has been closed.
In my view, close is different from a channel send because
it does not actually send a value. There is almost no correspondence
between the number of times a channel has been closed
and the number of values received.
> Here is another:
>
> The only use of channel close is to signal to the reader that there
> are no more values to come. That only makes sense when there is a
> single source of values, or when multiple sources coordinate. There
> is no reasonable program in which multiple goroutines close a channel
> without communicating. That would imply that multiple goroutines
> would know that there are no more values to send--how could they
> determine that if they don't communicate?
There is at least one counter-example to this, an idiom that
I've seen used regularly, and that was recently demonstrated in a
post on the Go Programming Language blog (
http://blog.golang.org/pipelines).
That is, it is perfectly reasonable to use a channel that is never used
to send any values at all, and where close is the only action
performed on the channel. In that context, it can often
be useful to be able to close the channel from two contexts.
Perhaps we have a goroutine sitting in a loop that may possibly
terminate with an error, and also some external agent may want to
terminate the loop itself.
It seems reasonable to me that in that situation, either the
external agent *or* the loop itself can close the channel
that indicates "everything should shut down now".
It doesn't much matter where the stimulus for
the shutdown came from, but if the two events happen
in close proximity, we need to be sure we do not panic.
One idiom I've seen for avoiding this is:
mu.Lock()
select {
case <-c:
// The channel is already closed.
default:
close(c)
}
mu.Unlock()
Another is just to recover from the panic.
But really it would be much nicer if we could just
call close.
On 18 March 2014 20:42, Rob Pike <
r...@golang.org> wrote:
> Closing a channel releases it as a resource. It makes no more sense to
> close a channel multiple times than it makes to close a file
> descriptor multiple times, or free a block of allocated memory
> multiple times. Such actions imply the code is broken, which is why
> closing a closed channel triggers a panic.
It actually does make sense to close a file descriptor multiple
times in some circumstances. In Go, the only way to unblock a goroutine blocked
on reading a file descriptor is to close the file descriptor.
But it's quite possible that at the same moment the
we decided to do that, the goroutine completed its action
and went ahead with closing the file descriptor itself.
For this reason, it's useful to make file descriptor closing idempotent.
Such code isn't necessarily broken; neither is code
that closes channels multiple times necessarily broken IMO.