Contexts in Go are generally used for convenience in request cancellation, but they're not <i>required</i>, and they're not the only way to do it. Under the hood, a context is just a channel that's closed on cancellation. The way it was done before contexts was pretty much the same:<p><pre><code> func CancellableOp(done chan error /* , args... */) {
for {
// ...
// cancellable code:
select {
case <-something:
// ...
case err := <-done:
// log error or whatever
}
}
}
</code></pre>
Some compare context "virus" to async virus in languages that bolt-on async runtime on top of sync syntax - but the main difference is you can compose context-aware code with context-oblivious code (by passing context.Background()), and vice versa with no problems. E.g. here's a context-aware wrapper for the standard `io.Reader` that is completely compatible with `io.Reader`:<p><pre><code> type ioContextReader struct {
io.Reader
ctx context.Context
}
func (rc ioContextReader) Read(p []byte) (n int, err error) {
done := make(chan struct{})
go func() {
n, err = rc.Reader.Read(p)
close(done)
}()
select {
case <-rc.ctx.Done():
return 0, rc.ctx.Err()
case <-done:
return n, err
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
rc := ioContextReader{Reader: os.Stdin, ctx: ctx}
// we can use rc in io.Copy as it is an io.Reader
_, err := io.Copy(os.Stdout, rc)
if err != nil {
log.Println(err)
}
}
</code></pre>
For io.ReadCloser, we could call `Close()` method when context exits, or even better, with `context.AfterFunc(ctx, rc.Close)`.<p>Contexts definitely have flaws - verbosity being the one I hate the most - but having them behave as ordinary values, just like errors, makes context-aware code more understandable and flexible.<p>And just like errors, having cancellation done automatically makes code more prone to errors. When you don't put "on-cancel" code, your code gets cancelled but doesn't clean up after itself. When you don't select on `ctx.Done()` your code doesn't get cancelled at all, making the bug more obvious.