Closed channels in select statements

2,557 views
Skip to first unread message

Tommi Virtanen

unread,
Nov 25, 2010, 6:50:59 PM11/25/10
to golang-nuts
Hi. I'm writing to suggest an improvement on the select statement,
related to how it deals with channels that are already closed. I find
the "if closed(ch)" idiom very tedious and repetitive, and was
wondering what you guys think could be done to make channels integrate
even better into the language.

Right now, to handle multiple channels until they close, you need to
write something like this:

package main

import "fmt"

func main() {
one := make(chan int, 1)
one <- 1
close(one)
two := make(chan int, 1)
two <- 2
close(two)
TOP:
for {
select {
case n := <-one:
if closed(one) {
fmt.Println("seeing closed on one")
one = nil
continue
}
fmt.Println("one", n)

case n := <-two:
if closed(two) {
fmt.Println("seeing closed on two")
two = nil
continue
}
fmt.Println("two", n)

default:
fmt.Println("all closed")
break TOP
}
}
}


Now, imagine support for detecting closed channels was added to select
itself. You would be able to write something like this:

case n := <-one:
fmt.Println("one", n)
case closed(one):
fmt.Println("seeing closed on one")
one = nil

The presence of "case closed(one)" would mean that the other receive
would not trigger after the channel is closed. An extra improvement on
this would be to make select itself know that the channel has been
closed, and it's "case closed" handler has been called, and ignore
that channel in further loops; that would make even the "one = nil"
unnecessary.

What do you think?

Jessta

unread,
Nov 25, 2010, 6:58:29 PM11/25/10
to Tommi Virtanen, golang-nuts
On Fri, Nov 26, 2010 at 10:50 AM, Tommi Virtanen
<tommi.v...@gmail.com> wrote:
> Now, imagine support for detecting closed channels was added to select
> itself. You would be able to write something like this:
>
>                case n := <-one:
>                        fmt.Println("one", n)
>                case closed(one):
>                        fmt.Println("seeing closed on one")
>                        one = nil
>
> The presence of "case closed(one)" would mean that the other receive
> would not trigger after the channel is closed. An extra improvement on
> this would be to make select itself know that the channel has been
> closed, and it's "case closed" handler has been called, and ignore
> that channel in further loops; that would make even the "one = nil"
> unnecessary.
>
> What do you think?
>

The last read from a channel that has been closed will return a nil.
The only way to know that this nil is because the channel is closed or
not is to check for closed() after the read.
closed() won't be true until this value is read.

In your case you have no way for case n := <-one: to know if the n
value is valid or not.
So you have to check it anyway.

For this to work you'd have to change the way channels work or make a
special case just for the select.

- jessta
--
=====================
http://jessta.id.au

Tommi Virtanen

unread,
Nov 25, 2010, 7:00:42 PM11/25/10
to golang-nuts
On Nov 25, 3:58 pm, Jessta <jes...@jessta.id.au> wrote:
> The last read from a channel that has been closed will return a nil.
> The only way to know that this nil is because the channel is closed or
> not is to check for closed() after the read.
> closed() won't be true until this value is read.
>
> In your case you have no way for case n := <-one: to know if the n
> value is valid or not.
> So you have to check it anyway.
>
> For this to work you'd have to change the way channels work or make a
> special case just for the select.

You mean zero value instead of nil, but yes.

In this case, the select is effectively doing the read on my behalf --
surely it can do the if closed() on my behalf, too?
Reply all
Reply to author
Forward
0 new messages