We need to talk about parentheses (2020)

Arguments over how heavily programming languages should rely on parentheses and operator precedence reveal deep trade-offs between readability, familiarity, and metaprogramming power. Some contributors advocate minimal precedence and more explicit grouping (or even RPN-style syntax), while others defend conventional math-like rules and Lisp’s fully parenthesized S‑expressions, especially when paired with good indentation and editor support. The exchange also touches on how syntax shapes tooling, scoping, and the ease of code transformation, and why—despite Lisp’s macro and “code as data” advantages—most mainstream languages continue to favor more varied, less uniform syntactic forms.

Operator precedence vs. mandatory parentheses

  • One camp argues operator precedence is a design mistake; mixed-operator expressions like 1 + 1 * 2 or a | b || c >> d & e * f should be syntax errors unless explicitly parenthesized.
  • Others strongly disagree, citing notational simplicity, parallels to algebra, and the burden of over-parenthesized code.
  • Proposed compromise: a partial precedence order. Common combinations (e.g., * over +) are allowed; uncommon mixes (e.g., * with &) are rejected as “ambiguous precedence.”
  • Debate extends into math: some say precedence is inherent (“order of operations”); others insist it’s purely a property of notation, often expressed visually via fractions, superscripts, radicals, etc.

Lisp parentheses, readability, and tooling

  • Many note that in Lisp, automatic indentation, structural editing, and paren-highlighting are considered essential; these quickly reveal missing or misplaced parentheses.
  • Some argue Lisp’s single kind of parenthesis hurts readability and suggest multiple bracket types for different syntactic roles, or even interchangeable brackets purely for visual grouping.
  • Counterpoint: experienced Lisp users mostly “see forms,” not parentheses, and rely on patterns starting with symbols rather than counting brackets.
  • Structural editing is praised: explicit delimiters plus auto-formatting act like “double-entry bookkeeping” for code structure.

Syntax style, whitespace, and scoping

  • Some celebrate languages that drop unnecessary parentheses in constructs like if conditions (Go, Scala 3).
  • There is disagreement over significant whitespace: some prefer explicit delimiters; others find indentation-centric syntax more readable.
  • Discussion on scoping: tight lexical blocks ({} or let forms) can reduce live variables, but not all lifetimes can be minimized; examples in C, Rust (non-lexical lifetimes), and FP/monadic code illustrate tradeoffs.

Lisp’s code-as-data and metaprogramming

  • Several comments emphasize that Lisp’s parentheses represent lists; programs are lists, and quoting turns code into data.
  • Simple list operations can transform code (e.g., replace all * with + then eval), underpinning powerful macros and domain-specific syntaxes.
  • Enthusiasts see this as Lisp’s main strength; skeptics reply that other languages now offer strong metaprogramming with less visually repetitive syntax, and question whether parentheses are a good ergonomic tradeoff.