liveBook · Manning

Nil channel pattern

As explained in Learn Concurrent Programming with Go

A nil channel pattern disables a select case by assigning nil to its channel after that channel closes.

A nil channel disables a select case. After receiving the closed-channel flag, assign nil to that channel variable so selection continues across the remaining open channels. Without this step, a case for a closed channel remains continuously selectable. section 8.1.6

Accounting from sales and expenses

Read sales and expenses through one select loop. Add sales, subtract expenses, and set each channel to nil when it closes. Continue while either channel is non-nil; when both become nil, print the end-of-day balance. section 8.1.6

Listing 8.12 A main() goroutine using the nil select pattern
func main() {
    sales := generateAmounts(50)                #1
    expenses := generateAmounts(40)             #2
    endOfDayAmount := 0
    for sales != nil || expenses != nil {       #3
        select {
        case sale, moreData := <-sales:         #4
            if moreData {
                fmt.Println("Sale of:", sale)
                endOfDayAmount += sale          #5
            } else {
                sales = nil                     #6
            }
        case expense, moreData := <-expenses:   #7
            if moreData {
                fmt.Println("Expense of:", expense)
                endOfDayAmount -= expense       #8
            } else {
                expenses = nil                  #9
            }
        }
    }
    fmt.Println("End of day profit and loss:", endOfDayAmount)
}
#1 Generates 50 amounts on the sales channel
#2 Generates 40 amounts on the expenses channel
#3 Continues to loop while there is a non-nil channel
#4 Consumes the next amount and channel open flag from the sales channel\
#5 Adds the sales amount to the total end-of-day balance
#6 If the channel has been closed, marks the channel as nil, disabling this select case
#7 Consumes the next amount and channel open flag from the expenses channel
#8 Subtracts the expense amount from the total end-of-day balance
#9 If the channel has been closed, marks the channel as nil, disabling this select case

Inspect the complete Go listing for merging two generated amount streams with the nil select pattern. section 8.1.6

How Learn Concurrent Programming with Go covers it

How deep it goes
Explains closure detection, case disabling, loop termination, and the fixed-source limit, while deferring dynamic fan-in.
Examples
Demonstrates interleaved sales and expense amounts producing an end-of-day profit-and-loss balance.
What it assumes
Assumes channel receiving and select syntax, while demonstrating the two-value closure check and nil-channel behavior.
What you can do after
Apply it to drain multiple fixed channel sources without repeatedly selecting a closed channel.
How it connects
Connects channels, select statements, closed channels, and fan-in patterns.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Concurrent Programming with Go. The section links point to the parts of the book it draws on.