# Directional Channel Types in APIs — Go Concurrency Patterns

Source: https://www.skillbyai.com/en/go-concurrency/gc-direction

> Let the compiler enforce who sends and who receives.

## chan<- and <-chan

A channel type can be restricted: `chan<- T` is **send-only** and `<-chan T` is **receive-only**. A bidirectional `chan T` converts implicitly to either, but not back. Use them in function signatures to document and enforce roles: a producer takes `chan<- T` or returns `<-chan T`, a consumer takes `<-chan T`. The compiler then rejects a consumer that tries to send or to close (closing a receive-only channel is a compile error), which encodes the "only the sender closes" rule in the type system. A common idiom is a generator that creates the channel, starts a goroutine to fill and close it, and returns it as `<-chan T`.

## A generator returning a receive-only channel

The function owns the channel; callers can only receive.

```go
package main

import "fmt"

// count owns out: it creates it, sends on it and closes it.
func count(n int) <-chan int {
	out := make(chan int)
	go func() {
		defer close(out)
		for i := range n { // Go 1.22+: range over an int
			out <- i
		}
	}()
	return out
}

func printAll(in <-chan int) {
	for v := range in {
		fmt.Println(v)
	}
	// in <- 1   // compile error: send to receive-only channel
	// close(in) // compile error: cannot close receive-only channel
}

func main() {
	printAll(count(3))
}
```

## Return <-chan, accept the narrowest type

Exported functions should rarely accept or return a plain `chan T`. Narrow types make ownership obvious in code review and prevent accidental double closes.

**Quiz:** What happens if code calls close on a value of type <-chan int?

- [ ] It is silently ignored
- [ ] It panics at run time
- [ ] It closes the channel normally
- [x] The program fails to compile

*Answer:* The program fails to compile. Closing a receive-only channel is rejected by the compiler.
