A ratio test is combined with a guard meant to exclude rows whose denominator is zero, yet those rows still produced warnings. Why?
answer
- no short-circuit over whole columns
- both sides already ran
- the guard selects, it does not protect
- reordering changes nothing
- restrict first, then compute
basics
~20 sBoth conditions are whole columns, computed in full before they meet, so the element-wise combiner evaluates both sides on every row. The guard never prevented anything: the division already ran on exactly the rows it was meant to exclude.
solid answer
~50 sGuarding depends on short-circuiting, and short-circuiting depends on evaluating a predicate per row. Here the ratio test is a full-length column: every division happened before the combiner saw either side, including on the rows where the denominator was zero. The combination then discards those rows, so the surviving row set is usually right — what you lost is the protection. The costs are real: the warnings or unrepresentable values from the excluded rows, the work spent computing them, and on designs where dividing by zero raises rather than warns, an expression that fails outright and produces no result at all. The repair is to change the unit of evaluation, not the order of the conditions: restrict the rows first and compute the ratio on the survivors, or substitute a safe value on the guarded rows before the risky operation runs. Reordering the two conditions changes nothing, because neither one was ever skipped.
code
pseudocode · 12 lines# one expression: both sides are computed for all rows
guard = not_equal(denominator_column, 0)
ratio_test = greater_than(divide(total_column, denominator_column), 1.5)
# ^ the division runs on every row, zero denominators included:
# it warns, or yields an unrepresentable value, or raises
keep = element_wise_and(guard, ratio_test)
result = restrict_rows(table, keep) # the surviving rows are still correct
# two steps: the division never meets a zero denominator
safe = restrict_rows(table, not_equal(denominator_column, 0))
keep2 = greater_than(divide(safe.total, safe.denominator), 1.5)
result2 = restrict_rows(safe, keep2)go deeper
Recall that when two conditions are whole columns, both are computed for every row before they are combined, so a condition placed first does not stop the other from running.
Explain why short-circuiting needs a per-row decision to exist at all, and describe what the guard still does correctly — it selects the surviving rows — against what it never did.
Diagnose it from the symptom: warnings about rows the result does not contain. Then repair it by changing the unit of evaluation, restricting before computing or substituting a safe value, and read the row count back.
Own the rule that an expensive or fallible expression is not written inside a combined condition at all, because a reviewer reading protection into a guard is a recurring and invisible error across a codebase.
## Why there is nothing to short-circuit Short-circuiting is a statement about **evaluation order per decision**: the host looks at the first test, finds it decisive, and never runs the second for that case. It only makes sense when there is a second test still waiting to run. When conditions are whole columns, there is not. By the time the element-wise connective is called, both of its operands are already finished columns: the guard has one outcome for each of the 10,000 rows, and the ratio test has one outcome for each of the 10,000 rows. The divisions that produced the second column all happened, on every row, before the connective existed as a call. The connective's job is to walk two finished columns and produce a third, and a walker cannot un-run work that completed before it started. So the sentence *the second condition only runs where the first one held* is not a slightly optimistic description here. It describes an operation that never took place. ## What the guard did and did not do It is worth being precise about the damage, because overstating it is its own mistake: - **The surviving rows are usually correct.** The combination is false on every zero-denominator row, so those rows are excluded from the result exactly as intended. The selection logic is sound. - **The warnings are real and they are about rows you excluded.** Whatever the division produced on a zero denominator — a warning, an unrepresentable value, a sentinel — it was produced, and it entered the intermediate column. - **The work is wasted.** Every guarded row paid for the expensive side anyway. On a large table with a costly right-hand expression, the guard bought nothing and the cost is the full table's. - **On some designs there is no result at all.** Where the unsafe operation raises rather than warning — an integer division by zero, a conversion that rejects a malformed value, a lookup that refuses a key — the whole expression fails, and the author is left staring at a guard that reads as though it should have prevented exactly that. ## Where short-circuiting is real This is a property of the evaluation model, not of the words you wrote, and two pieces of source can look identical and behave oppositely: | how the predicate is evaluated | is there short-circuiting? | does the guard protect? | |---|---|---| | Two materialised condition columns combined element-wise | no — both sides completed before combining | no | | A per-row expression the host evaluates once per record | yes — the host's own ordering applies | yes | | A recorded plan that fuses the chain into one expression | intermediates may never be materialised, but the guarded expression still applies to every row | no, unless the engine can prove the row is excluded first | So *I wrote a guard* predicts nothing on its own. What predicts the behaviour is whether the conditions are columns or per-row tests. ## Repairs 1. **Restrict first, then compute.** Keep the rows the guard selects, and compute the ratio only on what survives. The division never meets a zero denominator because those rows are no longer present. This changes the shape of the intermediate result, which is the point: you are no longer carrying a full-length column of values you intend to throw away. 2. **Make the risky rows safe before the risky step.** Substitute a harmless value on the guarded rows — a one in the denominator, a default in a conversion — and keep the guard for its selection role. The expression stays full-length and the unsafe case never arises. 3. **Keep the guard, and stop calling it a guard.** In the combined condition it is a *selector*: it decides which rows survive. That is a correctness role and a useful one. It is simply not a protection role, and the two get confused because in per-row code they are the same thing. 4. **Read the row count back.** After any of these, confirm the number of surviving rows matches what the guard alone selects. If the two disagree, the ratio test is excluding rows you did not intend to exclude — typically rows where it produced an undecided outcome rather than a false one. ## What not to try Reordering the two conditions does nothing. Putting the guard first, or last, or nesting the combination differently, changes which finished column is walked first and nothing else. Neither side was ever skipped, so there is no order in which one of them becomes conditional. Suppressing the warning is worse than doing nothing, because the warning is currently the only evidence that the unsafe operation ran at all. Silence the warning and the wasted work, the unrepresentable intermediate and the design that would have raised all become invisible.
- Does the combined condition still select the right rows despite the warnings?Usually yes. The guard is false on those rows, so the combination is false and they are excluded exactly as intended. The exceptions are designs where the unsafe operation raises rather than warning, which kills the whole expression, and cases where the risky side produces an undecided outcome that the combination then propagates.
- Would putting the cheap condition first help?No. Neither side is conditional on the other, so there is no ordering in which one becomes skippable. Both columns are complete before the connective runs. Ordering only matters where the predicate is evaluated per row, which is a different evaluation model and not one you select by rewriting the line.
- When is restricting first the wrong repair?When you need a full-length outcome rather than a shorter table — for example when the result must be written back alongside the original rows, or when several branches are being computed and later recombined. In those cases substitute a safe value before the risky operation instead, and keep the condition full-length.
A guard in per-row code is like a supervisor who stops an inspector at the door: the second inspection never happens for that item. A guard in column-shaped code is two inspectors who each walk the entire line independently and hand in their completed lists at the end; you then compare the lists. The second inspector cannot be told to skip the items the first rejected, because the first one's list does not exist until they have both finished. The distinction holds only where both lists really are made in full — where the tool evaluates one item at a time, the doorway supervisor is back.
saying these in an interview costs you the question
- Believes the safe condition stops the risky one running on excluded rows.
- Says the warning proves the surviving row set is wrong.
- Thinks swapping the order of the two conditions makes the guard take effect.
- Calls it a defect in the tool rather than the evaluation model.
- Assumes no design short-circuits, so a per-row predicate behaves identically.
- Silences the warning and treats the problem as solved.