Rust's Ugly Syntax (2023)

Overall reaction to the article

  • Several commenters feel the chosen example is not Rust’s “worst”; real pain appears when generics, lifetimes, and async are combined.
  • Some are unsure whether the article is tongue‑in‑cheek; others see it as arguing that complaints about syntax are actually about semantics needed for performance and safety.

Rust’s complexity: semantics vs syntax

  • One view: people want C/C++‑level speed but then dislike the semantics (ownership, lifetimes) that provide it.
  • Others argue most Rust use isn’t about raw speed but about safe, non‑GC systems programming; problems arise when Rust is used “for everything.”
  • There’s disagreement on whether Rust is “too complicated,” “as complicated as it needs to be,” or even “not complicated enough.”

Lifetimes and lifetime syntax

  • Multiple people struggle with 'a: 'b and lifetime subtyping; several mnemonic explanations are proposed, but they’re seen as unintuitive.
  • Debate over the ' sigil: some find it ugly/confusing and advocate a lifetime keyword; others argue brevity matters and note precedents in other languages.
  • Many mention that explicit lifetimes are rarely needed in everyday Rust, especially if you lean on heap‑allocating types (Box, Rc, Arc).

Generics, traits, and async “alphabet soup”

  • Complex signatures combining generics, lifetimes, async futures, and trait objects are cited as truly unreadable.
  • An example of an async trait method expanded by a macro is widely acknowledged as horrendous, though noted as codegen rather than hand‑written idiom.
  • Some suggest that needing such signatures is a sign of over‑engineering or extreme allocation avoidance.

Ergonomics, visibility, and type annotation style

  • Discussion around pub fn and non‑public-by-default: many like the conservative default and parallels with mut usage.
  • Type‑after‑name (x: T, fn foo(...) -> T) is defended as easier to parse and more consistent than C‑style declarations.
  • The :: vs . distinction (namespaces vs fields) is debated; some see it as unnecessary, others say it avoids ambiguity.
  • Semicolon‑free final expressions as implicit returns are confusing to some but defended as a useful expression‑oriented feature.

Error handling and Result

  • The article’s simplification of error types raises concern about losing information; others point out standard type aliases like io::Result<T> = Result<T, io::Error> preserve it.
  • The ? operator is described as “unwrap on success, early return on error,” enabling concise chaining.

Comparisons and alternative syntaxes

  • Many compare the example to equivalent code in Python, Go, Swift, C#, OCaml/CrabML, Raku, Ada, etc., showing those can be shorter or “prettier.”
  • Some argue standard library APIs are inherently more complex due to generality and performance constraints; typical user code often looks closer to the simpler “Rattlesnake/CrabML‑style” versions.
  • There is recurring interest in a Rust‑like language with GC or refcounting and a simpler surface syntax.

Async Rust

  • Opinions on async Rust are polarized: called both an “abomination” and “marvelous” depending on perspective.
  • Recent and upcoming features (async closures, async trait fns, impl Trait improvements) are seen as making async code substantially nicer, though ecosystem fragmentation (different async traits in different crates) remains a pain point.