Skip to content

fix: short-circuit && and || - #64

Open
bryan-ferry wants to merge 1 commit into
nyariv:mainfrom
bryan-ferry:fix/short-circuit-logical-operators
Open

bryan-ferry wants to merge 1 commit into
nyariv:mainfrom
bryan-ferry:fix/short-circuit-logical-operators

Conversation

@bryan-ferry

Copy link
Copy Markdown

Problem

a && b and a || b evaluated both operands before applying the op, so obj && obj.prop threw on a null obj and right-hand side effects ran unconditionally. Only ?? was lazy.

Fixes #63.

Fix

Extend the existing ?? short-circuit guard in execSync / execAsync (src/executor/executorUtils.ts) so it also returns a early for && when a is falsy and for || when a is truthy. b is only evaluated when it is needed. The op handlers in src/executor/ops/comparison.ts are unchanged and still produce the result in that case.

Tests

New test/logicalShortCircuit.spec.ts, 12 cases:

  • falsy left operands (null, undefined, 0, "", false, NaN) return the left value and never evaluate the right
  • truthy left operands (1, "x", true, [], {}) for || likewise
  • the obj && obj.prop and !obj || obj.prop guard patterns no longer throw
  • chains stop at the first deciding operand (hit(1) && hit(0) && hit(2) runs two calls)
  • ?? regression: still short-circuits only on null / undefined
  • compileAsync path, including an awaited left operand

9 of the 12 fail on main; all pass with the fix.

Verification

  • npm test: 52 suites / 1923 tests pass (was 51 / 1911)
  • npm run lint: 0 errors, warnings unchanged (pre-existing no-explicit-any)
  • tsc --noEmit and npm run build: clean

Not in this PR

&&=, ||= and ??= evaluate their right-hand side eagerly as well (details in #63). The same guard shape would cover them; this PR is kept to the two operators.

🤖 Generated with Claude Code

`a && b` and `a || b` evaluated both operands before applying the op, so
`obj && obj.prop` threw on a null `obj` and right-hand side effects ran
unconditionally. Only `??` was lazy. Extend the existing `??` guard in
execSync/execAsync to return `a` early when it already decides the
result: `&&` on a falsy `a`, `||` on a truthy `a`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

&& and || always evaluate the right operand (no short-circuit)

1 participant