What does Go's cmp.Or return, and does it stop evaluating arguments at the first non-zero one?
answer
- first one that is not the zero value
- all zero means you get zero back
- it only needs equality, not ordering
- it is a plain function call
- arguments are all evaluated up front
basics
~10 scmp.Or returns the first argument that is not the zero value of its type, or the zero value if none is. It is an ordinary call, so every argument is evaluated first: no short-circuiting.
solid answer
~40 sThe signature is `func Or[T comparable](vals ...T) T`. It walks its arguments left to right and returns the first one that is not equal to `T`'s zero value; if they are all zero it returns the zero value. Note the constraint is `comparable`, not `cmp.Ordered` — it compares with `==`, so any comparable type works, including structs of comparable fields, while slices, maps and functions do not compile. The trap is evaluation: it is a normal function call, so **all** arguments are evaluated before the call begins. `cmp.Or(flag, os.Getenv("REGION"), "us-east-1")` is fine, but `cmp.Or(cached, expensiveLookup())` always pays for the lookup even when `cached` is set. For that you still need an `if`. Its other common use is folding several comparison results into one decision, since a `0` means "tied, try the next key".
code
go · 6 linesfunc resolveRegion(flag, env, fromFile string) string {
return cmp.Or(flag, env, fromFile, "us-east-1")
}
// resolveRegion("", "eu-west-1", "") returns "eu-west-1"
// resolveRegion("", "", "") returns "us-east-1"go deeper
Know the one-line rule: it hands back the first argument that is not the zero value, and the zero value if there is no such argument. Recognise the configuration-precedence shape when you see it.
Explain why the constraint is comparable rather than an ordering constraint, and be ready for the evaluation question — it is a plain call, so every argument is produced before it runs.
Show judgment about when not to use it: expensive or fallible candidates belong in an if, and a configuration whose valid values include zero cannot use the zero value as its absent marker at all.
Treat the zero-value-means-absent convention as a design decision for the whole configuration surface, because once callers depend on it, adding a setting whose valid value is zero becomes a breaking change.
## The function ```go func Or[T comparable](vals ...T) T ``` `cmp.Or` returns the first argument that is not equal to `T`'s zero value. If every argument is zero — or if there are no arguments at all — it returns the zero value. That is the entire specification. "Zero value" means the type's own zero: `0` for numeric types, `""` for strings, `false` for `bool`, `nil` for pointers and interfaces, and the all-fields-zero value for a struct. ## The constraint is comparable, not Ordered Despite living in the `cmp` package next to the ordering helpers, `cmp.Or` has nothing to do with ordering. It needs only to ask "is this the zero value?", which is an `==` test, so its constraint is the built-in `comparable`. That is a wider set than `cmp.Ordered`: booleans, pointers, channels, interfaces, arrays of comparable elements and structs whose fields are all comparable are all allowed. What is excluded is what `==` cannot handle — slices, maps and function values — and those produce a compile error, not a run-time failure. A subtle consequence: for a struct type, "non-zero" means *any* field differs from its zero value, which may not be the emptiness test you had in mind. ## The evaluation trap This is the point interviewers actually probe. `cmp.Or` looks like the `||` operator or a null-coalescing operator from another language, and those short-circuit. `cmp.Or` does not, because Go evaluates every argument of a function call before the call runs. There is no lazy-argument mechanism in the language for an ordinary function. ```go region := cmp.Or(flagRegion, os.Getenv("REGION"), "us-east-1") // fine: reading an env var is cheap value := cmp.Or(cached, loadFromDatabase()) // loadFromDatabase() runs even when cached is set ``` So the rule is: use `cmp.Or` for values you already have, or whose production is cheap and side-effect free. The moment a candidate is expensive, may fail, or has a side effect, go back to an `if` — or pass functions and call them yourself, since `cmp.Or` over function values would not compile anyway (functions are not comparable). ## Where it earns its place **Configuration precedence.** The classic use is collapsing a chain of fallbacks into one expression, replacing four `if s == ""` blocks: ```go func resolveRegion(flag, env, fileValue string) string { return cmp.Or(flag, env, fileValue, "us-east-1") } ``` The precedence is now readable in a single line, and adding a source means adding an argument. **Folding comparison results.** Because a three-way comparison returns `0` for "tied", and `0` is `int`'s zero value, `cmp.Or` composes comparisons naturally: `cmp.Or(cmp.Compare(a.Score, b.Score), cmp.Compare(a.Name, b.Name))` yields the score comparison unless it is a tie, in which case the name decides. That reads better than nested `if`s, and again both comparisons are evaluated — harmless here, since they are cheap and pure, which is exactly the condition the function is comfortable in. ## What it is not - It is **not** a null-coalescing operator: it distinguishes only zero from non-zero, so a legitimately zero value (an intentional `0` port, an explicit empty string) is indistinguishable from "unset". When that distinction matters, use a pointer or an `ok` flag instead, and do not model the absent case as the zero value. - It is **not** short-circuiting, as above. - It does **not** validate: it will happily return a non-zero but wrong value, since it only ever asks whether the value equals the zero value. ## Choosing between cmp.Or and an if chain Use `cmp.Or` when the candidates are values in hand, the zero value genuinely means "not provided", and the list is a precedence order a reader should be able to see at a glance. Use explicit `if`s when a candidate is expensive to produce, when producing it can fail and you need the error, or when "provided but zero" is a state your configuration must be able to express.
- Why is cmp.Or constrained by comparable rather than cmp.Ordered?It never orders anything — it only asks whether each argument equals `T`'s zero value, which is an `==` test. `comparable` is the wider set, so structs of comparable fields, pointers and booleans all work. Slices, maps and functions are excluded because `==` is not defined for them, and that is a compile error.
- How would you express a fallback where the second candidate is expensive to compute?Keep the `if`. Assign the cheap candidate, test it against the zero value, and only then compute the expensive one. `cmp.Or` evaluates every argument before it runs, so wrapping the expensive call in it buys readability at the price of always doing the work.
- What breaks if a legitimate configured value happens to be the zero value?`cmp.Or` skips it, because it cannot distinguish "explicitly set to zero" from "unset". A configured port of 0 or an intentionally empty prefix silently falls through to the next source. When that distinction matters, model absence with a pointer or a separate ok flag rather than with the zero value.
saying these in an interview costs you the question
- Says cmp.Or short-circuits like the || operator
- Thinks cmp.Or requires cmp.Ordered
- Claims it returns the last argument when all are zero
- Believes it can distinguish unset from an explicit zero
- Expects it to work on a slice or map argument