# The nil-Channel Trick — Go Concurrency Patterns

Source: https://www.geekswithgeeks.com/en/go-concurrency/gc-nil-select

> Disabling select cases dynamically.

## A nil case never fires

Because operations on a **nil channel block forever**, a select case on a nil channel can never be chosen. You can therefore **switch a case off** by setting the channel variable to nil. Classic use: merging two input channels. When one input is closed (`ok == false`), set it to nil so the select stops spinning on its endless zero values, and exit the loop once both are nil. The same trick enables a send case only when there is something to send: keep the outgoing channel nil while your pending queue is empty.

## Merging two channels until both are closed

Closed inputs are disabled by setting them to nil.

```go
package main

import "fmt"

func merge(a, b <-chan int) <-chan int {
	out := make(chan int)
	go func() {
		defer close(out)
		for a != nil || b != nil {
			select {
			case v, ok := <-a:
				if !ok {
					a = nil // disable this case
					continue
				}
				out <- v
			case v, ok := <-b:
				if !ok {
					b = nil
					continue
				}
				out <- v
			}
		}
	}()
	return out
}

func gen(vals ...int) <-chan int {
	ch := make(chan int)
	go func() {
		defer close(ch)
		for _, v := range vals {
			ch <- v
		}
	}()
	return ch
}

func main() {
	for v := range merge(gen(1, 2), gen(10, 20, 30)) {
		fmt.Println(v) // all five values, interleaving not guaranteed
	}
}
```

## Unplugging a phone line

A switchboard operator listens to many lines. When a caller hangs up for good, the operator unplugs that line so its dial tone stops demanding attention; the other lines keep working.

**Quiz:** Why set a closed input channel variable to nil inside a merge loop?

- [ ] It frees the channel memory immediately
- [ ] Setting it to nil reopens the channel
- [x] A closed channel is always ready and returns zero values, while a nil channel case is never selected
- [ ] select panics on closed channels

*Answer:* A closed channel is always ready and returns zero values, while a nil channel case is never selected. Without the nil assignment the loop would spin on zero values from the closed channel.
