Appendix F. Self-referential options

 

This appendix presents an alternative options API for the HIT client in Chapter 6. We'll start with our current approach and then move on to the self-referential options pattern.

F.1 Struct options

Passing an Options struct directly to SendN has advantages:

  • Simple: Passing an Options value to SendN is straightforward and easy to grasp.
  • Explicit: All options are under a single Options type. Easy to read and maintain.
  • Concise: We only declare an Options struct and some helper functions.

However, this approach has downsides as well:

  • Defaults: We must pass an empty Options if we want the defaults.
  • Zero-value ambiguity: Unset Options fields do not always mean using the default value. For instance, we cannot differentiate between 0 and unset integer fields.

We'll first focus on the downsides of our current approach, then we'll explore an alternative.

F.1.1 Zero value ambiguity

Consider if Options had a MaxRetries option:

type Options struct {
    Concurrency int
    MaxRetries int // Defaults to 5 if zero.
}

The zero value of int, 0, makes it hard to distinguish between users wanting the default and those meaning no retries. Since 0 is ambiguous (could mean an unset field or "no retries"), we might add a boolean field like NoRetries to indicate turning off retries:

type Options struct {
    . . .
    NoRetries bool // NoRetries turns off retries. MaxRetries is ignored.
}

F.1.2 Zero-value options

F.2 Option functions

F.2.1 SendNWith

F.2.2 Options as functions

F.2.3 Applying options

F.2.4 Outro