In Go, how must a caller handle both results of a function returning `(int, bool)`?
answer
- one target per result
- there is no tuple to hold them
- the compiler counts your variables
- a name you cannot read back
- unused locals are an error, so _ exists
basics
~10 sA Go call returning two values needs two targets: port, ok := parsePort(s). Write the blank identifier _ for any result you do not want. Binding one variable to it is a compile error.
solid answer
~50 sGo returns multiple values natively, and there is no tuple type to hold them: a call like `parsePort(s)` that is declared `(int, bool)` yields exactly two values, so the caller writes `port, ok := parsePort(s)`. Writing `port := parsePort(s)` fails to compile with an assignment-mismatch error, because one variable cannot hold two results. When you only care about one of them, put the blank identifier `_` in the other slot — `port, _ := parsePort(s)` or `_, ok := parsePort(s)`. `_` is not a variable: nothing is stored, it can appear as often as you like, and it is the standard way around Go's rule that a declared local must be used. A multi-valued call can also be forwarded whole — `return parsePort(s)` from a function with the same result types, or `fmt.Println(parsePort(s))` — but only as the entire argument list, never mixed with other arguments.
code
go · 7 lines// parsePort returns the port number and whether s was a valid port.
port, ok := parsePort(raw) // both results
port2, _ := parsePort(raw) // keep the number, drop the flag
_, valid := parsePort(raw) // keep the flag, drop the number
// bad := parsePort(raw) // does not compile: assignment mismatchgo deeper
Be ready to write the call: two names separated by a comma, or _ where you do not want a value. Know that binding one variable to a two-result call is a compile error, not a silent truncation.
Explain that Go has no tuple type, that the results are separate values checked by the compiler, and that _ is not a variable. Mention the one rule for forwarding: a multi-valued call may be the whole argument list, never part of one.
Show that you treat each _ as a decision. Point at the cases where discarding the second result turns a detected failure into a zero value that flows onward, and say what you look for when reviewing one.
Frame it as a signature question: how many results a function should hand back before the pair should become a named struct, and what a team convention on discarding results buys you in review time.
## Multiple results are a language feature, not a trick Most languages let a function hand back exactly one thing, so returning two forces you into an out-parameter, a wrapper struct, or a tuple type. Go declares extra results directly in the signature: ```go func parsePort(s string) (int, bool) func Atoi(s string) (int, error) // strconv func LookupEnv(key string) (string, bool) // os ``` The result list is parenthesised whenever there is more than one result. Crucially, those two values are **not** bundled into a single object. Go has no tuple type, so there is nothing you can store the pair in, no `.0` and `.1`, and no way to pass "the results" around as one value. They exist only in the moment of the call. ## The caller must account for every result Because the values are separate, the assignment must have one target per result: ```go port, ok := parsePort(raw) ``` If you supply the wrong number of targets, the program does not compile. `port := parsePort(raw)` produces an assignment-mismatch error (one variable, two values), and so does `a, b, c := parsePort(raw)`. This is deliberate: the compiler will not let you quietly forget that the function told you something else as well. The same rule applies to `=` on existing variables. With `:=`, at least one of the names on the left must be new; if both `port` and `ok` already exist, use `=`. ## The blank identifier discards a result When a result genuinely does not matter, name it `_`: ```go port, _ := parsePort(raw) // keep the number, drop the flag _, ok := parsePort(raw) // keep the flag, drop the number ``` `_` is the blank identifier. It is not a variable: no storage is allocated, you cannot read it back, and it may appear many times in the same statement or function. It matters in Go specifically because an ordinary declared local that is never used is a **compile error** — so `_` is how you say "I know there is a value here and I am deliberately dropping it". That deliberateness is the point of review scrutiny. Discarding a `bool` that means "this value is real" or an `error` that means "this failed" turns a reported failure into a silent one, and the zero value you keep looks like a legitimate answer. In a config validator that runs as a CI step, `port, _ := parsePort(raw)` yields `0` for garbage input and the step passes; the same call written `port, ok := parsePort(raw)` forces the next line to decide what to do. If you write `_`, you should be able to say out loud why the dropped value carries no information you need. ## Forwarding a multi-valued call A call with several results can be used in two other places, both of which consume all of the values at once: ```go func port(raw string) (int, bool) { return parsePort(raw) // result types line up exactly } fmt.Println(parsePort(raw)) // both values become the arguments ``` What you cannot do is mix a multi-valued call with anything else. `fmt.Println("port:", parsePort(raw))` is rejected — a multi-valued call in a single-value context. The workaround is always the same: assign the results to variables first, then use them individually. ## Where you meet this every day The two-result shape shows up in three familiar guises. `(T, error)` is the failure convention: a value plus a reason it might be missing. `(T, bool)` is the comma-ok convention: a value plus whether it exists at all, as in `os.LookupEnv`, which distinguishes an unset environment variable from one set to the empty string. And several standard-library functions simply return two useful things — `context.WithTimeout` hands back a derived context and the cancel function you must call. In all three cases the mechanics are identical: two targets, or one target and a `_`, and never a single variable. ## What interviewers listen for They want to hear that the count is checked by the compiler, that `_` is the escape hatch rather than a variable, and that discarding a result is a decision with consequences rather than syntax noise. Saying "Go returns a tuple" is the common slip; it is close enough to be useful shorthand and wrong enough to mislead you the moment you try to store one.
- Why does Go make an unused local variable a compile error but allow the blank identifier everywhere?An unused local is almost always a leftover or a bug, so the compiler rejects it. The blank identifier is not a variable at all — nothing is stored and nothing can be read back — so it cannot be a leftover. It exists precisely so you can state, in code, that a value is being dropped on purpose.
- Can you store the pair of values a two-result Go function returns in one variable?No. Go has no tuple type, and the results are not bundled into a value. If you need to carry them together you declare a struct with two fields and return that instead, which changes the signature to a single result. Otherwise the pair exists only for the duration of the assignment.
- What happens if you write `fmt.Println("port:", parsePort(raw))` where parsePort returns two values?It does not compile. A multi-valued call may be the entire argument list of another call, or the whole expression of a matching `return`, but it cannot appear alongside other arguments — that is a single-value context. Assign the results to variables first and pass them individually.
The call hands you two items at once, like a cashier passing back change and a receipt. You need a hand for each; if you only want the change, you still have to say where the receipt goes.
saying these in an interview costs you the question
- Says Go returns a tuple you can store in one variable
- Thinks assigning one variable silently keeps the first result
- Believes _ declares a variable you can read later
- Drops a bool or error with _ and calls it clean code
- Expects fmt.Println("x:", f()) to compile for a two-result f