Skip to content

Drop string-content truthiness; &&/|| return operands#16

Merged
myzie merged 1 commit into
mainfrom
truthiness-and-operand-logical
May 8, 2026
Merged

Drop string-content truthiness; &&/|| return operands#16
myzie merged 1 commit into
mainfrom
truthiness-and-operand-logical

Conversation

@myzie
Copy link
Copy Markdown
Contributor

@myzie myzie commented May 8, 2026

Summary

  • Truthiness (truthy.go): IsTruthy no longer special-cases the string "false". A non-empty string is truthy regardless of content; empty strings stay falsey. bool("false") is now true.
  • Logical operators (program.go): && and || return the deciding operand (Python and/or semantics) instead of a coerced bool. Short-circuit behavior is unchanged.

Why

The "false"-string carve-out was a footgun in JSON-heavy contexts and becomes actively harmful once &&/|| return operands (a bare identifier carrying the string "false" would falsey-fall-through unexpectedly).

Operand-returning logical ops compose cleanly with the new truthiness rules:

name || "(none)"       // string fallback
xs   || []             // empty-list default
count || 0             // numeric default

This subsumes a default(x, y) builtin, so per the design doc we are not adding one. Hard bool casts remain available via bool(v).

Docs and tests

  • docs/reference/spec.md: Logical and Truthiness sections rewritten.
  • llms.txt: bullets updated.
  • engine_test.go: added TestEval_LogicalReturnsOperand pinning the new operand-returning behavior.
  • script_test.go, boundaries1_test.go, boundaries2_test.go: updated three existing assertions that depended on the dropped string-content rule.
  • The templates and higher-order-patterns guides intentionally stay as-is. They will be revisited when the if builtin lands (a later step in the design doc).

Test plan

  • go test ./...
  • go test -race ./...
  • FuzzCompile 20s
  • FuzzEval 20s
  • FuzzTemplateEval 15s

What:
- IsTruthy no longer treats "false" (case-insensitive) as falsey. A
  non-empty string is truthy regardless of content; empty strings stay
  falsey. bool("false") is now true.
- && and || return the deciding operand (Python and/or semantics)
  instead of a coerced bool. Short-circuit behavior is unchanged.
- Spec, llms.txt, and tests updated. Templates and higher-order-patterns
  guides left alone; they tie into the upcoming `if` builtin step.

Why:
- The "false" string special-case was a footgun in JSON-heavy contexts
  and would have been actively harmful once && and || started returning
  operands (a bare `name` of "false" would falsey-fall-through).
- Operand-returning logical ops compose cleanly with truthiness for
  idioms like `name || "(none)"`, `xs || []`, and `count || 0`. This
  also subsumes a `default(x, y)` builtin, so we will not add one.

Together these are step 1 of docs/design/language-evolution.md.
@myzie myzie merged commit 44c7301 into main May 8, 2026
1 check passed
@myzie myzie deleted the truthiness-and-operand-logical branch May 8, 2026 14:14
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.

1 participant