What do len(ch) and cap(ch) return for a buffered Go channel?
answer
- one is fixed, the other moves
- what make's second argument becomes
- zero and zero for a rendezvous channel
- true when read, maybe false one line later
basics
~20 sFor a channel, cap returns the capacity passed to make and never changes; len returns how many values are queued in the buffer right now. Both are 0 for an unbuffered channel, whose values are never queued.
solid answer
~40 sThe builtins `len` and `cap` are both defined on channels. `cap(ch)` is the buffer capacity given to `make` — fixed for the channel's life, and 0 for `make(chan T)`. `len(ch)` is the number of values currently sitting in the buffer, so it ranges from 0 to `cap(ch)`. On an unbuffered channel `len` is always 0: a value handed across a rendezvous is never stored, so there is nothing to count even while a sender is parked mid-handoff. The important caveat is that `len(ch)` is a **snapshot**, not a reservation. Between reading it and acting on it, other goroutines can send or receive, so a guard like `if len(ch) < cap(ch) { ch <- v }` is a race: the send can still block because another goroutine took the last free slot in between.
code
go · 12 linesch := make(chan int, 3)
fmt.Println(len(ch), cap(ch)) // prints: 0 3
ch <- 1
ch <- 2
fmt.Println(len(ch), cap(ch)) // prints: 2 3
<-ch
fmt.Println(len(ch), cap(ch)) // prints: 1 3
signal := make(chan struct{})
fmt.Println(len(signal), cap(signal)) // prints: 0 0go deeper
Remember the two definitions: cap is the number you passed to make, len is how many values are waiting in the buffer right now. Both are zero for a channel made with no capacity argument.
Explain why len is always zero on an unbuffered channel, and be able to write out why a length check before a send is a race rather than a guard.
Demonstrate that you never let correctness depend on len: only the channel operation itself is atomic with the channel's state, and a check narrows a window rather than closing it.
Be ready to argue where queue-depth observation belongs at all, and why a number that is stale the instant it is read is acceptable for diagnosis but never for control flow.
## Two builtins, overloaded onto channels Go's `len` and `cap` are builtins that work on several types. On a channel they mean: - **`cap(ch)`** — the buffer capacity, i.e. exactly the second argument you passed to `make`. `make(chan Sample, 64)` gives `cap` 64; `make(chan Sample)` gives `cap` 0. It is constant for the whole life of the channel; there is no operation that changes it. - **`len(ch)`** — how many values are queued in that buffer at this instant. It starts at 0, rises with each send that is not immediately consumed, falls with each receive, and never exceeds `cap(ch)`. So `cap` describes the shape of the channel and `len` describes its momentary contents. Confusing them is a common slip: `len` is not "the size of the channel". ## Unbuffered channels report 0 and 0 On `ch := make(chan string)` both builtins return 0, and `len(ch)` stays 0 forever — including while a sender is blocked in `ch <- v` waiting for a receiver. That is not a rounding decision: an unbuffered channel has no storage. The runtime copies the value straight from the sending goroutine to the receiving one when they meet, so the value is never "in" the channel in a way `len` could count. If your code branches on `len(ch) > 0` to decide whether work is pending, it will conclude "nothing pending" on an unbuffered channel no matter how many senders are queued up behind it. This also gives you a cheap way to ask which kind of channel you were handed: `cap(ch) == 0` means unbuffered. Note that a function signature cannot tell you this — capacity is not part of the channel's type. ## Why len is a snapshot and not a decision input The value `len(ch)` returns was true at the moment the runtime read it. It is not a promise about the next instruction. Any other goroutine may send or receive between your read and your use of the result, so the classic "look before you leap" guard is unsound: ```go if len(ch) < cap(ch) { // there was room a moment ago... ch <- v // ...but another goroutine may have taken it } ``` This is a time-of-check to time-of-use race in the ordinary sense: the check narrows the window in which the send blocks, it does not close it. With a single producer and no other senders it happens to hold, but that is a property of your program's structure, not of `len`, and it breaks the day someone adds a second sender. The same reasoning applies in the other direction: `len(ch) > 0` does not guarantee that a receive will not block, because another receiver can drain the value first. What `len` is genuinely good for is coarse, non-authoritative observation — a debug line, an assertion in a single-goroutine test, a rough sense of whether a queue is empty or brimming. Anything that must be *correct* has to use a channel operation, because only the operation itself is atomic with respect to the channel's state. ## Ordering and copies Two related facts often come up alongside `len`: - Values leave a buffered channel in the order they entered it. `len` counts a FIFO queue, not a bag. - Sends copy the value into the buffer. `len(ch)` of 5 means five copies are held by the channel, and if the element type contains pointers, those five copies keep whatever they point at reachable until they are received. ## What to say in an interview Give the two definitions crisply, add that both are 0 for an unbuffered channel and that `cap` never changes, then volunteer the race caveat about `len`. Volunteering the caveat is what separates a memorised answer from an understood one — many candidates can define the builtins and then immediately write the unsound guard.
- What do len and cap return for a channel created with make(chan int)?Both return 0, always. Capacity is 0 because no buffer was requested, and length stays 0 because an unbuffered channel never stores anything — the value is copied straight from sender to receiver at the rendezvous. So `len` gives you no signal at all about how many senders are waiting.
- Why is `if len(ch) < cap(ch) { ch <- v }` unsafe with several senders?It is a time-of-check to time-of-use race. Another goroutine can occupy the last free slot between the comparison and the send, so the send blocks anyway. The check only shrinks the window. Nothing outside a channel operation itself is atomic with respect to the channel's state.
- Can cap(ch) ever return a different number over a channel's life?No. The capacity is set once by `make` and there is no API to change it — no resize, no grow-on-demand. Any code that wants a different capacity has to create a new channel and arrange for producers and consumers to switch to it.
saying these in an interview costs you the question
- Says len(ch) returns the channel's capacity
- Uses len(ch) to decide whether a send will block
- Thinks cap grows as more values are sent
- Expects len of an unbuffered channel to be 1 mid-handoff
- Believes len and cap are undefined for channels